diff --git a/ANNOUNCE.md b/ANNOUNCE.md
index 5dd0cfc2706e..b5b501cb4c01 100644
--- a/ANNOUNCE.md
+++ b/ANNOUNCE.md
@@ -1,13 +1,12 @@
-The Wine development release 11.11 is now available.
+The Wine development release 11.12 is now available.
 
 What's new in this release:
-  - Bundled SymCrypt library, to replace TomCrypt.
-  - More USER32 window information moved to shared memory.
-  - Layered windows in the Wayland driver.
-  - More VBScript compatibility improvements.
+  - Bundled libswresample and libswscale from FFmpeg.
+  - Mono engine updated to version 11.2.0.
+  - XSLPattern parser reimplemented in MSXML.
   - Various bug fixes.
 
-The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.11.tar.xz>
+The source is available at <https://dl.winehq.org/wine/source/11.x/wine-11.12.tar.xz>
 
 Binary packages for various distributions will be available
 from the respective [download sites][1].
@@ -19,341 +18,330 @@ See the file [AUTHORS][3] for the complete list.
 
 [1]: https://gitlab.winehq.org/wine/wine/-/wikis/Download
 [2]: https://gitlab.winehq.org/wine/wine/-/wikis/Documentation
-[3]: https://gitlab.winehq.org/wine/wine/-/raw/wine-11.11/AUTHORS
+[3]: https://gitlab.winehq.org/wine/wine/-/raw/wine-11.12/AUTHORS
 
 ----------------------------------------------------------------
 
-### Bugs fixed in 11.11 (total 25):
-
- - #27579  The appearance of uTorrent 3.x torrents list is broken
- - #32079  Dotted (.foobar) files are not displayed in file open dialog
- - #37849  Wine causing color temperature setting(redshift) not working for a short time
- - #41134  Foxit Reader 8.x service 'FoxitConnectedPDFService.exe' crashes on startup due to invalid database permissions ('ConvertStringSecurityDescriptorToSecurityDescriptor' SDDL / ACL parser must take whitespace between ACEs into account)
- - #49622  error in installing battle.net launcher
- - #49722  Space Empires V can't load certain images (.bmp) with built-in d3dxof.dll
- - #50583  Foxit PhantomPDF Business v10.0 installer crashes in MSI custom action 'SetStartMenuWindows10T' with WinVer set to 'Windows 10'
- - #50763  Wreckfest has blurry rendering with OpenGL renderer
- - #51433  Battle.Net: Installer terminates with BLZBNTBTS0000005C error screen
- - #51567  Battle.net app takes a long time to start
- - #53293  Total War: Shogun 2 crashes with builtin d3dx9_42
- - #53653  winmine.exe is not scaled properly to match the output DPI
- - #54189  Fail in SetupDiEnumDeviceInfo: err=259: No more data available.
- - #54694  Marvel's Spider-Man Remastered requires Windows 10 version 1909, build 18363 (or newer)
- - #55230  Yesterday Origins shows black screen while playing some videos
- - #56398  Think or Swim running in WINE, loads, then crashes, and need to be shut down.
- - #57806  visual and response lags in Guitar Pro v8.1.3 (build 121)
- - #58297  [Wayland-only mode] Minimize button click makes the app window buttons lock up
- - #59125  Sunlogin crashes on unimplemented function advapi32.dll.WmiCloseBlock
- - #59453  uSimmics crashes on unimplemented function msvcp100.dll._Sinh
- - #59549  MS-Money 2000 - shows errors when loading INV7.OCX
- - #59604  setupapi: CM_Get_Parent stub breaks USB HID device identification
- - #59807  Regression in multithreaded application
- - #59841  Missing audio in Gray Matter due to FAudio 26.06 import
- - #59845  Istaria: game window fails to appear since Wine 11.10
-
-### Changes since 11.10:
+### Bugs fixed in 11.12 (total 27):
+
+ - #3037   LTspice, Progman: broken internal windows resizing
+ - #18010  Slingplayer video tuning wizard fails
+ - #27240  Multiple Corel product installers report msxml:xslpattern_error syntax error / msxml:domselection_create error code 1206 (Corel Paint Shop Photo Pro, CorelDRAW Graphics Suite X3/X4)
+ - #33450  .NET 3.5 Framework installation fails (.NET WorkFlow Service Registration Tool "WFServicesReg.exe" crash with libxml2 < 2.9.0)
+ - #34758  Microsoft Money 97 5.0 crashes with an unhandled divide by zero
+ - #36912  Taskkill does not support /T option
+ - #44232  Menus in Slingplayer 1.5 do not draw until mouseover
+ - #48174  wine-mono creates incorrect strings
+ - #51678  Avogadro crashes when adding atoms
+ - #56100  Greenshot: Error when adding a textbox
+ - #56664  winecfg not exposing an option for 7.1 surround sound audio output (winepulse.drv)
+ - #58632  Against the Storm: Encyclopedia doesn't display animated sequences
+ - #59317  Need for Speed Most Wanted (2005): Up is triggered continuously without pressing a button on gamepad
+ - #59318  Graphic problem
+ - #59406  Super Hexagon: if gamepad is connected, game will ignore every input after selecting anything from title screen
+ - #59590  MS-Money 2000 - cannot process TKIND_UNION when loading INV7.OCX
+ - #59711  unlock_fd: UnlockFile returns ERROR_LOCK_VIOLATION (33) instead of ERROR_NOT_LOCKED (158) when no matching lock is held
+ - #59820  ComicRackCE freezes when attempting to view "info" for a comic file
+ - #59842  Cross builds don't install the "wine" executable anymore
+ - #59855  .configure script fails on system without "ln -s"
+ - #59856  "musl: Use __builtin_rint if available" breaks rounding control in rint function family on x86_64
+ - #59870  VRChat PhotonEncryptorPlugin.dll crash
+ - #59871  Sonic Boom (1995 Klik & Play fangame) fails to create HBITMAP over memory, cannot start
+ - #59880  For games installed under a prefix that has cnc_ddraw installed using Winetricks, error message appears
+ - #59886  Build failed for SymCrypt with clang-msvc on x86/i386 and x86_64
+ - #59894  MS Office 2007 does no longer accept product key from config file
+ - #59910  One case of i386 unwinding broken
+
+### Changes since 11.11:
 ```
-Alexandre Julliard (35):
-      configure: Re-generate with autoconf 2.73.
-      libs: Import upstream code from SymCrypt 103.11.0.
-      rsaenh: Use SymCrypt for hash algorithms.
-      rsaenh: Use SymCrypt for AES, DES and RC2.
-      symcrypt: Add pclmul target for older compilers.
-      ntdll: Use SymCrypt for SHA hashes.
-      ntdll: Get crc32 implementation from zlib instead of tomcrypt.
-      configure: Don't try to link to external zlib.
-      makefiles: Look for dependencies in assembly files.
-      makefiles: Only build asm files in PE builds.
-      makefiles: Use a separate directory for ARM64EC asm files.
-      symcrypt: Import upstream assembly code for x86-64.
-      symcrypt: Import upstream assembly code for ARM64.
-      symcrypt: Import upstream assembly code for ARM.
-      symcrypt: Import upstream assembly code for i386.
-      faudio: Import upstream release 26.06.
-      mpg123: Import upstream release 1.33.5.
-      png: Import upstream release 1.6.58.
-      lcms2: Import upstream release 2.19.1.
-      sqlite3: Import upstream release 3.53.2.
-      sqlite3: Disable debug assertions.
-      rsaenh: Align allocations for SymCrypt.
-      dssenh: Align allocations for SymCrypt.
-      notices: Add a file to collect all third-party copyright notices.
-      makedep: Add a helper function to skip an initial directory.
-      makedep: Also ignore missing headers when included from external lib header.
-      fluidsynth: Remove unused files.
-      gsm: Remove unused files.
-      icucommon: Remove unused files.
-      icui18n: Remove unused files.
-      ldap: Remove unused files.
-      vkd3d: Remove unused files.
-      xml2: Remove unused files.
-      faudio: Don't fixup wma bitrate if it's already valid.
-      ntdll: Support either a Unix call function table or a __wine_unix_lib_init entrypoint.
-
-Alistair Leslie-Hughes (1):
-      include: Add IInkRecognizerContext coclass.
-
-Anton Baskanov (5):
-      dsound: Use DWORD to store freqAdjustNum, freqAdjustDen and freqAccNum.
-      dsound: Move cp_fields_noresample after cp_fields_resample.
-      dsound: Use #define for fir.h constants.
-      dsound: Add an SSE version of upsample.
-      dsound: Add an SSE version of downsample.
-
-Bernhard Kölbl (2):
-      win32u: Add missing internal messages to spy.
-      win32u: Add win32u internal driver messages to spy.
+Alexandre Julliard (20):
+      makefiles: Don't reuse an install command if it has an explicit destination name.
+      makefiles: Always enable the wine tool.
+      makefiles: Also skip C files in arch-specific directories.
+      libs: Import ffmpeg from upstream release 8.1.1.
+      user32: Don't send a message in GetComboBoxInfo().
+      nsiproxy.sys: Link to pthread libs for pthread_once.
+      ffmpeg: Import upstream assembly optimizations for ARM64.
+      ffmpeg: Import upstream assembly optimizations for ARM.
+      makefiles: Add support for nasm.
+      ffmpeg: Import upstream assembly optimizations for x86.
+      symcrypt: Disable asm optimizations globally for non-PE builds.
+      symcrypt: Disable asm optimizations for older clang versions.
+      ffmpeg: Only disable clang warnings when building ffmpeg itself.
+      configure: Use the pkg-config specified libs by default in package checks.
+      configure: Use the pkg-config specified libs also for MinGW checks.
+      configure: Add more pkg-config checks.
+      kernelbase: Implement HasFiberData thread flag.
+      ntdll: Initialize fiber data to 0x1e00.
+      ntdll: Set default NtGlobalFlag for debugged processes.
+      server: Fix returned status for NtUnlockFile on unlocked range.
+
+Alistair Leslie-Hughes (4):
+      tiptsf: Add dll.
+      tiptsf: Add ITextInputPanel interface stub.
+      rtscom: Add stub dll.
+      rtscom: Add RealTimeStylus stubbed interface.
+
+André Zwing (6):
+      comctl32/tests: Fix typo for ARM64EC.
+      kernel32/tests: Fix typo for ARM64EC.
+      oleaut32/tests: Fix typo for ARM64EC.
+      user32/tests: Fix typo for ARM64EC.
+      uxtheme/tests: Fix typo for ARM64EC.
+      vcomp/tests: Fix typo for ARM64EC.
+
+Anna (navi) Figueiredo Gomes (4):
+      win32u: Stub NtUserGetPointerType.
+      win32u: Stub NtUserGetPointerDeviceRects.
+      win32u/tests: Add NtUserGetPointerDeviceRects test for INVALID_HANDLE_VALUE.
+      win32u: Implement NtUserGetPointerDeviceRects for INVALID_HANDLE_VALUE.
+
+Bartosz Kosiorek (5):
+      msvcp: Use sizeof(wchar_t) instead of sizeof(char) for basic_string_wchar_replace_cstr_len.
+      msvcp: Use sizeof(wchar_t) instead of sizeof(char) for basic_string_wchar_replace_ch.
+      msvcp90: Add _Ctraits<float>::_Isinf(float) implementation.
+      msvcp90: Add _Ctraits<double>::_Isinf(double) implementation.
+      msvcp90: Add _Ctraits<long double>::_Isinf(long double) implementation.
+
+Benoît Legat (1):
+      rsaenh: Fix reporting of "Cryptographic Service Provider".
 
 Bernhard Übelacker (9):
-      crypt32/tests: Avoid crash in testCertProperties.
-      rsaenh: Use _aligned_free instead of free for aligned allocations (ASan).
-      dssenh: Use _aligned_free instead of free for aligned allocations (ASan).
-      dsound/tests: Don't fail test if device cannot be opened the second time.
-      webservices/tests: Improve double tests.
-      user32/tests: Fix test_window_extra_data_proc.
-      windows.ui.core.textinput/tests: Only check interfaces if retrieval succeeded.
-      imagehlp/tests: Accept zero checksum if the compiler emitted a zero checksum.
-      kernel32/tests: Fix tests with old Windows 10 versions.
-
-Charlotte Pabst (3):
-      include: Add some missing definitions in mfd3d12.idl.
-      mfplat/tests: Add tests for mf d3d12 synchronization object.
-      mfplat: Implement mf d3d12 synchronization object.
-
-Conor McCarthy (6):
-      quartz: Update current and elapsed positions in Stop().
-      d3d8/tests: Test multisampled back buffer locking.
-      d3d9/tests: Test multisampled back buffer locking.
-      wined3d: Disallow locking of multisampled back buffers.
-      mfplat/tests: Test CreateObjectFromByteStream() URL with unknown or no extension.
-      mfplat: Do not require CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE if no extension is present.
-
-Dmitry Timoshkov (9):
-      msi: Catch all exceptions in the custom DLL procedure.
-      msi: Return ERROR_INSTALL_FAILURE on an exception in the custom action.
-      ole32/tests: Add some tests for IStorage::MoveElementTo().
-      ole32: Implement IStorage::MoveElementTo() for stream element.
-      ole32: Implement IStorage::MoveElementTo() for storage element.
-      widl: Add support for enums to SLTG typelib generator.
-      widl: Add support for unions to SLTG typelib generator.
-      sane.ds: Add more traces.
-      sane.ds: SANE_DisableDSUserInterface() should accept states 5 and 6.
-
-Elizabeth Figura (11):
-      srclient: No longer prefer native.
-      wevtapi: No longer prefer native.
-      ninput: No longer prefer native.
-      msctf: No longer prefer native.
-      msctfmonitor: No longer prefer native.
-      quartz/tests: Add a few more seeking tests.
-      directmanipulation: No longer prefer native.
-      feclient: No longer prefer native.
-      d3d8thk: No longer prefer native.
-      shcore: No longer prefer native.
-      userenv: No longer prefer native.
+      mfplat/tests: Avoid crash if mediasource retrieval failed.
+      mfplat/tests: Explicitly link against kernel32 before kernelbase.
+      mfsrcsnk/tests: Add broken in test_mp4_extra_metadata.
+      user32/tests: Fix test_class_name with old Windows versions.
+      dxgi/tests: Add two missing winetest_pop_context.
+      dxgi/tests: Skip tests if DXGI 1.4 is not available.
+      msxml3/xpath: Fix out-of-bounds access in query string (ASan).
+      oleview: Avoid heap-use-after-free when reloading (ASan).
+      regedit: Avoid heap-buffer-overflow in regedit with REG_MULTI_SZ (ASan).
+
+Connor McAdams (1):
+      dinput: Lowercase device paths passed into insert_cache_entry() when reusing cache entries.
+
+Daniel Lehman (4):
+      msxml3/tests: Fix double-free of node text.
+      dwrite: Add fallbacks for arrows.
+      include: Move ifdef __cplusplus in rpcasync.h.
+      shell32: Use DE_INVALIDFILES instead of hard-coded value.
+
+Dmitry Timoshkov (2):
+      oleaut32: Take into account that SAFEARRAY element in an SLTG typelib uses 32-bit units.
+      gdi.exe: Don't use biSizeImage when calculating DIB pitch.
 
 Esme Povirk (1):
-      comdlg32: Treat empty default extension as null.
-
-Etaash Mathamsetty (3):
-      winewayland: Do not place_above on a detached client surface.
-      winewayland: Treat maximized+fullscreen state as fullscreen.
-      winewayland: Implement min/max size hints for non-resizeable windows.
-
-Fatih Uzunoglu (1):
-      mscms: Add stub for `WcsCreateIccProfile()`.
-
-Francis De Brabandere (20):
-      scrrun/tests: Add tests for dictionary put_Key.
-      scrrun/dictionary: Rename keys in place in put_Key.
-      vbscript: Bind local variables and arguments at compile time.
-      vbscript: Factor out assign_local_var from assign_ident.
-      vbscript: Bind local variable assignments at compile time.
-      vbscript: Factor out do_for_step and do_incc from interp_step and interp_incc.
-      vbscript: Bind For-loop variables at compile time.
-      vbscript: Bind class properties at compile time.
-      scrrun/tests: Add tests for Empty dictionary keys.
-      scrrun/dictionary: Match Empty keys against zero-valued and empty-string keys.
-      scrrun/tests: Add tests for Boolean dictionary keys.
-      scrrun/dictionary: Match native key semantics for Boolean keys.
-      vbscript/tests: Add tests for class declaration scope.
-      vbscript: Handle class declaration scope in the parser.
-      vbscript/tests: Add tests for sub declaration scope.
-      vbscript: Lex a dot immediately followed by a digit as a numeric literal.
-      vbscript: Report specific compile errors for trailing tokens and missing identifiers.
-      vbscript: Allow Dim to shadow a global const from a previous compile unit.
-      vbscript/tests: Add tests for one-line sub headers with multi-line bodies.
-      vbscript: Keep the offending identifier out of Err.Description.
-
-Francisco Casas (3):
-      win32u: Enable VK_KHR_external_fence_capabilities in d3dkmt_init_vulkan().
-      wined3d: Enable VK_KHR_external_fence_capabilities when initializing vulkan.
-      wined3d: Don't use texelFetchOffset() for buffers and multi-sample textures.
-
-Gabriel Ivăncescu (1):
-      ieframe: Return S_FALSE for NULL URLs in WebBrowser_Navigate.
-
-Georg Lehmann (1):
-      winevulkan: Update to VK spec version 1.4.353.
-
-Hans Leidekker (9):
-      winhttp: Revert recursion limit to 3.
-      rsaenh: Use SymCrypt for RSA and RC4.
-      dssenh: Use SymCrypt.
-      bcrypt: Use SymCrypt for hashes.
-      tomcrypt: Remove library.
-      bcrypt: Use SymCrypt for keys.
-      bcrypt: Get rid of the unixlib.
-      bcrypt: Add initial support for CHACHA20_POLY1305.
-      bcrypt: Add support for Brainpool curves.
-
-Ivan Lyugaev (1):
-      secur32: Return SEC_E_INVALID_TOKEN for invalid TLS record headers.
+      mscoree: Update Wine Mono to 11.2.0.
+
+Etaash Mathamsetty (6):
+      winewayland: Implement fractional scaling protocol.
+      winewayland: Fix missing wayland_win_data_release.
+      win32u: Always flush the window surface in expose_window_surface.
+      winewayland: Assign a name to the winewayland queue.
+      winewayland: Change default debug channel to cursor for pointer.
+      winewayland: Rename toplevel_hwnd to owner_hwnd.
+
+Feli Rippmann (1):
+      comctl32: Clamp rebar height to cyMaxChild when cyIntegral == 0 too.
+
+Floris Renaud (1):
+      po: Update Dutch translation.
+
+Francis De Brabandere (6):
+      vbscript: Index named items by name.
+      vbscript: Store global variables and functions in a single tagged tree.
+      vbscript: Parse a bare '&' followed by octal digits as an octal literal.
+      vbscript: Cache host DISPIDs as entries in the unified global tree.
+      vbscript: Raise type mismatch when comparing an array.
+      vbscript: Look up named items before builtin functions.
+
+Giang Nguyen (1):
+      d2d1: Free the vertex types array in d2d_figure_cleanup.
+
+Hans Leidekker (4):
+      bcrypt: Fix parameter validation for GCM mode.
+      bcrypt: Remove unused fields.
+      symcrypt: Accept RSA keys with public exponent 1.
+      bcrypt: Reject RSA keys with public exponent 1.
+
+Henri Verbeet (2):
+      d3dcompiler: Retrieve signature information using vkd3d in d3dcompiler_shader_reflection_init().
+      d3dcompiler: Retrieve thread group size information using vkd3d in d3dcompiler_shader_reflection_init().
 
 Jacek Caban (12):
-      jscript/tests: Remove unused variables.
-      vbscript/tests: Remove unused variables.
-      ucrtbase/tests: Link directly to environment functions.
-      msvcp140_1/tests: Remove unused variable.
-      msvcp60/tests: Remove unused variable.
-      ddraw/tests: Remove unused variable.
-      ddraw: Remove unused variable.
-      ntdll: Synthesize caller context in ARM64EC RtlRaiseException.
-      ieframe/tests: Add missing CHECK_CALLED statements.
-      scrobj/tests: Remove unused variables.
-      wpcap/tests: Remove unused variables.
-      shcore/tests: Remove unused variables.
-
-Jiangyi Chen (2):
-      winewayland.drv: Add alpha-modifier-v1 protocol to support change alpha by WAYLAND_SetLayeredWindowAttributes.
-      winewayland.drv: Add WAYLAND_UpdateLayeredWindow and add support for changing alpha using the alpha-modifier-v1 protocol.
-
-Kellen Kopp (1):
-      win32u: Fixed incorrect glyph outline size.
-
-Marc-Aurel Zent (3):
-      winemac: Remove unused includes in vulkan.c.
-      winemac: Factor out Metal device and view logic into MetalViewSwapChain.
-      winemac: Implement cross-process MetalViewSwapChain via CALayerHost.
+      dpnet: Remove unused variables.
+      rpcrt4/tests: Remove unused variables.
+      riched20/tests: Remove unused variables.
+      msxml6/tests: Enable call checks in set_xht_site.
+      msxml3/tests: Remove unused code.
+      msxml3/tests: Add missing CLEAR_CALLED statement.
+      mf/tests: Remove unused variables.
+      wbemprox: Remove unused variable.
+      winebus: Remove unused variables.
+      joy.cpl: Remove unused variable.
+      winevulkan: Remove unused variable.
+      winex11: Remove unused variables.
+
+Marius Kamm (2):
+      windowscodecs: Fix decoding GIFs that fill the LZW code table.
+      windowscodecs/tests: Test decoding a GIF that fills the LZW code table.
 
 Martin Storsjö (2):
-      ntdll: Fix building for arm64 without HWCAP_CPUID defined.
-      ntdll: Fix building for arm64 without ESR_MAGIC/esr_context.
-
-Matteo Bruni (4):
-      server: Fix numpad vkey handling.
-      winex11: Return the layout index from from detect_keyboard_layout().
-      winex11: Create layouts when falling back to fuzzy detection.
-      configure: Add -msse2 to default i386_EXTRACFLAGS.
-
-Nikolay Sivov (5):
-      msxml3/writer: Use wchar literals in more places.
-      msxml3/tests: Add more tests for the writer output.
-      msxml3/tests: Use writer output test helper throughout the tests.
-      msxml3/tests: Avoid string conversion in a few places.
-      msxml3/writer: Normalize newlines in CDATA content.
-
-Paul Gofman (8):
-      ddraw: Renamed is_root surface attribute to is_implicit.
-      ddraw: Allow attaching flip chain surfaces.
-      ddraw/tests: Add tests for attaching and detaching backbuffers on ddraw1.
-      ddraw: Force render target bind flags on v1 swapchain candidate surfaces.
-      kernelbase: Add stub for GetIntegratedDisplaySize().
-      dsound: Fail IDirectSoundCaptureBufferImpl_Lock() for invalid buffer range.
-      ddraw/tests: Remove extra backbuffer1 release in test_surface_attachment().
-      win32u: Always consider newly created shape updated in set_surface_shape().
-
-Piotr Caban (3):
-      msxml3: Don't add newline before first element when indentation is enabled.
-      msxml3: Don't indent endElement since it changes text node content.
-      include: Define more runtimeclasses in windows.storage.streams.idl.
-
-Rose Hellsing (6):
-      wineboot: Create SQMClient MachineId registry key.
-      ntdll: Account for read-only cookie in loader.
-      ntoskrnl.exe: Account for read-only cookies.
-      kernel32/tests: Add test for read-only cookie in loader.
-      riched20: Properly capture \pntext content.
-      riched20/tests: Expand editor tests to verify \pntext behaviour.
-
-Russell Greene (1):
-      hhctrl: Return a nonzero cookie from HH_INITIALIZE.
-
-Rémi Bernon (43):
-      server: Keep track of builtin class FNID on registration.
-      server: Introduce a get_class_fnid helper.
-      user32: Set builtin class FNID for menu controls.
-      user32: Set builtin class FNID for MDI client controls.
-      user32: Set builtin class FNID for dialog controls.
-      win32u: Set builtin class FNID on window creation.
-      winex11: Move find_xkb_layout_variant helper around.
-      opengl32: Allocate display lists for client-side contexts.
-      opengl32: Share display lists in wglShareLists on the PE side.
-      opengl32: Query the context profile mask on init.
-      opengl32: Track client-side buffer names allocation.
-      opengl32: Track implicit buffer names allocation.
-      user32: Store a scroll_info pointer in the scrollbar control info.
-      user32: Set FNID for the builtin scrollbar window class.
-      opengl32: Call get_integer hook after a successful unix call.
-      opengl32: Add get_integer hooks to indexed glGet functions.
-      opengl32: Pass the returned unix value to get_integer hooks.
-      opengl32: Hook more glGet functions with get_integer.
-      opengl32: Implement client / host mapping for buffer names.
-      win32u: Introduce a server_set_window_info helper.
-      server: Move window extra data to the shared memory.
-      win32u: Return value directly from get_window_extra.
-      server: Move window id / menu to the shared memory.
-      server: Move window instance to the shared memory.
-      server: Move window user data to shared memory.
-      server: Move class local flag to the shared memory.
-      server: Keep track of class window proc ansi nature.
-      win32u: Simplify winproc handle to index conversions.
-      win32u: Move window procedure to the shared memory.
-      opengl32: Implement client / host mapping for framebuffer names.
-      opengl32: Allow framebuffer implicit allocation in some core contexts.
-      opengl32: Implement client / host mapping for renderbuffer names.
-      opengl32: Allow renderbuffer implicit allocation in some core contexts.
-      opengl32: Implement client / host mapping for texture names.
-      opengl32: Ignore more cases in make_opengl get_object_type.
-      opengl32: Implement client / host mapping for sampler names.
-      opengl32: Implement client / host mapping for display list names.
-      opengl32: Implement client / host mapping for program names.
-      opengl32: Implement client / host mapping for vertex shader names.
-      opengl32: Implement client / host mapping for fragment shader names.
-      opengl32: Implement client / host mapping for semaphore names.
-      opengl32: Implement client / host mapping for memory names.
-      opengl32: Implement client / host mapping for path names.
-
-SeongChan Lee (1):
-      winexinput.sys: Fix handling of non-32-bit axis.
+      ntdll: Don't validate arm64 pointer signing when unwinding.
+      include: Use __msvcrt_ulong in setjmp.h.
+
+Matteo Bruni (1):
+      dsound: Get rid of non-float mixing remnants.
+
+Nello De Gregoris (1):
+      mfsrcsnk: Use SetCurrentPosition() for absolute byte stream seeks.
+
+Nikolay Sivov (15):
+      dsrole: Add a new dll.
+      netapi32: Forward DsRole* functions to dsrole.dll.
+      msxml3/tests: Add more selection tests.
+      msxml3/xpath: Remove duplicate line typo.
+      msxml3/tests: Add some tests for node value comparison in queries.
+      msxml3/xpath: Fix comparison direction for node-set vs value case.
+      msxml3/tests: Add some more comparison tests for XPath.
+      msxml3: Add a helper to check for XPath query keywords.
+      msxml3: Explicitly switch to XPath for XmlView documents.
+      msxml3: Handle XSLPattern syntax directly instead of converting to XPath.
+      msxml3: Fix a typo in a helper name.
+      msxml3/tests: Add a query test with attribute test in the predicate.
+      msxml3: Add support for nodeName() function.
+      msxml3: Rename helpers to reflect their purpose better.
+      msxml3: Remove now unused file.
+
+Pan Hui (1):
+      winewayland: Use process_name in wl_display_create_queue_with_name for debugging.
+
+Paul Gofman (21):
+      nsiproxy.sys: Factor out icmp_socket structure.
+      nsiproxy.sys: Rename icmp_listen into icmp_get_reply.
+      nsiproxy.sys: Contain all the reply data in struct icmp_reply_ctx.
+      nsiproxy.sys: Manage ICMP listen threads on the Unix side.
+      nsiproxy.sys: Poll all icmp sockets in a single thread.
+      nsiproxy.sys: Return ICMP ids from parse_icmp_hdr() instead of matching those.
+      nsiproxy.sys: Reuse icmp socket with matching parameters.
+      nsiproxy.sys: Support ICMP error replies with ping sockets.
+      nsiproxy.sys: Use compatible ICMP request id and seq numbers.
+      winevulkan: Do not show debug assertion dialog on Unix side exceptions.
+      win32u: Support D3D12_FENCE_SUBMIT_INFO in win32u_vkQueueSubmit().
+      win32u: Force timeline semaphore type when importing d3d12 fence.
+      ntdll/tests: Add tests for PROCESS_PARAMS_IMAGE_KEY_MISSING flag.
+      ntdll: Manage PROCESS_PARAMS_IMAGE_KEY_MISSING flag.
+      imm32/tests: Flush events in test_ImmSetCompositionWindow().
+      imm32/tests: Add tests for resetting in-composition state.
+      imm32: Strip off trailing zeros in ImeSetCompositionString().
+      imm32: Clear in-composition state when empty composition string is set.
+      imm32: Reset composition string when deactivating context.
+      wbemprox: Use device instance id for pnpdevice_id in get_display_adapters().
+      ntdll: Don't reserve exc_stack_layout twice in call_user_exception_dispatcher() on i386.
+
+Piotr Caban (10):
+      mshtml: Added IHTMLTextAreaElement::disabled property implementation.
+      msv1_0: Initialize seal keys in ntlm_SpAcceptLsaModeContext.
+      ucrtbase/tests: Remove no longer needed workaround from test_math_errors.
+      ucrtbase: Don't use builtin_rint since it doesn't respect rounding control.
+      secur32/tests: Cleanup ntlm negotiate flags tests.
+      secur32/tests: Test ctxt_attrs value after initial InitializeSecurityContextA call.
+      msv1_0: Fix buffer type returned by ntlm_SpAcceptLsaModeContext.
+      msv1_0: Make output argument optional on second call to ntlm_SpAcceptLsaModeContext.
+      msv1_0: Set ctxt_attr in ntlm_SpInitLsaModeContext.
+      msv1_0: Set ctxt_attr in ntlm_SpAcceptLsaModeContext.
+
+Rose Hellsing (4):
+      gdiplus: Recognize raw WMF streams in the WMF image codec.
+      gdiplus: Rasterize metafiles for encoding and report raw WMF as EMF.
+      gdiplus: Store the source HMETAFILE for proper lifetime management.
+      gdiplus/tests: Add tests for raw WMF load, playback and encoding.
+
+Rémi Bernon (50):
+      xinput1_3: Introduce a new open_device_at_index helper.
+      mf/topology_loader: Restore original type when optional connection fails.
+      opengl32: Implement client / host mapping for shader names.
+      opengl32: Use a per-table lock for context / pbuffer / sync handles.
+      opengl32: Move the sync handle table to the display lists.
+      opengl32: Trace client side object names leaks.
+      opengl32: Remove unused unix thunks.
+      ffmpeg: Redirect av_log calls to Wine debug traces.
+      winegstreamer: Remove unnecessary resampler inline qualifiers.
+      winegstreamer/resampler: Implement IMediaObject iface using libswresample.
+      winegstreamer/resampler: Translate IMFTransform calls to IMediaObject.
+      resampledmo: Move resampler implementation from winegstreamer.
+      win32u: Add a new driver entry to create client surfaces.
+      win32u: Create vulkan client surfaces from win32u.
+      win32u: Create OpenGL client surfaces from win32u.
+      user32/tests: Use 1024x768 as test resolution for DPI scaling on Windows.
+      user32/tests: Add more GetPointerDeviceRects tests with DPI scaling.
+      opengl32: Unset current context on thread detach.
+      win32u: Create a default thread context when binding NULL.
+      opengl32: Ensure a context is current before display lists destruction.
+      win32u: Share all unix-side GL contexts with a global context.
+      opengl32: Keep a global WOW64 buffer storage map.
+      opengl32: Implement wglShareLists on the PE side.
+      win32u: Get rid of opengl_drawable set_context callback.
+      opengl32: Allocate WOW64 buffers struct with calloc.
+      opengl32: Set dummy context with wglMakeContextCurrentARB.
+      gitlab: Add nasm to the CI docker images.
+      xinput1_3: Move keystroke states and locks to check_for_keystroke.
+      xinput1_3: Read and write current state without the controller lock.
+      xinput1_3: Use a global critical section to guard device and enabled flag.
+      xinput1_3: Extend the CS to guard all device open / read / destroy.
+      winegstreamer/color_convert: Remove unnecessary inline qualifiers.
+      winegstreamer/color_convert: Implement IMediaObject iface using libswscale.
+      winegstreamer/color_convert: Translate IMFTransform calls to IMediaObject.
+      colorcnv: Move color converter implementation from winegstreamer.
+      winegstreamer/video_processor: Reimplement using libswscale.
+      msvproc: Move video processor implementation from winegstreamer.
+      opengl32: Only query GL_CONTEXT_PROFILE_MASK with GL >= 3.2.
+      opengl32: Only reserve name range if range length is > 0.
+      opengl32: Remove now unnecessary context creation attribs.
+      winewayland: Make sure the primary monitor rect is at 0x0.
+      winewayland: Use RECT / POINT to map coordinates from surface.
+      winewayland: Use RECT / POINT to map coordinates to surface.
+      winewayland: Use a RECT in struct wayland_surface_config.
+      win32u: Use the null context instead of internal context for pbuffers.
+      win32u: Notify driver of capture window reset on destruction.
+      win32u: Pass current and previous toplevel windows to SetCapture.
+      winex11: Also ignore warped MotionNotify if cursor isn't clipped.
+      winex11: Simplify send_mouse_input when clipping cursor.
+      winex11: Get rid of now unnecessary x11drv_thread_data()->grab_hwnd.
+
+Shaun Ren (10):
+      xinput1_3: Remove an unreachable return from HID_set_state().
+      xinput1_3: Keep controller read events across device changes.
+      xinput1_3: Return correct slot indices for existing devices in find_opened_device().
+      xinput1_3: Don't wait on overlapped event if CancelIoEx failed.
+      xinput1_3: Clear enabled when controller is destroyed on read error.
+      xinput1_3: Return FALSE from controller_init if device enable failed.
+      xinput1_3: Disable controller when removing an opened device.
+      xinput1_3: Rescan controllers before reporting disconnection to callers.
+      xinput1_3: Initialize state with the previous state in read_controller_state.
+      xinput1_3: Initialize controller state only on success in controller_init.
 
 Soham Nandy (1):
-      ntdll: Preserve nonvolatile registers across VEH callbacks.
+      ntdll: Ignore hardware breakpoint traps inside the signal stack.
 
-Steven Don (2):
-      atl: Implement registering ATL window messages.
-      atl/tests: Add tests for proper handling of WM_ATLGETCONTROL and WM_ATLGETHOST.
+Thomas Portal (1):
+      user32: Add a stub for IsImmersiveProcess().
 
-Thibault Payet (1):
-      ntdll/unix: Always define get_current_thread_data.
+Tobias Markus (1):
+      ksecdd.sys: Forward BCrypt functions to bcrypt.dll.
 
-Tim Clem (1):
-      hnetcfg: Report 0 returned elements from IEnumVARIANT::Next.
-
-Twaik Yont (1):
-      wineandroid: Raise minimum SDK version to 28 (Android 9.0).
-
-Vibhav Pant (2):
-      combase/tests: Add tests for delayed marshaling of objects with apartment affinity.
-      combase: Implement delayed marshaling for RoGetAgileReference.
+Vibhav Pant (1):
+      winebth.sys: Ensure bus relations are invalidated after the PDO has been started by the PnP manager.
 
 Wolfgang Hartl (1):
-      ir50_32: Export DllRegisterServer and DllUnregisterServer.
-
-Yuxuan Shui (2):
-      mf/tests: Check frame size of video processor's output type.
-      winegstreamer: Video processor shouldn't have a preferred size.
+      oleaut32: Implement SLTG union type processing.
 
 Zhengyong Chen (1):
-      win32u: Fix signed coordinate extraction in drag_drop_call.
+      windowscodecs: Decode GIF frames on demand.
+
+Zhiyi Zhang (1):
+      server: Fix a memory leak in d3dkmt_share_objects.
+
+Ziqing Hui (1):
+      dwrite: Fix Miscellaneous Symbols font fallback.
 ```
diff --git a/AUTHORS b/AUTHORS
index e59fbd687931..54f93cd01591 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -169,6 +169,7 @@ Andy Rysin
 Aneurin Price
 Angelo Haller
 Anish Mistry
+Anna (navi) Figueiredo Gomes
 Anssi Hannula
 Anthony Fok
 Antoine Chavasse
@@ -577,6 +578,7 @@ Fatih Aşıcı
 Fatih Uzunoglu
 Federico Schwindt
 Feifan He
+Feli Rippmann
 Felix Hädicke
 Felix Janda
 Felix Münchhalfen
@@ -1207,6 +1209,7 @@ Marcus Meissner
 Marcus R. Brown
 Marek Chmiel
 Mario Kacmar
+Marius Kamm
 Mariusz Pluciński
 Mark Dufour
 Mark G. Adams
@@ -1854,6 +1857,7 @@ Thomas Mertes
 Thomas Mullaly
 Thomas Petazzoni
 Thomas Pointhuber
+Thomas Portal
 Thomas Sandford
 Thomas Spear
 Thomas Weidenmüller
@@ -1883,6 +1887,7 @@ Tobias Burnus
 Tobias Gruetzmacher
 Tobias Jakobi
 Tobias Loew
+Tobias Markus
 Todd Mokros
 Todd T. Fries
 Todd Vierling
diff --git a/NOTICES.md b/NOTICES.md
index dc4b94d902e2..cbe96715c0b5 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
@@ -1076,7 +1085,7 @@ Lesser General Public License for more details.
 ```
 
 
-### Wayland alpha modified protocol
+### Wayland alpha modifier protocol
 ```
 Copyright © 2024 Xaver Hugl
 
@@ -1125,6 +1134,29 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.
 ```
 
+### Wayland fractional scaling protocol
+```
+Copyright © 2022 Kenny Levinsen
+
+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 (including the next
+paragraph) 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.
+```
 
 ### Wayland pointer constraints protocol
 ```
diff --git a/VERSION b/VERSION
index 1d3a286ee68a..38fd2a0bbbfc 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-Wine version 11.11
+Wine version 11.12
diff --git a/aclocal.m4 b/aclocal.m4
index 11f8c855697c..e9c6459bfaa3 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -113,10 +113,13 @@ if test -s conftest.err; then
      cat conftest.err >&AS_MESSAGE_LOG_FD
 fi
 rm -f conftest.err
-AS_IF([test -n "$ac_cflags$ac_libs"],[ac_save_CPPFLAGS=$CPPFLAGS
+AS_IF([test -n "$ac_cflags$ac_libs"],[ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $ac_cflags"
+LIBS="$ac_libs $LIBS"
 $6
-CPPFLAGS=$ac_save_CPPFLAGS])
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS])
 AS_VAR_POPDEF([ac_libs])dnl
 AS_VAR_POPDEF([ac_cflags])])dnl
 
@@ -135,10 +138,13 @@ AS_VAR_IF([ac_libs],[],
       [AS_VAR_SET_IF([MINGW_PKG_CONFIG],
       [ac_libs=`$MINGW_PKG_CONFIG --libs [$2] 2>/dev/null`])])
 m4_ifval([$3],[ac_libs=[$]{ac_libs:-"$3"}])
-AS_IF([test -n "$ac_cflags$ac_libs"],[ac_save_CPPFLAGS=$CPPFLAGS
+AS_IF([test -n "$ac_cflags$ac_libs"],[ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $ac_cflags"
+LIBS="$ac_libs $LIBS"
 $4
-CPPFLAGS=$ac_save_CPPFLAGS])
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS])
 AS_VAR_POPDEF([ac_libs])dnl
 AS_VAR_POPDEF([ac_cflags])])dnl
 
@@ -236,24 +242,21 @@ ac_exeext=$ac_wine_check_headers_saved_exeext])
 AS_VAR_IF([ac_var],[yes],[$2],[$3])dnl
 AS_VAR_POPDEF([ac_var])])
 
-dnl **** Check whether the given MinGW library is available ****
+dnl **** Check whether the given MinGW library function is available ****
 dnl
-dnl Usage: WINE_CHECK_MINGW_LIB(library,function,[action-if-found],[action-if-not-found],[other-libraries])
+dnl Usage: WINE_CHECK_MINGW_FUNC(library,function,[action-if-found],[action-if-not-found])
 dnl
-AC_DEFUN([WINE_CHECK_MINGW_LIB],
-[AS_VAR_PUSHDEF([ac_var],[ac_cv_mingw_lib_$1])dnl
-AC_CACHE_CHECK([for $2 in MinGW -l$1], ac_var,
+AC_DEFUN([WINE_CHECK_MINGW_FUNC],
+[AS_VAR_PUSHDEF([ac_var],[ac_cv_mingw_func_$1])dnl
+AC_CACHE_CHECK([for $1 in PE library], ac_var,
 [ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 AS_VAR_COPY([CC],[${wine_arch}_CC])
 ac_exeext=".exe"
-LIBS="-l$1 $5 $LIBS"
-AC_LINK_IFELSE([AC_LANG_CALL([], [$2])],[AS_VAR_SET([ac_var],[yes])],[AS_VAR_SET([ac_var],[no])])
+AC_LINK_IFELSE([AC_LANG_CALL([], [$1])],[AS_VAR_SET([ac_var],[yes])],[AS_VAR_SET([ac_var],[no])])
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs])
-AS_VAR_IF([ac_var],[yes],[$3],[$4])dnl
+ac_exeext=$ac_wine_check_headers_saved_exeext])
+AS_VAR_IF([ac_var],[yes],[$2],[$3])dnl
 AS_VAR_POPDEF([ac_var])])
 
 dnl **** Check whether we need to define a symbol on the compiler command line ****
@@ -329,7 +332,9 @@ AC_DEFUN([WINE_CONFIG_MAKEFILE],[AC_REQUIRE([WINE_CONFIG_HELPERS])dnl
 AS_VAR_PUSHDEF([ac_enable],[enable_]m4_bpatsubst(m4_bpatsubst([$1],[.*/\([^/]*\)$],[\1]),[.*\.\(.*16\|vxd\)$],[win16]))dnl
 m4_append_uniq([_AC_USER_OPTS],ac_enable,[
 ])dnl
-m4_if(m4_bregexp([$1],[^tools]),[-1],[],[test "x$enable_tools" = xno || ])wine_fn_config_makefile [$1] ac_enable[]dnl
+m4_if(m4_bregexp([$1],[^tools]),[-1],[],
+      m4_if([$1],[tools/wine],[],[test "x$enable_tools" = xno || ]))dnl
+wine_fn_config_makefile [$1] ac_enable[]dnl
 AS_VAR_POPDEF([ac_enable])])
 
 dnl **** Append a file to the .gitignore list ****
diff --git a/configure b/configure
index 4fad7b2636d5..5cd54ad7b4db 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.73 for Wine 11.11.
+# Generated by GNU Autoconf 2.73 for Wine 11.12.
 #
 # Report bugs to <wine-devel@winehq.org>.
 #
@@ -587,8 +587,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='Wine'
 PACKAGE_TARNAME='wine'
-PACKAGE_VERSION='11.11'
-PACKAGE_STRING='Wine 11.11'
+PACKAGE_VERSION='11.12'
+PACKAGE_STRING='Wine 11.12'
 PACKAGE_BUGREPORT='wine-devel@winehq.org'
 PACKAGE_URL='https://www.winehq.org'
 
@@ -681,7 +681,10 @@ DBUS_CFLAGS
 INOTIFY_LIBS
 INOTIFY_CFLAGS
 PCSCLITE_LIBS
+PCSCLITE_CFLAGS
 PCAP_LIBS
+PCAP_CFLAGS
+OPENCL_CFLAGS
 WAYLAND_EGL_LIBS
 WAYLAND_EGL_CFLAGS
 XKBCOMMON_LIBS
@@ -697,6 +700,7 @@ CPP
 XMKMF
 EGL_LIBS
 EGL_CFLAGS
+NASM
 PTHREAD_LIBS
 ZLIB_PE_LIBS
 ZLIB_PE_CFLAGS
@@ -736,6 +740,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
@@ -1152,6 +1158,7 @@ enable_drmclien
 enable_dsdmo
 enable_dsound
 enable_dsquery
+enable_dsrole
 enable_dssenh
 enable_dsuiext
 enable_dswave
@@ -1420,6 +1427,7 @@ enable_rpcrt4
 enable_rsabase
 enable_rsaenh
 enable_rstrtmgr
+enable_rtscom
 enable_rtutils
 enable_rtworkq
 enable_samlib
@@ -1472,6 +1480,7 @@ enable_tdh
 enable_tdi_sys
 enable_threadpoolwinrt
 enable_thumbcache
+enable_tiptsf
 enable_traffic
 enable_twain_32
 enable_twaindsm
@@ -1675,6 +1684,7 @@ enable_dxerr8
 enable_dxerr9
 enable_dxguid
 enable_faudio
+enable_ffmpeg
 enable_fluidsynth
 enable_gsm
 enable_icucommon
@@ -1851,6 +1861,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
@@ -1901,6 +1913,12 @@ XKBCOMMON_CFLAGS
 XKBCOMMON_LIBS
 WAYLAND_EGL_CFLAGS
 WAYLAND_EGL_LIBS
+OPENCL_CFLAGS
+OPENCL_LIBS
+PCAP_CFLAGS
+PCAP_LIBS
+PCSCLITE_CFLAGS
+PCSCLITE_LIBS
 INOTIFY_CFLAGS
 INOTIFY_LIBS
 DBUS_CFLAGS
@@ -2491,7 +2509,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-'configure' configures Wine 11.11 to adapt to many kinds of systems.
+'configure' configures Wine 11.12 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -2561,7 +2579,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of Wine 11.11:";;
+     short | recursive ) echo "Configuration of Wine 11.12:";;
    esac
   cat <<\_ACEOF
 
@@ -2670,6 +2688,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
@@ -2774,6 +2797,15 @@ Some influential environment variables:
               C compiler flags for wayland-egl, overriding pkg-config
   WAYLAND_EGL_LIBS
               Linker flags for wayland-egl, overriding pkg-config
+  OPENCL_CFLAGS
+              C compiler flags for OpenCL, overriding pkg-config
+  OPENCL_LIBS Linker flags for OpenCL, overriding pkg-config
+  PCAP_CFLAGS C compiler flags for libpcap, overriding pkg-config
+  PCAP_LIBS   Linker flags for libpcap, overriding pkg-config
+  PCSCLITE_CFLAGS
+              C compiler flags for libpcsclite, overriding pkg-config
+  PCSCLITE_LIBS
+              Linker flags for libpcsclite, overriding pkg-config
   INOTIFY_CFLAGS
               C compiler flags for libinotify, overriding pkg-config
   INOTIFY_LIBS
@@ -2908,7 +2940,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-Wine configure 11.11
+Wine configure 11.12
 generated by GNU Autoconf 2.73
 
 Copyright (C) 2026 Free Software Foundation, Inc.
@@ -3314,7 +3346,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by Wine $as_me 11.11, which was
+It was created by Wine $as_me 11.12, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   $ $0$ac_configure_args_raw
@@ -4421,7 +4453,7 @@ fi
 # Check whether --with-opencl was given.
 if test ${with_opencl+y}
 then :
-  withval=$with_opencl; if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi
+  withval=$with_opencl; if test "x$withval" = "xno"; then ac_cv_header_OpenCL_opencl_h=no; fi
 fi
 
 
@@ -4442,7 +4474,7 @@ fi
 # Check whether --with-pcap was given.
 if test ${with_pcap+y}
 then :
-  withval=$with_pcap; if test "x$withval" = "xno"; then ac_cv_header_pcap_pcap_h=no; fi
+  withval=$with_pcap;
 fi
 
 
@@ -10738,12 +10770,6 @@ then :
 
 printf '%s\n' "#define STDC_HEADERS 1" >>confdefs.h
 
-fi
-ac_fn_c_check_header_compile "$LINENO" "CL/cl.h" "ac_cv_header_CL_cl_h" "$ac_includes_default"
-if test "x$ac_cv_header_CL_cl_h" = xyes
-then :
-  printf '%s\n' "#define HAVE_CL_CL_H 1" >>confdefs.h
-
 fi
 ac_fn_c_check_header_compile "$LINENO" "OpenCL/opencl.h" "ac_cv_header_OpenCL_opencl_h" "$ac_includes_default"
 if test "x$ac_cv_header_OpenCL_opencl_h" = xyes
@@ -10810,6 +10836,12 @@ if test "x$ac_cv_header_linux_cdrom_h" = xyes
 then :
   printf '%s\n' "#define HAVE_LINUX_CDROM_H 1" >>confdefs.h
 
+fi
+ac_fn_c_check_header_compile "$LINENO" "linux/errqueue.h" "ac_cv_header_linux_errqueue_h" "$ac_includes_default"
+if test "x$ac_cv_header_linux_errqueue_h" = xyes
+then :
+  printf '%s\n' "#define HAVE_LINUX_ERRQUEUE_H 1" >>confdefs.h
+
 fi
 ac_fn_c_check_header_compile "$LINENO" "linux/filter.h" "ac_cv_header_linux_filter_h" "$ac_includes_default"
 if test "x$ac_cv_header_linux_filter_h" = xyes
@@ -10966,12 +10998,6 @@ if test "x$ac_cv_header_netinet_tcp_fsm_h" = xyes
 then :
   printf '%s\n' "#define HAVE_NETINET_TCP_FSM_H 1" >>confdefs.h
 
-fi
-ac_fn_c_check_header_compile "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default"
-if test "x$ac_cv_header_pcap_pcap_h" = xyes
-then :
-  printf '%s\n' "#define HAVE_PCAP_PCAP_H 1" >>confdefs.h
-
 fi
 ac_fn_c_check_header_compile "$LINENO" "port.h" "ac_cv_header_port_h" "$ac_includes_default"
 if test "x$ac_cv_header_port_h" = xyes
@@ -12430,7 +12456,7 @@ fi
     then
         OPENCL_LIBS="-framework OpenCL"
 
-        ac_cv_lib_OpenCL_clGetPlatformInfo=yes
+        ac_cv_func_clGetPlatformInfo=yes
     fi
 
         ac_ext=m
@@ -13285,8 +13311,10 @@ fi
 FAUDIO_PE_LIBS=${FAUDIO_PE_LIBS:-"-lFAudio"}
 if test -n "$FAUDIO_PE_CFLAGS$FAUDIO_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $FAUDIO_PE_CFLAGS"
+LIBS="$FAUDIO_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW FAudio.h" >&5
 printf %s "checking for MinGW FAudio.h... " >&6; }
 if test ${ac_cv_mingw_header_FAudio_h+y}
@@ -13325,18 +13353,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_FAudio_h" >&6; }
 if test "x$ac_cv_mingw_header_FAudio_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for FAudio_CommitOperationSet in MinGW -lFAudio" >&5
-printf %s "checking for FAudio_CommitOperationSet in MinGW -lFAudio... " >&6; }
-if test ${ac_cv_mingw_lib_FAudio+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for FAudio_CommitOperationSet in PE library" >&5
+printf %s "checking for FAudio_CommitOperationSet in PE library... " >&6; }
+if test ${ac_cv_mingw_func_FAudio_CommitOperationSet+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lFAudio $FAUDIO_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13360,21 +13386,20 @@ return FAudio_CommitOperationSet ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_FAudio=yes
+  ac_cv_mingw_func_FAudio_CommitOperationSet=yes
 else case e in #(
-  e) ac_cv_mingw_lib_FAudio=no ;;
+  e) ac_cv_mingw_func_FAudio_CommitOperationSet=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_FAudio" >&5
-printf '%s\n' "$ac_cv_mingw_lib_FAudio" >&6; }
-if test "x$ac_cv_mingw_lib_FAudio" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_FAudio_CommitOperationSet" >&5
+printf '%s\n' "$ac_cv_mingw_func_FAudio_CommitOperationSet" >&6; }
+if test "x$ac_cv_mingw_func_FAudio_CommitOperationSet" = xyes
 then :
   :
 else case e in #(
@@ -13385,7 +13410,8 @@ else case e in #(
   e) FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$FAUDIO_PE_LIBS" = "x"
@@ -13410,8 +13436,10 @@ fi
 FLUIDSYNTH_PE_LIBS=${FLUIDSYNTH_PE_LIBS:-"-lfluidsynth"}
 if test -n "$FLUIDSYNTH_PE_CFLAGS$FLUIDSYNTH_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $FLUIDSYNTH_PE_CFLAGS"
+LIBS="$FLUIDSYNTH_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW fluidsynth.h" >&5
 printf %s "checking for MinGW fluidsynth.h... " >&6; }
 if test ${ac_cv_mingw_header_fluidsynth_h+y}
@@ -13450,18 +13478,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_fluidsynth_h" >&6; }
 if test "x$ac_cv_mingw_header_fluidsynth_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for new_fluid_synth in MinGW -lfluidsynth" >&5
-printf %s "checking for new_fluid_synth in MinGW -lfluidsynth... " >&6; }
-if test ${ac_cv_mingw_lib_fluidsynth+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for new_fluid_synth in PE library" >&5
+printf %s "checking for new_fluid_synth in PE library... " >&6; }
+if test ${ac_cv_mingw_func_new_fluid_synth+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lfluidsynth $FLUIDSYNTH_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13485,21 +13511,20 @@ return new_fluid_synth ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_fluidsynth=yes
+  ac_cv_mingw_func_new_fluid_synth=yes
 else case e in #(
-  e) ac_cv_mingw_lib_fluidsynth=no ;;
+  e) ac_cv_mingw_func_new_fluid_synth=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_fluidsynth" >&5
-printf '%s\n' "$ac_cv_mingw_lib_fluidsynth" >&6; }
-if test "x$ac_cv_mingw_lib_fluidsynth" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_new_fluid_synth" >&5
+printf '%s\n' "$ac_cv_mingw_func_new_fluid_synth" >&6; }
+if test "x$ac_cv_mingw_func_new_fluid_synth" = xyes
 then :
   :
 else case e in #(
@@ -13510,7 +13535,8 @@ else case e in #(
   e) FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$FLUIDSYNTH_PE_LIBS" = "x"
@@ -13535,8 +13561,10 @@ fi
 
 if test -n "$JPEG_PE_CFLAGS$JPEG_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $JPEG_PE_CFLAGS"
+LIBS="$JPEG_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW jpeglib.h" >&5
 printf %s "checking for MinGW jpeglib.h... " >&6; }
 if test ${ac_cv_mingw_header_jpeglib_h+y}
@@ -13576,18 +13604,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_jpeglib_h" >&6; }
 if test "x$ac_cv_mingw_header_jpeglib_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_decompress in MinGW -ljpeg" >&5
-printf %s "checking for jpeg_start_decompress in MinGW -ljpeg... " >&6; }
-if test ${ac_cv_mingw_lib_jpeg+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for jpeg_start_decompress in PE library" >&5
+printf %s "checking for jpeg_start_decompress in PE library... " >&6; }
+if test ${ac_cv_mingw_func_jpeg_start_decompress+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-ljpeg $JPEG_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13611,21 +13637,20 @@ return jpeg_start_decompress ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_jpeg=yes
+  ac_cv_mingw_func_jpeg_start_decompress=yes
 else case e in #(
-  e) ac_cv_mingw_lib_jpeg=no ;;
+  e) ac_cv_mingw_func_jpeg_start_decompress=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_jpeg" >&5
-printf '%s\n' "$ac_cv_mingw_lib_jpeg" >&6; }
-if test "x$ac_cv_mingw_lib_jpeg" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_jpeg_start_decompress" >&5
+printf '%s\n' "$ac_cv_mingw_func_jpeg_start_decompress" >&6; }
+if test "x$ac_cv_mingw_func_jpeg_start_decompress" = xyes
 then :
   :
 else case e in #(
@@ -13636,7 +13661,8 @@ else case e in #(
   e) JPEG_PE_CFLAGS=""; JPEG_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$JPEG_PE_LIBS" = "x"
@@ -13661,8 +13687,10 @@ fi
 LCMS2_PE_LIBS=${LCMS2_PE_LIBS:-"-llcms2"}
 if test -n "$LCMS2_PE_CFLAGS$LCMS2_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $LCMS2_PE_CFLAGS"
+LIBS="$LCMS2_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW lcms2.h" >&5
 printf %s "checking for MinGW lcms2.h... " >&6; }
 if test ${ac_cv_mingw_header_lcms2_h+y}
@@ -13701,18 +13729,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_lcms2_h" >&6; }
 if test "x$ac_cv_mingw_header_lcms2_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for cmsOpenProfileFromFile in MinGW -llcms2" >&5
-printf %s "checking for cmsOpenProfileFromFile in MinGW -llcms2... " >&6; }
-if test ${ac_cv_mingw_lib_lcms2+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for cmsOpenProfileFromFile in PE library" >&5
+printf %s "checking for cmsOpenProfileFromFile in PE library... " >&6; }
+if test ${ac_cv_mingw_func_cmsOpenProfileFromFile+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-llcms2 $LCMS2_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13736,21 +13762,20 @@ return cmsOpenProfileFromFile ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_lcms2=yes
+  ac_cv_mingw_func_cmsOpenProfileFromFile=yes
 else case e in #(
-  e) ac_cv_mingw_lib_lcms2=no ;;
+  e) ac_cv_mingw_func_cmsOpenProfileFromFile=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_lcms2" >&5
-printf '%s\n' "$ac_cv_mingw_lib_lcms2" >&6; }
-if test "x$ac_cv_mingw_lib_lcms2" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_cmsOpenProfileFromFile" >&5
+printf '%s\n' "$ac_cv_mingw_func_cmsOpenProfileFromFile" >&6; }
+if test "x$ac_cv_mingw_func_cmsOpenProfileFromFile" = xyes
 then :
   :
 else case e in #(
@@ -13761,7 +13786,8 @@ else case e in #(
   e) LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$LCMS2_PE_LIBS" = "x"
@@ -13786,8 +13812,10 @@ fi
 MPG123_PE_LIBS=${MPG123_PE_LIBS:-"-lmpg123"}
 if test -n "$MPG123_PE_CFLAGS$MPG123_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $MPG123_PE_CFLAGS"
+LIBS="$MPG123_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW mpg123.h" >&5
 printf %s "checking for MinGW mpg123.h... " >&6; }
 if test ${ac_cv_mingw_header_mpg123_h+y}
@@ -13826,18 +13854,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_mpg123_h" >&6; }
 if test "x$ac_cv_mingw_header_mpg123_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for mpg123_feed in MinGW -lmpg123" >&5
-printf %s "checking for mpg123_feed in MinGW -lmpg123... " >&6; }
-if test ${ac_cv_mingw_lib_mpg123+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for mpg123_feed in PE library" >&5
+printf %s "checking for mpg123_feed in PE library... " >&6; }
+if test ${ac_cv_mingw_func_mpg123_feed+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lmpg123 $MPG123_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13861,21 +13887,20 @@ return mpg123_feed ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_mpg123=yes
+  ac_cv_mingw_func_mpg123_feed=yes
 else case e in #(
-  e) ac_cv_mingw_lib_mpg123=no ;;
+  e) ac_cv_mingw_func_mpg123_feed=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_mpg123" >&5
-printf '%s\n' "$ac_cv_mingw_lib_mpg123" >&6; }
-if test "x$ac_cv_mingw_lib_mpg123" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_mpg123_feed" >&5
+printf '%s\n' "$ac_cv_mingw_func_mpg123_feed" >&6; }
+if test "x$ac_cv_mingw_func_mpg123_feed" = xyes
 then :
   :
 else case e in #(
@@ -13886,7 +13911,8 @@ else case e in #(
   e) MPG123_PE_CFLAGS=""; MPG123_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$MPG123_PE_LIBS" = "x"
@@ -13911,8 +13937,10 @@ fi
 
 if test -n "$PNG_PE_CFLAGS$PNG_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $PNG_PE_CFLAGS"
+LIBS="$PNG_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW png.h" >&5
 printf %s "checking for MinGW png.h... " >&6; }
 if test ${ac_cv_mingw_header_png_h+y}
@@ -13951,18 +13979,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_png_h" >&6; }
 if test "x$ac_cv_mingw_header_png_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for png_create_read_struct in MinGW -lpng" >&5
-printf %s "checking for png_create_read_struct in MinGW -lpng... " >&6; }
-if test ${ac_cv_mingw_lib_png+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for png_create_read_struct in PE library" >&5
+printf %s "checking for png_create_read_struct in PE library... " >&6; }
+if test ${ac_cv_mingw_func_png_create_read_struct+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lpng $PNG_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -13986,21 +14012,20 @@ return png_create_read_struct ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_png=yes
+  ac_cv_mingw_func_png_create_read_struct=yes
 else case e in #(
-  e) ac_cv_mingw_lib_png=no ;;
+  e) ac_cv_mingw_func_png_create_read_struct=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_png" >&5
-printf '%s\n' "$ac_cv_mingw_lib_png" >&6; }
-if test "x$ac_cv_mingw_lib_png" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_png_create_read_struct" >&5
+printf '%s\n' "$ac_cv_mingw_func_png_create_read_struct" >&6; }
+if test "x$ac_cv_mingw_func_png_create_read_struct" = xyes
 then :
   :
 else case e in #(
@@ -14011,7 +14036,8 @@ else case e in #(
   e) PNG_PE_CFLAGS=""; PNG_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$PNG_PE_LIBS" = "x"
@@ -14036,8 +14062,10 @@ fi
 
 if test -n "$TIFF_PE_CFLAGS$TIFF_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $TIFF_PE_CFLAGS"
+LIBS="$TIFF_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW tiffio.h" >&5
 printf %s "checking for MinGW tiffio.h... " >&6; }
 if test ${ac_cv_mingw_header_tiffio_h+y}
@@ -14076,18 +14104,16 @@ fi
 printf '%s\n' "$ac_cv_mingw_header_tiffio_h" >&6; }
 if test "x$ac_cv_mingw_header_tiffio_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for TIFFClientOpen in MinGW -ltiff" >&5
-printf %s "checking for TIFFClientOpen in MinGW -ltiff... " >&6; }
-if test ${ac_cv_mingw_lib_tiff+y}
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for TIFFClientOpen in PE library" >&5
+printf %s "checking for TIFFClientOpen in PE library... " >&6; }
+if test ${ac_cv_mingw_func_TIFFClientOpen+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-ltiff $TIFF_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -14111,21 +14137,20 @@ return TIFFClientOpen ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_tiff=yes
+  ac_cv_mingw_func_TIFFClientOpen=yes
 else case e in #(
-  e) ac_cv_mingw_lib_tiff=no ;;
+  e) ac_cv_mingw_func_TIFFClientOpen=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_tiff" >&5
-printf '%s\n' "$ac_cv_mingw_lib_tiff" >&6; }
-if test "x$ac_cv_mingw_lib_tiff" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_TIFFClientOpen" >&5
+printf '%s\n' "$ac_cv_mingw_func_TIFFClientOpen" >&6; }
+if test "x$ac_cv_mingw_func_TIFFClientOpen" = xyes
 then :
   :
 else case e in #(
@@ -14136,7 +14161,8 @@ else case e in #(
   e) TIFF_PE_CFLAGS=""; TIFF_PE_LIBS="" ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$TIFF_PE_LIBS" = "x"
@@ -14161,8 +14187,10 @@ fi
 VKD3D_PE_LIBS=${VKD3D_PE_LIBS:-"-lvkd3d-utils -lvkd3d -lvkd3d-shader"}
 if test -n "$VKD3D_PE_CFLAGS$VKD3D_PE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $VKD3D_PE_CFLAGS"
+LIBS="$VKD3D_PE_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for MinGW vkd3d_utils.h" >&5
 printf %s "checking for MinGW vkd3d_utils.h... " >&6; }
 if test ${ac_cv_mingw_header_vkd3d_utils_h+y}
@@ -14245,18 +14273,16 @@ then :
 fi
         if test "$ac_cv_mingw_header_vkd3d_utils_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes"
         then
-            { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for vkd3d_utils_set_log_callback in MinGW -lvkd3d-utils" >&5
-printf %s "checking for vkd3d_utils_set_log_callback in MinGW -lvkd3d-utils... " >&6; }
-if test ${ac_cv_mingw_lib_vkd3d_utils+y}
+            { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for vkd3d_utils_set_log_callback in PE library" >&5
+printf %s "checking for vkd3d_utils_set_log_callback in PE library... " >&6; }
+if test ${ac_cv_mingw_func_vkd3d_utils_set_log_callback+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lvkd3d-utils $VKD3D_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -14280,39 +14306,36 @@ return vkd3d_utils_set_log_callback ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_vkd3d_utils=yes
+  ac_cv_mingw_func_vkd3d_utils_set_log_callback=yes
 else case e in #(
-  e) ac_cv_mingw_lib_vkd3d_utils=no ;;
+  e) ac_cv_mingw_func_vkd3d_utils_set_log_callback=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d_utils" >&5
-printf '%s\n' "$ac_cv_mingw_lib_vkd3d_utils" >&6; }
-if test "x$ac_cv_mingw_lib_vkd3d_utils" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_vkd3d_utils_set_log_callback" >&5
+printf '%s\n' "$ac_cv_mingw_func_vkd3d_utils_set_log_callback" >&6; }
+if test "x$ac_cv_mingw_func_vkd3d_utils_set_log_callback" = xyes
 then :
   :
 else case e in #(
   e) : ;;
 esac
 fi
-            { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for vkd3d_shader_build_varying_map in MinGW -lvkd3d-shader" >&5
-printf %s "checking for vkd3d_shader_build_varying_map in MinGW -lvkd3d-shader... " >&6; }
-if test ${ac_cv_mingw_lib_vkd3d_shader+y}
+            { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for vkd3d_shader_build_varying_map in PE library" >&5
+printf %s "checking for vkd3d_shader_build_varying_map in PE library... " >&6; }
+if test ${ac_cv_mingw_func_vkd3d_shader_build_varying_map+y}
 then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_wine_check_headers_saved_cc=$CC
 ac_wine_check_headers_saved_exeext=$ac_exeext
-ac_wine_check_headers_saved_libs=$LIBS
 eval CC=\$${wine_arch}_CC
 ac_exeext=".exe"
-LIBS="-lvkd3d-shader $VKD3D_PE_LIBS $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -14336,28 +14359,27 @@ return vkd3d_shader_build_varying_map ();
 _ACEOF
 if ac_fn_c_try_link "$LINENO"
 then :
-  ac_cv_mingw_lib_vkd3d_shader=yes
+  ac_cv_mingw_func_vkd3d_shader_build_varying_map=yes
 else case e in #(
-  e) ac_cv_mingw_lib_vkd3d_shader=no ;;
+  e) ac_cv_mingw_func_vkd3d_shader_build_varying_map=no ;;
 esac
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam \
     conftest$ac_exeext conftest.$ac_ext
 CC=$ac_wine_check_headers_saved_cc
-ac_exeext=$ac_wine_check_headers_saved_exeext
-LIBS=$ac_wine_check_headers_saved_libs ;;
+ac_exeext=$ac_wine_check_headers_saved_exeext ;;
 esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_lib_vkd3d_shader" >&5
-printf '%s\n' "$ac_cv_mingw_lib_vkd3d_shader" >&6; }
-if test "x$ac_cv_mingw_lib_vkd3d_shader" = xyes
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_mingw_func_vkd3d_shader_build_varying_map" >&5
+printf '%s\n' "$ac_cv_mingw_func_vkd3d_shader_build_varying_map" >&6; }
+if test "x$ac_cv_mingw_func_vkd3d_shader_build_varying_map" = xyes
 then :
   :
 else case e in #(
   e) : ;;
 esac
 fi
-            if test "$ac_cv_mingw_lib_vkd3d_utils" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no"
+            if test "$ac_cv_mingw_func_vkd3d_utils_set_log_callback" = "no" -o "$ac_cv_mingw_func_vkd3d_shader_build_varying_map" = "no"
             then
                 VKD3D_PE_CFLAGS=""
                 VKD3D_PE_LIBS=""
@@ -14366,7 +14388,8 @@ fi
             VKD3D_PE_CFLAGS=""
             VKD3D_PE_LIBS=""
         fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$VKD3D_PE_LIBS" = "x"
@@ -14443,6 +14466,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"
@@ -14843,6 +14883,61 @@ esac
 fi
 
 
+case " $PE_ARCHS " in
+  *\ i386\ *|*\ x86_64\ *)
+    for ac_prog in nasm
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+printf %s "checking for $ac_word... " >&6; }
+if test ${ac_cv_prog_NASM+y}
+then :
+  printf %s "(cached) " >&6
+else case e in #(
+  e) if test -n "$NASM"; then
+  ac_cv_prog_NASM="$NASM" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  case $as_dir in #(((
+    '') as_dir=./ ;;
+    */) ;;
+    *) as_dir=$as_dir/ ;;
+  esac
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then
+    ac_cv_prog_NASM="$ac_prog"
+    printf '%s\n' "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi ;;
+esac
+fi
+NASM=$ac_cv_prog_NASM
+if test -n "$NASM"; then
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $NASM" >&5
+printf '%s\n' "$NASM" >&6; }
+else
+  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf '%s\n' "no" >&6; }
+fi
+
+
+  test -n "$NASM" && break
+done
+test -n "$NASM" || NASM="false"
+
+    test "$NASM" = false || FFMPEG_PE_CFLAGS="$FFMPEG_PE_CFLAGS -DHAVE_NASM" ;;
+esac
+
+
 if test "x$with_opengl" != "xno"
 then
     rm -f conftest.err
@@ -14872,8 +14967,10 @@ fi
 rm -f conftest.err
 if test -n "$EGL_CFLAGS$EGL_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $EGL_CFLAGS"
+LIBS="$EGL_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -lEGL" >&5
 printf %s "checking for -lEGL... " >&6; }
 if test ${ac_cv_lib_soname_EGL+y}
@@ -14881,7 +14978,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lEGL $EGL_LIBS $LIBS"
+LIBS="-lEGL  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -14937,7 +15034,8 @@ printf '%s\n' "#define SONAME_LIBEGL \"$ac_cv_lib_soname_EGL\"" >>confdefs.h
         ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -16670,8 +16768,10 @@ fi
 rm -f conftest.err
 if test -n "$XKBREGISTRY_CFLAGS$XKBREGISTRY_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $XKBREGISTRY_CFLAGS"
+LIBS="$XKBREGISTRY_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "xkbcommon/xkbregistry.h" "ac_cv_header_xkbcommon_xkbregistry_h" "$ac_includes_default"
 if test "x$ac_cv_header_xkbcommon_xkbregistry_h" = xyes
 then :
@@ -16682,7 +16782,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lxkbregistry $XKBREGISTRY_LIBS $LIBS"
+LIBS="-lxkbregistry  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -16740,7 +16840,8 @@ esac
 fi
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -16774,55 +16875,15 @@ fi
 rm -f conftest.err
 if test -n "$WAYLAND_CLIENT_CFLAGS$WAYLAND_CLIENT_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $WAYLAND_CLIENT_CFLAGS"
+LIBS="$WAYLAND_CLIENT_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "wayland-client.h" "ac_cv_header_wayland_client_h" "$ac_includes_default"
 if test "x$ac_cv_header_wayland_client_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wl_display_connect in -lwayland-client" >&5
-printf %s "checking for wl_display_connect in -lwayland-client... " >&6; }
-if test ${ac_cv_lib_wayland_client_wl_display_connect+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lwayland-client $WAYLAND_CLIENT_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char wl_display_connect (void);
-int
-main (void)
-{
-return wl_display_connect ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_wayland_client_wl_display_connect=yes
-else case e in #(
-  e) ac_cv_lib_wayland_client_wl_display_connect=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_client_wl_display_connect" >&5
-printf '%s\n' "$ac_cv_lib_wayland_client_wl_display_connect" >&6; }
-if test "x$ac_cv_lib_wayland_client_wl_display_connect" = xyes
+  ac_fn_c_check_func "$LINENO" "wl_display_connect" "ac_cv_func_wl_display_connect"
+if test "x$ac_cv_func_wl_display_connect" = xyes
 then :
   # Extract the first word of "wayland-scanner", so it can be a program name with args.
 set dummy wayland-scanner; ac_word=$2
@@ -16878,7 +16939,8 @@ fi
 
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     rm -f conftest.err
@@ -16908,52 +16970,12 @@ fi
 rm -f conftest.err
 if test -n "$XKBCOMMON_CFLAGS$XKBCOMMON_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $XKBCOMMON_CFLAGS"
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for xkb_context_new in -lxkbcommon" >&5
-printf %s "checking for xkb_context_new in -lxkbcommon... " >&6; }
-if test ${ac_cv_lib_xkbcommon_xkb_context_new+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lxkbcommon $XKBCOMMON_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char xkb_context_new (void);
-int
-main (void)
-{
-return xkb_context_new ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_xkbcommon_xkb_context_new=yes
-else case e in #(
-  e) ac_cv_lib_xkbcommon_xkb_context_new=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_xkbcommon_xkb_context_new" >&5
-printf '%s\n' "$ac_cv_lib_xkbcommon_xkb_context_new" >&6; }
-if test "x$ac_cv_lib_xkbcommon_xkb_context_new" = xyes
+LIBS="$XKBCOMMON_LIBS $LIBS"
+ac_fn_c_check_func "$LINENO" "xkb_context_new" "ac_cv_func_xkb_context_new"
+if test "x$ac_cv_func_xkb_context_new" = xyes
 then :
   :
 else case e in #(
@@ -16961,7 +16983,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     if test "x$with_opengl" != "xno"
@@ -16993,55 +17016,15 @@ fi
 rm -f conftest.err
 if test -n "$WAYLAND_EGL_CFLAGS$WAYLAND_EGL_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $WAYLAND_EGL_CFLAGS"
+LIBS="$WAYLAND_EGL_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "wayland-egl.h" "ac_cv_header_wayland_egl_h" "$ac_includes_default"
 if test "x$ac_cv_header_wayland_egl_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for wl_egl_window_create in -lwayland-egl" >&5
-printf %s "checking for wl_egl_window_create in -lwayland-egl... " >&6; }
-if test ${ac_cv_lib_wayland_egl_wl_egl_window_create+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lwayland-egl $WAYLAND_EGL_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char wl_egl_window_create (void);
-int
-main (void)
-{
-return wl_egl_window_create ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_wayland_egl_wl_egl_window_create=yes
-else case e in #(
-  e) ac_cv_lib_wayland_egl_wl_egl_window_create=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_wayland_egl_wl_egl_window_create" >&5
-printf '%s\n' "$ac_cv_lib_wayland_egl_wl_egl_window_create" >&6; }
-if test "x$ac_cv_lib_wayland_egl_wl_egl_window_create" = xyes
+  ac_fn_c_check_func "$LINENO" "wl_egl_window_create" "ac_cv_func_wl_egl_window_create"
+if test "x$ac_cv_func_wl_egl_window_create" = xyes
 then :
 
 printf '%s\n' "#define HAVE_LIBWAYLAND_EGL 1" >>confdefs.h
@@ -17053,12 +17036,13 @@ fi
 
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
         if test "x$with_wayland" != "x"
         then
-            if test -z "$ac_cv_lib_soname_EGL" -o "$ac_cv_lib_wayland_egl_wl_egl_window_create" != yes
+            if test -z "$ac_cv_lib_soname_EGL" -o "$ac_cv_func_wl_egl_window_create" != yes
 then :
   case "x$with_opengl" in
   x)   as_fn_append wine_notices "|EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL" ;;
@@ -17108,59 +17092,58 @@ enable_winex11_drv=${enable_winex11_drv:-no}
 fi
 fi
 
-if test "$ac_cv_header_CL_cl_h" = "yes"
+if test "x$with_opencl" != "xno"
 then
-    { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for clGetPlatformInfo in -lOpenCL" >&5
-printf %s "checking for clGetPlatformInfo in -lOpenCL... " >&6; }
-if test ${ac_cv_lib_OpenCL_clGetPlatformInfo+y}
+    rm -f conftest.err
+if ${OPENCL_CFLAGS:+false} :
 then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lOpenCL  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
+  if test ${PKG_CONFIG+y}
+then :
+  OPENCL_CFLAGS=`$PKG_CONFIG --cflags OpenCL 2>conftest.err`
+fi
+fi
 
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char clGetPlatformInfo (void);
-int
-main (void)
-{
-return clGetPlatformInfo ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
+if ${OPENCL_LIBS:+false} :
 then :
-  ac_cv_lib_OpenCL_clGetPlatformInfo=yes
-else case e in #(
-  e) ac_cv_lib_OpenCL_clGetPlatformInfo=no ;;
-esac
+  if test ${PKG_CONFIG+y}
+then :
+  OPENCL_LIBS=`$PKG_CONFIG --libs OpenCL 2>/dev/null`
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_OpenCL_clGetPlatformInfo" >&5
-printf '%s\n' "$ac_cv_lib_OpenCL_clGetPlatformInfo" >&6; }
-if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" = xyes
+
+OPENCL_LIBS=${OPENCL_LIBS:-"-lOpenCL"}
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: OpenCL cflags: $OPENCL_CFLAGS" >&5
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: OpenCL libs: $OPENCL_LIBS" >&5
+if test -s conftest.err; then
+     printf %s "$as_me:${as_lineno-$LINENO}: OpenCL errors: " >&5
+     cat conftest.err >&5
+fi
+rm -f conftest.err
+if test -n "$OPENCL_CFLAGS$OPENCL_LIBS"
+then :
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
+CPPFLAGS="$CPPFLAGS $OPENCL_CFLAGS"
+LIBS="$OPENCL_LIBS $LIBS"
+ac_fn_c_check_header_compile "$LINENO" "CL/cl.h" "ac_cv_header_CL_cl_h" "$ac_includes_default"
+if test "x$ac_cv_header_CL_cl_h" = xyes
+then :
+  printf '%s\n' "#define HAVE_CL_CL_H 1" >>confdefs.h
+
+fi
+
+         ac_fn_c_check_func "$LINENO" "clGetPlatformInfo" "ac_cv_func_clGetPlatformInfo"
+if test "x$ac_cv_func_clGetPlatformInfo" = xyes
 then :
-  OPENCL_LIBS="-lOpenCL"
+  :
+fi
 
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes
+if test "x$ac_cv_func_clGetPlatformInfo" != xyes
 then :
   case "x$with_opencl" in
   x)   as_fn_append wine_notices "|OpenCL ${notice_platform}development files not found, OpenCL won't be supported." ;;
@@ -17171,59 +17154,61 @@ esac
 enable_opencl=${enable_opencl:-no}
 fi
 
-if test "$ac_cv_header_pcap_pcap_h" = "yes"
+if test "x$with_pcap" != "xno"
 then
-    { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pcap_init in -lpcap" >&5
-printf %s "checking for pcap_init in -lpcap... " >&6; }
-if test ${ac_cv_lib_pcap_pcap_init+y}
+    rm -f conftest.err
+if ${PCAP_CFLAGS:+false} :
 then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcap  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pcap_init (void);
-int
-main (void)
-{
-return pcap_init ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
+  if test ${PKG_CONFIG+y}
 then :
-  ac_cv_lib_pcap_pcap_init=yes
-else case e in #(
-  e) ac_cv_lib_pcap_pcap_init=no ;;
-esac
+  PCAP_CFLAGS=`$PKG_CONFIG --cflags libpcap 2>conftest.err`
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcap_pcap_init" >&5
-printf '%s\n' "$ac_cv_lib_pcap_pcap_init" >&6; }
-if test "x$ac_cv_lib_pcap_pcap_init" = xyes
+
+if ${PCAP_LIBS:+false} :
+then :
+  if test ${PKG_CONFIG+y}
+then :
+  PCAP_LIBS=`$PKG_CONFIG --libs libpcap 2>/dev/null`
+fi
+fi
+
+PCAP_LIBS=${PCAP_LIBS:-"-lpcap"}
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: libpcap cflags: $PCAP_CFLAGS" >&5
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: libpcap libs: $PCAP_LIBS" >&5
+if test -s conftest.err; then
+     printf %s "$as_me:${as_lineno-$LINENO}: libpcap errors: " >&5
+     cat conftest.err >&5
+fi
+rm -f conftest.err
+if test -n "$PCAP_CFLAGS$PCAP_LIBS"
+then :
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
+CPPFLAGS="$CPPFLAGS $PCAP_CFLAGS"
+LIBS="$PCAP_LIBS $LIBS"
+ac_fn_c_check_header_compile "$LINENO" "pcap/pcap.h" "ac_cv_header_pcap_pcap_h" "$ac_includes_default"
+if test "x$ac_cv_header_pcap_pcap_h" = xyes
+then :
+  printf '%s\n' "#define HAVE_PCAP_PCAP_H 1" >>confdefs.h
+
+fi
+
+         ac_fn_c_check_func "$LINENO" "pcap_init" "ac_cv_func_pcap_init"
+if test "x$ac_cv_func_pcap_init" = xyes
 then :
-  PCAP_LIBS="-lpcap"
+  :
+else case e in #(
+  e) PCAP_LIBS="" ;;
+esac
+fi
 
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "x$ac_cv_lib_pcap_pcap_init" != xyes
+if test "x$ac_cv_func_pcap_init" != xyes
 then :
   case "x$with_pcap" in
   x)   as_fn_append wine_notices "|pcap ${notice_platform}development files not found, wpcap won't be supported." ;;
@@ -17236,61 +17221,50 @@ fi
 
 if test "x$with_pcsclite" != "xno"
 then
-    { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for SCardEstablishContext in -lpcsclite" >&5
-printf %s "checking for SCardEstablishContext in -lpcsclite... " >&6; }
-if test ${ac_cv_lib_pcsclite_SCardEstablishContext+y}
+    rm -f conftest.err
+if ${PCSCLITE_CFLAGS:+false} :
 then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpcsclite  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char SCardEstablishContext (void);
-int
-main (void)
-{
-return SCardEstablishContext ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
+  if test ${PKG_CONFIG+y}
 then :
-  ac_cv_lib_pcsclite_SCardEstablishContext=yes
-else case e in #(
-  e) ac_cv_lib_pcsclite_SCardEstablishContext=no ;;
-esac
+  PCSCLITE_CFLAGS=`$PKG_CONFIG --cflags libpcsclite 2>conftest.err`
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
 fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pcsclite_SCardEstablishContext" >&5
-printf '%s\n' "$ac_cv_lib_pcsclite_SCardEstablishContext" >&6; }
-if test "x$ac_cv_lib_pcsclite_SCardEstablishContext" = xyes
+
+if ${PCSCLITE_LIBS:+false} :
+then :
+  if test ${PKG_CONFIG+y}
 then :
-  PCSCLITE_LIBS="-lpcsclite"
+  PCSCLITE_LIBS=`$PKG_CONFIG --libs libpcsclite 2>/dev/null`
+fi
+fi
 
+PCSCLITE_LIBS=${PCSCLITE_LIBS:-"-lpcsclite"}
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: libpcsclite cflags: $PCSCLITE_CFLAGS" >&5
+printf '%s\n' "$as_me:${as_lineno-$LINENO}: libpcsclite libs: $PCSCLITE_LIBS" >&5
+if test -s conftest.err; then
+     printf %s "$as_me:${as_lineno-$LINENO}: libpcsclite errors: " >&5
+     cat conftest.err >&5
+fi
+rm -f conftest.err
+if test -n "$PCSCLITE_CFLAGS$PCSCLITE_LIBS"
+then :
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
+CPPFLAGS="$CPPFLAGS $PCSCLITE_CFLAGS"
+LIBS="$PCSCLITE_LIBS $LIBS"
+ac_fn_c_check_func "$LINENO" "SCardEstablishContext" "ac_cv_func_SCardEstablishContext"
+if test "x$ac_cv_func_SCardEstablishContext" = xyes
+then :
+  :
 else case e in #(
-  e) case $host_os in
-                    darwin*) PCSCLITE_LIBS="-framework PCSC"
- ;;
-                  esac ;;
+  e) PCSCLITE_LIBS="" ;;
 esac
 fi
 
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
+fi
+
 fi
 if test "x$PCSCLITE_LIBS" = x
 then :
@@ -17332,8 +17306,10 @@ fi
 rm -f conftest.err
 if test -n "$INOTIFY_CFLAGS$INOTIFY_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $INOTIFY_CFLAGS"
+LIBS="$INOTIFY_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
 if test "x$ac_cv_header_sys_inotify_h" = xyes
 then :
@@ -17341,50 +17317,8 @@ then :
 
 fi
 
-         { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for inotify_add_watch in -linotify" >&5
-printf %s "checking for inotify_add_watch in -linotify... " >&6; }
-if test ${ac_cv_lib_inotify_inotify_add_watch+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-linotify $INOTIFY_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char inotify_add_watch (void);
-int
-main (void)
-{
-return inotify_add_watch ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_inotify_inotify_add_watch=yes
-else case e in #(
-  e) ac_cv_lib_inotify_inotify_add_watch=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_inotify_inotify_add_watch" >&5
-printf '%s\n' "$ac_cv_lib_inotify_inotify_add_watch" >&6; }
-if test "x$ac_cv_lib_inotify_inotify_add_watch" = xyes
+         ac_fn_c_check_func "$LINENO" "inotify_add_watch" "ac_cv_func_inotify_add_watch"
+if test "x$ac_cv_func_inotify_add_watch" = xyes
 then :
   :
 else case e in #(
@@ -17392,7 +17326,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -17436,8 +17371,10 @@ fi
 rm -f conftest.err
 if test -n "$DBUS_CFLAGS$DBUS_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $DBUS_CFLAGS"
+LIBS="$DBUS_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "dbus/dbus.h" "ac_cv_header_dbus_dbus_h" "$ac_includes_default"
 if test "x$ac_cv_header_dbus_dbus_h" = xyes
 then :
@@ -17448,7 +17385,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-ldbus-1 $DBUS_LIBS $LIBS"
+LIBS="-ldbus-1  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -17509,7 +17446,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -17556,8 +17494,10 @@ fi
 rm -f conftest.err
 if test -n "$GNUTLS_CFLAGS$GNUTLS_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $GNUTLS_CFLAGS"
+LIBS="$GNUTLS_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default"
 if test "x$ac_cv_header_gnutls_gnutls_h" = xyes
 then :
@@ -17582,7 +17522,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lgnutls $GNUTLS_LIBS $LIBS"
+LIBS="-lgnutls  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -17638,23 +17578,15 @@ printf '%s\n' "#define SONAME_LIBGNUTLS \"$ac_cv_lib_soname_gnutls\"" >>confdefs
         ;;
 esac
 fi
-                 ac_wine_check_funcs_save_LIBS="$LIBS"
-LIBS="$LIBS $GNUTLS_LIBS"
-
-  for ac_func in gnutls_cipher_init
-do :
-  ac_fn_c_check_func "$LINENO" "gnutls_cipher_init" "ac_cv_func_gnutls_cipher_init"
+                 ac_fn_c_check_func "$LINENO" "gnutls_cipher_init" "ac_cv_func_gnutls_cipher_init"
 if test "x$ac_cv_func_gnutls_cipher_init" = xyes
 then :
-  printf '%s\n' "#define HAVE_GNUTLS_CIPHER_INIT 1" >>confdefs.h
 
 else case e in #(
   e) as_fn_append wine_notices "|libgnutls ${notice_platform}development files too old, bcrypt encryption won't be supported." ;;
 esac
 fi
 
-done
-LIBS="$ac_wine_check_funcs_save_LIBS"
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
 else case e in #(
@@ -17662,7 +17594,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -17708,55 +17641,15 @@ fi
 rm -f conftest.err
 if test -n "$HWLOC_CFLAGS$HWLOC_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $HWLOC_CFLAGS"
+LIBS="$HWLOC_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "hwloc.h" "ac_cv_header_hwloc_h" "$ac_includes_default"
 if test "x$ac_cv_header_hwloc_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for hwloc_topology_init in -lhwloc" >&5
-printf %s "checking for hwloc_topology_init in -lhwloc... " >&6; }
-if test ${ac_cv_lib_hwloc_hwloc_topology_init+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lhwloc $HWLOC_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char hwloc_topology_init (void);
-int
-main (void)
-{
-return hwloc_topology_init ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_hwloc_hwloc_topology_init=yes
-else case e in #(
-  e) ac_cv_lib_hwloc_hwloc_topology_init=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_hwloc_hwloc_topology_init" >&5
-printf '%s\n' "$ac_cv_lib_hwloc_hwloc_topology_init" >&6; }
-if test "x$ac_cv_lib_hwloc_hwloc_topology_init" = xyes
+  ac_fn_c_check_func "$LINENO" "hwloc_topology_init" "ac_cv_func_hwloc_topology_init"
+if test "x$ac_cv_func_hwloc_topology_init" = xyes
 then :
 
 printf '%s\n' "#define HAVE_LIBHWLOC 1" >>confdefs.h
@@ -17771,10 +17664,11 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
-        if test "$ac_cv_lib_hwloc_hwloc_topology_init" != "yes"
+        if test "$ac_cv_func_hwloc_topology_init" != "yes"
 then :
   case "x$with_hwloc" in
   x)   as_fn_append wine_notices "|hwloc ${notice_platform}development files not found, detailed CPU info on FreeBSD won't be supported." ;;
@@ -17817,66 +17711,27 @@ fi
 rm -f conftest.err
 if test -n "$SANE_CFLAGS$SANE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $SANE_CFLAGS"
+LIBS="$SANE_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "sane/sane.h" "ac_cv_header_sane_sane_h" "$ac_includes_default"
 if test "x$ac_cv_header_sane_sane_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for sane_init in -lsane" >&5
-printf %s "checking for sane_init in -lsane... " >&6; }
-if test ${ac_cv_lib_sane_sane_init+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lsane $SANE_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char sane_init (void);
-int
-main (void)
-{
-return sane_init ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_sane_sane_init=yes
-else case e in #(
-  e) ac_cv_lib_sane_sane_init=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_sane_sane_init" >&5
-printf '%s\n' "$ac_cv_lib_sane_sane_init" >&6; }
-if test "x$ac_cv_lib_sane_sane_init" = xyes
+  ac_fn_c_check_func "$LINENO" "sane_init" "ac_cv_func_sane_init"
+if test "x$ac_cv_func_sane_init" = xyes
 then :
   :
 fi
 
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "$ac_cv_lib_sane_sane_init" != "yes"
+if test "$ac_cv_func_sane_init" != "yes"
 then :
   case "x$with_sane" in
   x)   as_fn_append wine_notices "|libsane ${notice_platform}development files not found, scanners won't be supported." ;;
@@ -17916,55 +17771,15 @@ fi
 rm -f conftest.err
 if test -n "$USB_CFLAGS$USB_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $USB_CFLAGS"
+LIBS="$USB_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default"
 if test "x$ac_cv_header_libusb_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for libusb_interrupt_event_handler in -lusb-1.0" >&5
-printf %s "checking for libusb_interrupt_event_handler in -lusb-1.0... " >&6; }
-if test ${ac_cv_lib_usb_1_0_libusb_interrupt_event_handler+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lusb-1.0 $USB_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char libusb_interrupt_event_handler (void);
-int
-main (void)
-{
-return libusb_interrupt_event_handler ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=yes
-else case e in #(
-  e) ac_cv_lib_usb_1_0_libusb_interrupt_event_handler=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&5
-printf '%s\n' "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" >&6; }
-if test "x$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" = xyes
+  ac_fn_c_check_func "$LINENO" "libusb_interrupt_event_handler" "ac_cv_func_libusb_interrupt_event_handler"
+if test "x$ac_cv_func_libusb_interrupt_event_handler" = xyes
 then :
   :
 else case e in #(
@@ -17977,11 +17792,12 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" != "yes"
+if test "$ac_cv_func_libusb_interrupt_event_handler" != "yes"
 then :
   case "x$with_usb" in
   x)   as_fn_append wine_notices "|libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported." ;;
@@ -18098,62 +17914,23 @@ fi
 rm -f conftest.err
 if test -n "$GPHOTO2_CFLAGS$GPHOTO2_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $GPHOTO2_CFLAGS"
+LIBS="$GPHOTO2_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "gphoto2-camera.h" "ac_cv_header_gphoto2_camera_h" "$ac_includes_default"
 if test "x$ac_cv_header_gphoto2_camera_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for gp_camera_new in -lgphoto2" >&5
-printf %s "checking for gp_camera_new in -lgphoto2... " >&6; }
-if test ${ac_cv_lib_gphoto2_gp_camera_new+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lgphoto2 $GPHOTO2_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gp_camera_new (void);
-int
-main (void)
-{
-return gp_camera_new ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_gphoto2_gp_camera_new=yes
-else case e in #(
-  e) ac_cv_lib_gphoto2_gp_camera_new=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_gp_camera_new" >&5
-printf '%s\n' "$ac_cv_lib_gphoto2_gp_camera_new" >&6; }
-if test "x$ac_cv_lib_gphoto2_gp_camera_new" = xyes
+  ac_fn_c_check_func "$LINENO" "gp_camera_new" "ac_cv_func_gp_camera_new"
+if test "x$ac_cv_func_gp_camera_new" = xyes
 then :
   :
 fi
 
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
     rm -f conftest.err
@@ -18183,74 +17960,35 @@ fi
 rm -f conftest.err
 if test -n "$GPHOTO2_PORT_CFLAGS$GPHOTO2_PORT_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $GPHOTO2_PORT_CFLAGS"
+LIBS="$GPHOTO2_PORT_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "gphoto2-port.h" "ac_cv_header_gphoto2_port_h" "$ac_includes_default"
 if test "x$ac_cv_header_gphoto2_port_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for gp_port_info_list_new in -lgphoto2_port" >&5
-printf %s "checking for gp_port_info_list_new in -lgphoto2_port... " >&6; }
-if test ${ac_cv_lib_gphoto2_port_gp_port_info_list_new+y}
+  ac_fn_c_check_func "$LINENO" "gp_port_info_list_new" "ac_cv_func_gp_port_info_list_new"
+if test "x$ac_cv_func_gp_port_info_list_new" = xyes
 then :
-  printf %s "(cached) " >&6
+
+printf '%s\n' "#define HAVE_GPHOTO2_PORT 1" >>confdefs.h
+
 else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lgphoto2_port $GPHOTO2_PORT_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gp_port_info_list_new (void);
-int
-main (void)
-{
-return gp_port_info_list_new ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_gphoto2_port_gp_port_info_list_new=yes
-else case e in #(
-  e) ac_cv_lib_gphoto2_port_gp_port_info_list_new=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&5
-printf '%s\n' "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" >&6; }
-if test "x$ac_cv_lib_gphoto2_port_gp_port_info_list_new" = xyes
-then :
-
-printf '%s\n' "#define HAVE_GPHOTO2_PORT 1" >>confdefs.h
-
-else case e in #(
-  e) GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" ;;
-esac
-fi
+  e) GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" ;;
+esac
+fi
 
 else case e in #(
   e) GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS="" ;;
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "$ac_cv_lib_gphoto2_gp_camera_new" != "yes"
+if test "$ac_cv_func_gp_camera_new" != "yes"
 then :
   case "x$with_gphoto" in
   x)   as_fn_append wine_notices "|libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported." ;;
@@ -18260,7 +17998,7 @@ This is an error since --with-gphoto was requested." "$LINENO" 5 ;;
 esac
 enable_gphoto2_ds=${enable_gphoto2_ds:-no}
 fi
-if test "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" != "yes"
+if test "$ac_cv_func_gp_port_info_list_new" != "yes"
 then :
   case "x$with_gphoto" in
   x)   as_fn_append wine_notices "|libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected." ;;
@@ -18401,8 +18139,10 @@ fi
 rm -f conftest.err
 if test -n "$FREETYPE_CFLAGS$FREETYPE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $FREETYPE_CFLAGS"
+LIBS="$FREETYPE_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "ft2build.h" "ac_cv_header_ft2build_h" "$ac_includes_default"
 if test "x$ac_cv_header_ft2build_h" = xyes
 then :
@@ -18419,7 +18159,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lfreetype $FREETYPE_LIBS $LIBS"
+LIBS="-lfreetype  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -18479,7 +18219,8 @@ fi
             FREETYPE_CFLAGS=""
             FREETYPE_LIBS=""
         fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -18612,55 +18353,15 @@ fi
 rm -f conftest.err
 if test -n "$PULSE_CFLAGS$PULSE_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $PULSE_CFLAGS"
+LIBS="$PULSE_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "pulse/pulseaudio.h" "ac_cv_header_pulse_pulseaudio_h" "$ac_includes_default"
 if test "x$ac_cv_header_pulse_pulseaudio_h" = xyes
 then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for pa_stream_is_corked in -lpulse" >&5
-printf %s "checking for pa_stream_is_corked in -lpulse... " >&6; }
-if test ${ac_cv_lib_pulse_pa_stream_is_corked+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lpulse $PULSE_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char pa_stream_is_corked (void);
-int
-main (void)
-{
-return pa_stream_is_corked ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_pulse_pa_stream_is_corked=yes
-else case e in #(
-  e) ac_cv_lib_pulse_pa_stream_is_corked=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pulse_pa_stream_is_corked" >&5
-printf '%s\n' "$ac_cv_lib_pulse_pa_stream_is_corked" >&6; }
-if test "x$ac_cv_lib_pulse_pa_stream_is_corked" = xyes
+  ac_fn_c_check_func "$LINENO" "pa_stream_is_corked" "ac_cv_func_pa_stream_is_corked"
+if test "x$ac_cv_func_pa_stream_is_corked" = xyes
 then :
   :
 else case e in #(
@@ -18673,7 +18374,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -18717,8 +18419,10 @@ fi
 rm -f conftest.err
 if test -n "$FFMPEG_CFLAGS$FFMPEG_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $FFMPEG_CFLAGS"
+LIBS="$FFMPEG_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "libavutil/avutil.h" "ac_cv_header_libavutil_avutil_h" "$ac_includes_default"
 if test "x$ac_cv_header_libavutil_avutil_h" = xyes
 then :
@@ -18746,140 +18450,14 @@ fi
 
          if test "$ac_cv_header_libavutil_avutil_h" = "yes" -a "$ac_cv_header_libavformat_avformat_h" = "yes" -a "$ac_cv_header_libavcodec_avcodec_h" = "yes"
          then
-            { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for av_log_set_callback in -lavutil" >&5
-printf %s "checking for av_log_set_callback in -lavutil... " >&6; }
-if test ${ac_cv_lib_avutil_av_log_set_callback+y}
+            ac_fn_c_check_func "$LINENO" "av_log_set_callback" "ac_cv_func_av_log_set_callback"
+if test "x$ac_cv_func_av_log_set_callback" = xyes
 then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lavutil $FFMPEG_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char av_log_set_callback (void);
-int
-main (void)
-{
-return av_log_set_callback ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
+  ac_fn_c_check_func "$LINENO" "av_find_input_format" "ac_cv_func_av_find_input_format"
+if test "x$ac_cv_func_av_find_input_format" = xyes
 then :
-  ac_cv_lib_avutil_av_log_set_callback=yes
-else case e in #(
-  e) ac_cv_lib_avutil_av_log_set_callback=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avutil_av_log_set_callback" >&5
-printf '%s\n' "$ac_cv_lib_avutil_av_log_set_callback" >&6; }
-if test "x$ac_cv_lib_avutil_av_log_set_callback" = xyes
-then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for av_find_input_format in -lavformat" >&5
-printf %s "checking for av_find_input_format in -lavformat... " >&6; }
-if test ${ac_cv_lib_avformat_av_find_input_format+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lavformat $FFMPEG_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char av_find_input_format (void);
-int
-main (void)
-{
-return av_find_input_format ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_avformat_av_find_input_format=yes
-else case e in #(
-  e) ac_cv_lib_avformat_av_find_input_format=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avformat_av_find_input_format" >&5
-printf '%s\n' "$ac_cv_lib_avformat_av_find_input_format" >&6; }
-if test "x$ac_cv_lib_avformat_av_find_input_format" = xyes
-then :
-  { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for avcodec_get_name in -lavcodec" >&5
-printf %s "checking for avcodec_get_name in -lavcodec... " >&6; }
-if test ${ac_cv_lib_avcodec_avcodec_get_name+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lavcodec $FFMPEG_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char avcodec_get_name (void);
-int
-main (void)
-{
-return avcodec_get_name ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_avcodec_avcodec_get_name=yes
-else case e in #(
-  e) ac_cv_lib_avcodec_avcodec_get_name=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_avcodec_avcodec_get_name" >&5
-printf '%s\n' "$ac_cv_lib_avcodec_avcodec_get_name" >&6; }
-if test "x$ac_cv_lib_avcodec_avcodec_get_name" = xyes
+  ac_fn_c_check_func "$LINENO" "avcodec_get_name" "ac_cv_func_avcodec_get_name"
+if test "x$ac_cv_func_avcodec_get_name" = xyes
 then :
 
 printf '%s\n' "#define HAVE_FFMPEG 1" >>confdefs.h
@@ -18902,7 +18480,8 @@ fi
          else
             FFMPEG_LIBS=""
          fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -18946,8 +18525,10 @@ fi
 rm -f conftest.err
 if test -n "$GSTREAMER_CFLAGS$GSTREAMER_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $GSTREAMER_CFLAGS"
+LIBS="$GSTREAMER_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "gst/gst.h" "ac_cv_header_gst_gst_h" "$ac_includes_default"
 if test "x$ac_cv_header_gst_gst_h" = xyes
 then :
@@ -18968,50 +18549,8 @@ if ac_fn_c_try_compile "$LINENO"
 then :
   { printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 printf '%s\n' "yes" >&6; }
-                 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for gst_pad_new in -lgstreamer-1.0" >&5
-printf %s "checking for gst_pad_new in -lgstreamer-1.0... " >&6; }
-if test ${ac_cv_lib_gstreamer_1_0_gst_pad_new+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lgstreamer-1.0 $GSTREAMER_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char gst_pad_new (void);
-int
-main (void)
-{
-return gst_pad_new ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_gstreamer_1_0_gst_pad_new=yes
-else case e in #(
-  e) ac_cv_lib_gstreamer_1_0_gst_pad_new=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gstreamer_1_0_gst_pad_new" >&5
-printf '%s\n' "$ac_cv_lib_gstreamer_1_0_gst_pad_new" >&6; }
-if test "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" = xyes
+                 ac_fn_c_check_func "$LINENO" "gst_pad_new" "ac_cv_func_gst_pad_new"
+if test "x$ac_cv_func_gst_pad_new" = xyes
 then :
   :
 fi
@@ -19027,11 +18566,12 @@ fi
 rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "x$ac_glib2_broken" != xyes -a "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes
+if test "x$ac_glib2_broken" != xyes -a "x$ac_cv_func_gst_pad_new" != xyes
 then :
   case "x$with_gstreamer" in
   x)   as_fn_append wine_notices "|gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported." ;;
@@ -19073,52 +18613,12 @@ fi
 rm -f conftest.err
 if test -n "$ALSA_CFLAGS$ALSA_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $ALSA_CFLAGS"
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_hw_params_get_access_mask in -lasound" >&5
-printf %s "checking for snd_pcm_hw_params_get_access_mask in -lasound... " >&6; }
-if test ${ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lasound $ALSA_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char snd_pcm_hw_params_get_access_mask (void);
-int
-main (void)
-{
-return snd_pcm_hw_params_get_access_mask ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=yes
-else case e in #(
-  e) ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&5
-printf '%s\n' "$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" >&6; }
-if test "x$ac_cv_lib_asound_snd_pcm_hw_params_get_access_mask" = xyes
+LIBS="$ALSA_LIBS $LIBS"
+ac_fn_c_check_func "$LINENO" "snd_pcm_hw_params_get_access_mask" "ac_cv_func_snd_pcm_hw_params_get_access_mask"
+if test "x$ac_cv_func_snd_pcm_hw_params_get_access_mask" = xyes
 then :
   :
 else case e in #(
@@ -19126,7 +18626,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19257,58 +18758,18 @@ fi
 rm -f conftest.err
 if test -n "$UDEV_CFLAGS$UDEV_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $UDEV_CFLAGS"
+LIBS="$UDEV_LIBS $LIBS"
        for ac_header in libudev.h
 do :
   ac_fn_c_check_header_compile "$LINENO" "libudev.h" "ac_cv_header_libudev_h" "$ac_includes_default"
 if test "x$ac_cv_header_libudev_h" = xyes
 then :
   printf '%s\n' "#define HAVE_LIBUDEV_H 1" >>confdefs.h
- { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for udev_new in -ludev" >&5
-printf %s "checking for udev_new in -ludev... " >&6; }
-if test ${ac_cv_lib_udev_udev_new+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-ludev $UDEV_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char udev_new (void);
-int
-main (void)
-{
-return udev_new ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_udev_udev_new=yes
-else case e in #(
-  e) ac_cv_lib_udev_udev_new=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_udev_udev_new" >&5
-printf '%s\n' "$ac_cv_lib_udev_udev_new" >&6; }
-if test "x$ac_cv_lib_udev_udev_new" = xyes
+ ac_fn_c_check_func "$LINENO" "udev_new" "ac_cv_func_udev_new"
+if test "x$ac_cv_func_udev_new" = xyes
 then :
 
 printf '%s\n' "#define HAVE_UDEV 1" >>confdefs.h
@@ -19324,7 +18785,8 @@ esac
 fi
 
 done
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19368,8 +18830,10 @@ fi
 rm -f conftest.err
 if test -n "$SDL2_CFLAGS$SDL2_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $SDL2_CFLAGS"
+LIBS="$SDL2_LIBS $LIBS"
        for ac_header in SDL.h
 do :
   ac_fn_c_check_header_compile "$LINENO" "SDL.h" "ac_cv_header_SDL_h" "$ac_includes_default"
@@ -19383,7 +18847,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lSDL2 $SDL2_LIBS $LIBS"
+LIBS="-lSDL2  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -19442,7 +18906,8 @@ fi
 fi
 
 done
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19486,8 +18951,10 @@ fi
 rm -f conftest.err
 if test -n "$CAPI20_CFLAGS$CAPI20_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $CAPI20_CFLAGS"
+LIBS="$CAPI20_LIBS $LIBS"
     ac_fn_c_check_header_compile "$LINENO" "capi20.h" "ac_cv_header_capi20_h" "#define __user
 "
 if test "x$ac_cv_header_capi20_h" = xyes
@@ -19505,50 +18972,8 @@ fi
 
     if test "$ac_cv_header_capi20_h" = "yes" -a "$ac_cv_header_linux_capi_h" = "yes"
     then
-        { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for capi20_register in -lcapi20" >&5
-printf %s "checking for capi20_register in -lcapi20... " >&6; }
-if test ${ac_cv_lib_capi20_capi20_register+y}
-then :
-  printf %s "(cached) " >&6
-else case e in #(
-  e) ac_check_lib_save_LIBS=$LIBS
-LIBS="-lcapi20 $CAPI20_LIBS $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.
-   The 'extern "C"' is for builds by C++ compilers;
-   although this is not generally supported in C code supporting it here
-   has little cost and some practical benefit (sr 110532).  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char capi20_register (void);
-int
-main (void)
-{
-return capi20_register ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"
-then :
-  ac_cv_lib_capi20_capi20_register=yes
-else case e in #(
-  e) ac_cv_lib_capi20_capi20_register=no ;;
-esac
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.beam \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS ;;
-esac
-fi
-{ printf '%s\n' "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_capi20_capi20_register" >&5
-printf '%s\n' "$ac_cv_lib_capi20_capi20_register" >&6; }
-if test "x$ac_cv_lib_capi20_capi20_register" = xyes
+        ac_fn_c_check_func "$LINENO" "capi20_register" "ac_cv_func_capi20_register"
+if test "x$ac_cv_func_capi20_register" = xyes
 then :
   :
 else case e in #(
@@ -19557,11 +18982,12 @@ esac
 fi
 
     fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
-if test "x$ac_cv_lib_capi20_capi20_register" != xyes
+if test "x$ac_cv_func_capi20_register" != xyes
 then :
   case "x$with_capi" in
   x)   as_fn_append wine_notices "|libcapi20 ${notice_platform}development files not found, ISDN won't be supported." ;;
@@ -19601,8 +19027,10 @@ fi
 rm -f conftest.err
 if test -n "$CUPS_CFLAGS$CUPS_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $CUPS_CFLAGS"
+LIBS="$CUPS_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "cups/cups.h" "ac_cv_header_cups_cups_h" "$ac_includes_default"
 if test "x$ac_cv_header_cups_cups_h" = xyes
 then :
@@ -19625,7 +19053,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lcups $CUPS_LIBS $LIBS"
+LIBS="-lcups  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -19685,7 +19113,8 @@ fi
                             CUPS_CFLAGS=""
                             CUPS_LIBS=""
                         fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19729,8 +19158,10 @@ fi
 rm -f conftest.err
 if test -n "$FONTCONFIG_CFLAGS$FONTCONFIG_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $FONTCONFIG_CFLAGS"
+LIBS="$FONTCONFIG_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "fontconfig/fontconfig.h" "ac_cv_header_fontconfig_fontconfig_h" "$ac_includes_default"
 if test "x$ac_cv_header_fontconfig_fontconfig_h" = xyes
 then :
@@ -19741,7 +19172,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lfontconfig $FONTCONFIG_LIBS $LIBS"
+LIBS="-lfontconfig  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -19802,7 +19233,8 @@ else case e in #(
 esac
 fi
 
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19846,8 +19278,10 @@ fi
 rm -f conftest.err
 if test -n "$KRB5_CFLAGS$KRB5_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $KRB5_CFLAGS"
+LIBS="$KRB5_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "krb5/krb5.h" "ac_cv_header_krb5_krb5_h" "$ac_includes_default"
 if test "x$ac_cv_header_krb5_krb5_h" = xyes
 then :
@@ -19864,7 +19298,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lkrb5 $KRB5_LIBS $LIBS"
+LIBS="-lkrb5  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -19923,7 +19357,8 @@ fi
          else
              KRB5_CFLAGS=""
          fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -19968,8 +19403,10 @@ fi
 rm -f conftest.err
 if test -n "$GSSAPI_CFLAGS$GSSAPI_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $GSSAPI_CFLAGS"
+LIBS="$GSSAPI_LIBS $LIBS"
 ac_fn_c_check_header_compile "$LINENO" "gssapi/gssapi.h" "ac_cv_header_gssapi_gssapi_h" "$ac_includes_default"
 if test "x$ac_cv_header_gssapi_gssapi_h" = xyes
 then :
@@ -19992,7 +19429,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lgssapi_krb5 $GSSAPI_LIBS $LIBS"
+LIBS="-lgssapi_krb5  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -20051,7 +19488,8 @@ fi
         else
             GSSAPI_CFLAGS=""
         fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -20216,8 +19654,10 @@ fi
 rm -f conftest.err
 if test -n "$NETAPI_CFLAGS$NETAPI_LIBS"
 then :
-  ac_save_CPPFLAGS=$CPPFLAGS
+  ac_save_pkg_CPPFLAGS=$CPPFLAGS
+ac_save_pkg_LIBS=$LIBS
 CPPFLAGS="$CPPFLAGS $NETAPI_CFLAGS"
+LIBS="$NETAPI_LIBS $LIBS"
 { printf '%s\n' "$as_me:${as_lineno-$LINENO}: checking for -lnetapi" >&5
 printf %s "checking for -lnetapi... " >&6; }
 if test ${ac_cv_lib_soname_netapi+y}
@@ -20225,7 +19665,7 @@ then :
   printf %s "(cached) " >&6
 else case e in #(
   e) ac_check_soname_save_LIBS=$LIBS
-LIBS="-lnetapi $NETAPI_LIBS $LIBS"
+LIBS="-lnetapi  $LIBS"
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -20282,7 +19722,8 @@ printf '%s\n' "#define SONAME_LIBNETAPI \"$ac_cv_lib_soname_netapi\"" >>confdefs
         ;;
 esac
 fi
-CPPFLAGS=$ac_save_CPPFLAGS
+CPPFLAGS=$ac_save_pkg_CPPFLAGS
+LIBS=$ac_save_pkg_LIBS
 fi
 
 fi
@@ -22972,6 +22413,7 @@ wine_fn_config_makefile dlls/dsdmo/tests enable_tests
 wine_fn_config_makefile dlls/dsound enable_dsound
 wine_fn_config_makefile dlls/dsound/tests enable_tests
 wine_fn_config_makefile dlls/dsquery enable_dsquery
+wine_fn_config_makefile dlls/dsrole enable_dsrole
 wine_fn_config_makefile dlls/dssenh enable_dssenh
 wine_fn_config_makefile dlls/dssenh/tests enable_tests
 wine_fn_config_makefile dlls/dsuiext enable_dsuiext
@@ -23394,6 +22836,7 @@ wine_fn_config_makefile dlls/rsabase enable_rsabase
 wine_fn_config_makefile dlls/rsaenh enable_rsaenh
 wine_fn_config_makefile dlls/rsaenh/tests enable_tests
 wine_fn_config_makefile dlls/rstrtmgr enable_rstrtmgr
+wine_fn_config_makefile dlls/rtscom enable_rtscom
 wine_fn_config_makefile dlls/rtutils enable_rtutils
 wine_fn_config_makefile dlls/rtworkq enable_rtworkq
 wine_fn_config_makefile dlls/rtworkq/tests enable_tests
@@ -23476,6 +22919,7 @@ wine_fn_config_makefile dlls/threadpoolwinrt enable_threadpoolwinrt
 wine_fn_config_makefile dlls/threadpoolwinrt/tests enable_tests
 wine_fn_config_makefile dlls/thumbcache enable_thumbcache
 wine_fn_config_makefile dlls/thumbcache/tests enable_tests
+wine_fn_config_makefile dlls/tiptsf enable_tiptsf
 wine_fn_config_makefile dlls/toolhelp.dll16 enable_win16
 wine_fn_config_makefile dlls/traffic enable_traffic
 wine_fn_config_makefile dlls/twain.dll16 enable_win16
@@ -23782,6 +23226,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
@@ -23948,7 +23393,7 @@ wine_fn_config_makefile server enable_server
 test "x$enable_tools" = xno || wine_fn_config_makefile tools enable_tools
 test "x$enable_tools" = xno || wine_fn_config_makefile tools/sfnt2fon enable_sfnt2fon
 test "x$enable_tools" = xno || wine_fn_config_makefile tools/widl enable_widl
-test "x$enable_tools" = xno || wine_fn_config_makefile tools/wine enable_wine
+wine_fn_config_makefile tools/wine enable_wine
 test "x$enable_tools" = xno || wine_fn_config_makefile tools/winebuild enable_winebuild
 test "x$enable_tools" = xno || wine_fn_config_makefile tools/winedump enable_winedump
 test "x$enable_tools" = xno || wine_fn_config_makefile tools/winegcc enable_winegcc
@@ -24026,7 +23471,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)'"
 
@@ -24497,7 +23942,7 @@ cat >>"$CONFIG_STATUS" <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by Wine $as_me 11.11, which was
+This file was extended by Wine $as_me 11.12, which was
 generated by GNU Autoconf 2.73.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24557,7 +24002,7 @@ ac_cs_config_escaped=`printf '%s\n' "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>"$CONFIG_STATUS" <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
-Wine config.status 11.11
+Wine config.status 11.12
 configured by $0, generated by GNU Autoconf 2.73,
   with options \\"\$ac_cs_config\\"
 
@@ -24877,6 +24322,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
@@ -24916,6 +24363,7 @@ XSLT_PE_LIBS = $XSLT_PE_LIBS
 ZLIB_PE_CFLAGS = $ZLIB_PE_CFLAGS
 ZLIB_PE_LIBS = $ZLIB_PE_LIBS
 PTHREAD_LIBS = $PTHREAD_LIBS
+NASM = $NASM
 EGL_CFLAGS = $EGL_CFLAGS
 EGL_LIBS = $EGL_LIBS
 XMKMF = $XMKMF
@@ -24931,7 +24379,10 @@ XKBCOMMON_CFLAGS = $XKBCOMMON_CFLAGS
 XKBCOMMON_LIBS = $XKBCOMMON_LIBS
 WAYLAND_EGL_CFLAGS = $WAYLAND_EGL_CFLAGS
 WAYLAND_EGL_LIBS = $WAYLAND_EGL_LIBS
+OPENCL_CFLAGS = $OPENCL_CFLAGS
+PCAP_CFLAGS = $PCAP_CFLAGS
 PCAP_LIBS = $PCAP_LIBS
+PCSCLITE_CFLAGS = $PCSCLITE_CFLAGS
 PCSCLITE_LIBS = $PCSCLITE_LIBS
 INOTIFY_CFLAGS = $INOTIFY_CFLAGS
 INOTIFY_LIBS = $INOTIFY_LIBS
diff --git a/configure.ac b/configure.ac
index d597bad37504..a8e3bf77076f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -47,11 +47,10 @@ AC_ARG_WITH(krb5,      AS_HELP_STRING([--without-krb5],[do not use krb5 (Kerbero
 AC_ARG_WITH(mingw,     AS_HELP_STRING([--without-mingw],[do not use the MinGW cross-compiler]))
 AC_ARG_WITH(netapi,    AS_HELP_STRING([--without-netapi],[do not use the Samba NetAPI library]))
 AC_ARG_WITH(opencl,    AS_HELP_STRING([--without-opencl],[do not use OpenCL]),
-            [if test "x$withval" = "xno"; then ac_cv_header_CL_cl_h=no; ac_cv_header_OpenCL_opencl_h=no; fi])
+            [if test "x$withval" = "xno"; then ac_cv_header_OpenCL_opencl_h=no; fi])
 AC_ARG_WITH(opengl,    AS_HELP_STRING([--without-opengl],[do not use OpenGL]))
 AC_ARG_WITH(oss,       AS_HELP_STRING([--without-oss],[do not use the OSS sound support]))
-AC_ARG_WITH(pcap,      AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]),
-            [if test "x$withval" = "xno"; then ac_cv_header_pcap_pcap_h=no; fi])
+AC_ARG_WITH(pcap,      AS_HELP_STRING([--without-pcap],[do not use the Packet Capture library]))
 AC_ARG_WITH(pcsclite,  AS_HELP_STRING([--without-pcsclite],[do not use PCSC lite]))
 AC_ARG_WITH(pthread,   AS_HELP_STRING([--without-pthread],[do not use the pthread library]))
 AC_ARG_WITH(pulse,     AS_HELP_STRING([--without-pulse],[do not use PulseAudio sound support]))
@@ -724,7 +723,6 @@ m4_ifdef([AC_SYS_YEAR2038],
          [test "$ac_cv_sys_file_offset_bits" = 64 && AC_DEFINE(_TIME_BITS,64,[Define to 64 to enable 64-bit time_t])])
 
 AC_CHECK_HEADERS(\
-	CL/cl.h \
 	OpenCL/opencl.h \
 	arpa/inet.h \
 	arpa/nameser.h \
@@ -736,6 +734,7 @@ AC_CHECK_HEADERS(\
 	gettext-po.h \
 	link.h \
 	linux/cdrom.h \
+	linux/errqueue.h \
 	linux/filter.h \
 	linux/fs.h \
 	linux/hdreg.h \
@@ -762,7 +761,6 @@ AC_CHECK_HEADERS(\
 	netinet/in_systm.h \
 	netinet/tcp.h \
 	netinet/tcp_fsm.h \
-	pcap/pcap.h \
 	port.h \
 	pwd.h \
 	sched.h \
@@ -1030,7 +1028,7 @@ case $host_os in
     if test "$ac_cv_header_OpenCL_opencl_h" = "yes"
     then
         AC_SUBST(OPENCL_LIBS,"-framework OpenCL")
-        ac_cv_lib_OpenCL_clGetPlatformInfo=yes
+        ac_cv_func_clGetPlatformInfo=yes
     fi
 
     dnl Check for MTLDevice registryID property
@@ -1137,7 +1135,7 @@ if test "x$with_system_dllpath" != "x" -a -n "$PE_ARCHS"
 then
     WINE_MINGW_PACKAGE_FLAGS(FAUDIO,[FAudio],[-lFAudio],
         [WINE_CHECK_MINGW_HEADER(FAudio.h,
-            [WINE_CHECK_MINGW_LIB(FAudio,FAudio_CommitOperationSet,[:],[FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS=""],[$FAUDIO_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(FAudio_CommitOperationSet,[:],[FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS=""])],
             [FAUDIO_PE_CFLAGS=""; FAUDIO_PE_LIBS=""])])
     if test "x$FAUDIO_PE_LIBS" = "x"
     then
@@ -1146,7 +1144,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(FLUIDSYNTH,[fluidsynth],[-lfluidsynth],
         [WINE_CHECK_MINGW_HEADER(fluidsynth.h,
-            [WINE_CHECK_MINGW_LIB(fluidsynth,new_fluid_synth,[:],[FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS=""],[$FLUIDSYNTH_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(new_fluid_synth,[:],[FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS=""])],
             [FLUIDSYNTH_PE_CFLAGS=""; FLUIDSYNTH_PE_LIBS=""])])
     if test "x$FLUIDSYNTH_PE_LIBS" = "x"
     then
@@ -1155,7 +1153,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(JPEG,[libjpeg],,
         [WINE_CHECK_MINGW_HEADER(jpeglib.h,
-            [WINE_CHECK_MINGW_LIB(jpeg,jpeg_start_decompress,[:],[JPEG_PE_CFLAGS=""; JPEG_PE_LIBS=""],[$JPEG_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(jpeg_start_decompress,[:],[JPEG_PE_CFLAGS=""; JPEG_PE_LIBS=""])],
             [JPEG_PE_CFLAGS=""; JPEG_PE_LIBS=""],
             [#include <stddef.h>
              #include <stdio.h>])])
@@ -1166,7 +1164,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(LCMS2,[lcms2],[-llcms2],
         [WINE_CHECK_MINGW_HEADER(lcms2.h,
-            [WINE_CHECK_MINGW_LIB(lcms2,cmsOpenProfileFromFile,[:],[LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS=""],[$LCMS2_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(cmsOpenProfileFromFile,[:],[LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS=""])],
             [LCMS2_PE_CFLAGS=""; LCMS2_PE_LIBS=""])])
     if test "x$LCMS2_PE_LIBS" = "x"
     then
@@ -1175,7 +1173,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(MPG123,[libmpg123],[-lmpg123],
         [WINE_CHECK_MINGW_HEADER(mpg123.h,
-            [WINE_CHECK_MINGW_LIB(mpg123,mpg123_feed,[:],[MPG123_PE_CFLAGS=""; MPG123_PE_LIBS=""],[$MPG123_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(mpg123_feed,[:],[MPG123_PE_CFLAGS=""; MPG123_PE_LIBS=""])],
             [MPG123_PE_CFLAGS=""; MPG123_PE_LIBS=""])])
     if test "x$MPG123_PE_LIBS" = "x"
     then
@@ -1184,7 +1182,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(PNG,[libpng],,
         [WINE_CHECK_MINGW_HEADER(png.h,
-            [WINE_CHECK_MINGW_LIB(png,png_create_read_struct,[:],[PNG_PE_CFLAGS=""; PNG_PE_LIBS=""],[$PNG_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(png_create_read_struct,[:],[PNG_PE_CFLAGS=""; PNG_PE_LIBS=""])],
             [PNG_PE_CFLAGS=""; PNG_PE_LIBS=""])])
     if test "x$PNG_PE_LIBS" = "x"
     then
@@ -1193,7 +1191,7 @@ then
 
     WINE_MINGW_PACKAGE_FLAGS(TIFF,[libtiff-4],,
         [WINE_CHECK_MINGW_HEADER(tiffio.h,
-            [WINE_CHECK_MINGW_LIB(tiff,TIFFClientOpen,[:],[TIFF_PE_CFLAGS=""; TIFF_PE_LIBS=""],[$TIFF_PE_LIBS])],
+            [WINE_CHECK_MINGW_FUNC(TIFFClientOpen,[:],[TIFF_PE_CFLAGS=""; TIFF_PE_LIBS=""])],
             [TIFF_PE_CFLAGS=""; TIFF_PE_LIBS=""])])
     if test "x$TIFF_PE_LIBS" = "x"
     then
@@ -1205,9 +1203,9 @@ then
         WINE_CHECK_MINGW_HEADER(vkd3d_shader.h)
         if test "$ac_cv_mingw_header_vkd3d_utils_h" = "yes" -a "$ac_cv_mingw_header_vkd3d_shader_h" = "yes"
         then
-            WINE_CHECK_MINGW_LIB(vkd3d-utils,vkd3d_utils_set_log_callback,[:],[:],[$VKD3D_PE_LIBS])
-            WINE_CHECK_MINGW_LIB(vkd3d-shader,vkd3d_shader_build_varying_map,[:],[:],[$VKD3D_PE_LIBS])
-            if test "$ac_cv_mingw_lib_vkd3d_utils" = "no" -o "$ac_cv_mingw_lib_vkd3d_shader" = "no"
+            WINE_CHECK_MINGW_FUNC(vkd3d_utils_set_log_callback,[:],[:])
+            WINE_CHECK_MINGW_FUNC(vkd3d_shader_build_varying_map,[:],[:])
+            if test "$ac_cv_mingw_func_vkd3d_utils_set_log_callback" = "no" -o "$ac_cv_mingw_func_vkd3d_shader_build_varying_map" = "no"
             then
                 VKD3D_PE_CFLAGS=""
                 VKD3D_PE_LIBS=""
@@ -1226,6 +1224,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")
@@ -1254,12 +1253,20 @@ WINE_ERROR_WITH(pthread,[test "x$ac_cv_func_pthread_create" != xyes -a "x$PTHREA
 [pthread ${notice_platform}development files not found.
 Wine cannot support threads without libpthread.])
 
+dnl **** Check for nasm ****
+
+case " $PE_ARCHS " in
+  *\ i386\ *|*\ x86_64\ *)
+    AC_CHECK_PROGS(NASM,[nasm],[false])
+    test "$NASM" = false || FFMPEG_PE_CFLAGS="$FFMPEG_PE_CFLAGS -DHAVE_NASM" ;;
+esac
+
 dnl **** Check for EGL ****
 
 if test "x$with_opengl" != "xno"
 then
     WINE_PACKAGE_FLAGS(EGL,[egl],[-lEGL],,,
-        [WINE_CHECK_SONAME(EGL,eglGetProcAddress,,,[$EGL_LIBS])])
+        [WINE_CHECK_SONAME(EGL,eglGetProcAddress)])
 fi
 WINE_NOTICE_WITH(opengl, [test -z "$ac_cv_lib_soname_EGL"],
     [EGL ${notice_platform}development files not found])
@@ -1434,29 +1441,29 @@ if test "x$have_x$with_wayland" != "xnono"
 then
     WINE_PACKAGE_FLAGS(XKBREGISTRY,[xkbregistry],,,,
         [AC_CHECK_HEADER([xkbcommon/xkbregistry.h],
-                [WINE_CHECK_SONAME(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""],[$XKBREGISTRY_LIBS])])])
+                [WINE_CHECK_SONAME(xkbregistry,rxkb_context_new,[:],[XKBREGISTRY_LIBS=""])])])
 fi
 
 if test "x$with_wayland" != "xno"
 then
     WINE_PACKAGE_FLAGS(WAYLAND_CLIENT,[wayland-client],,,,
         [AC_CHECK_HEADER([wayland-client.h],
-           [AC_CHECK_LIB(wayland-client,wl_display_connect,
+           [AC_CHECK_FUNC(wl_display_connect,
               [AC_PATH_PROG(WAYLAND_SCANNER,wayland-scanner,
                             [`test -n "$PKG_CONFIG" && $PKG_CONFIG --variable=wayland_scanner wayland-scanner 2>/dev/null`])],
-              [WAYLAND_CLIENT_LIBS=""],[$WAYLAND_CLIENT_LIBS])])])
+              [WAYLAND_CLIENT_LIBS=""])])])
     WINE_PACKAGE_FLAGS(XKBCOMMON,[xkbcommon],,,,
-        [AC_CHECK_LIB(xkbcommon,xkb_context_new,[:],[XKBCOMMON_LIBS=""],[$XKBCOMMON_LIBS])])
+        [AC_CHECK_FUNC(xkb_context_new,[:],[XKBCOMMON_LIBS=""])])
     if test "x$with_opengl" != "xno"
     then
         WINE_PACKAGE_FLAGS(WAYLAND_EGL,[wayland-egl],,,,
             [AC_CHECK_HEADER([wayland-egl.h],
-               [AC_CHECK_LIB(wayland-egl,wl_egl_window_create,
+               [AC_CHECK_FUNC(wl_egl_window_create,
                   [AC_DEFINE(HAVE_LIBWAYLAND_EGL, 1, [Define if we have the wayland-egl development environment])],
-                  [WAYLAND_EGL_LIBS=""],[$WAYLAND_EGL_LIBS])])])
+                  [WAYLAND_EGL_LIBS=""])])])
         if test "x$with_wayland" != "x"
         then
-            WINE_NOTICE_WITH(opengl, [test -z "$ac_cv_lib_soname_EGL" -o "$ac_cv_lib_wayland_egl_wl_egl_window_create" != yes],
+            WINE_NOTICE_WITH(opengl, [test -z "$ac_cv_lib_soname_EGL" -o "$ac_cv_func_wl_egl_window_create" != yes],
                 [EGL ${notice_platform}development files not found, the Wayland driver won't support OpenGL])
         fi
     fi
@@ -1479,27 +1486,32 @@ else
 fi
 
 dnl **** Check for OpenCL ****
-if test "$ac_cv_header_CL_cl_h" = "yes"
+if test "x$with_opencl" != "xno"
 then
-    AC_CHECK_LIB(OpenCL,clGetPlatformInfo,[AC_SUBST(OPENCL_LIBS,["-lOpenCL"])])
+    WINE_PACKAGE_FLAGS(OPENCL,[OpenCL],[-lOpenCL],,,
+        [AC_CHECK_HEADERS([CL/cl.h])
+         AC_CHECK_FUNC(clGetPlatformInfo,[:])])
 fi
-WINE_NOTICE_WITH(opencl,[test "x$ac_cv_lib_OpenCL_clGetPlatformInfo" != xyes],
+WINE_NOTICE_WITH(opencl,[test "x$ac_cv_func_clGetPlatformInfo" != xyes],
                  [OpenCL ${notice_platform}development files not found, OpenCL won't be supported.],
                  [enable_opencl])
 
 dnl **** Check for libpcap ****
-if test "$ac_cv_header_pcap_pcap_h" = "yes"
+if test "x$with_pcap" != "xno"
 then
-    AC_CHECK_LIB(pcap,pcap_init,[AC_SUBST(PCAP_LIBS,["-lpcap"])])
+    WINE_PACKAGE_FLAGS(PCAP,[libpcap],[-lpcap],,,
+        [AC_CHECK_HEADERS([pcap/pcap.h])
+         AC_CHECK_FUNC(pcap_init,[:],[PCAP_LIBS=""])])
 fi
-WINE_NOTICE_WITH(pcap,[test "x$ac_cv_lib_pcap_pcap_init" != xyes],
+WINE_NOTICE_WITH(pcap,[test "x$ac_cv_func_pcap_init" != xyes],
                  [pcap ${notice_platform}development files not found, wpcap won't be supported.],
                  [enable_wpcap])
 
 dnl **** Check for libpcsclite ****
 if test "x$with_pcsclite" != "xno"
 then
-    AC_CHECK_LIB(pcsclite,SCardEstablishContext,[AC_SUBST(PCSCLITE_LIBS,["-lpcsclite"])],
+    WINE_PACKAGE_FLAGS(PCSCLITE,[libpcsclite],[-lpcsclite],,,
+                 [AC_CHECK_FUNC(SCardEstablishContext,[:],[PCSCLITE_LIBS=""])],
                  [case $host_os in
                     darwin*) AC_SUBST(PCSCLITE_LIBS,"-framework PCSC") ;;
                   esac])
@@ -1513,7 +1525,7 @@ if test "x$with_inotify" != "xno"
 then
     WINE_PACKAGE_FLAGS(INOTIFY,[libinotify],[-linotify],,,
         [AC_CHECK_HEADERS([sys/inotify.h])
-         AC_CHECK_LIB(inotify,inotify_add_watch,[:],[INOTIFY_LIBS=""],[$INOTIFY_LIBS])])
+         AC_CHECK_FUNC(inotify_add_watch,[:],[INOTIFY_LIBS=""])])
 fi
 WINE_NOTICE_WITH(inotify,[test "$ac_cv_header_sys_inotify_h" != "yes"],
                  [libinotify ${notice_platform}development files not found (or too old), filesystem change notifications won't be supported.])
@@ -1523,7 +1535,7 @@ if test "x$with_dbus" != "xno"
 then
     WINE_PACKAGE_FLAGS(DBUS,[dbus-1],,,,
         [AC_CHECK_HEADER([dbus/dbus.h],
-            [WINE_CHECK_SONAME(dbus-1, dbus_connection_close,,[DBUS_CFLAGS=""],[$DBUS_LIBS])],
+            [WINE_CHECK_SONAME(dbus-1, dbus_connection_close,,[DBUS_CFLAGS=""])],
             [DBUS_CFLAGS=""])])
 fi
 case $host_os in
@@ -1539,9 +1551,8 @@ then
         [AC_CHECK_HEADER(gnutls/gnutls.h,
             [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gnutls/gnutls.h>
 #include <gnutls/crypto.h>]], [[static typeof(gnutls_mac_get_key_size) *func; if (func) return 0;]])],
-                [WINE_CHECK_SONAME(gnutls,gnutls_global_init,,[GNUTLS_CFLAGS=""],[$GNUTLS_LIBS],[[libgnutls\\(-deb0\\)\\{0,1\\}]])
-                 WINE_CHECK_LIB_FUNCS(gnutls_cipher_init,[$GNUTLS_LIBS],,
-                                      [WINE_NOTICE([libgnutls ${notice_platform}development files too old, bcrypt encryption won't be supported.])])])],
+                [WINE_CHECK_SONAME(gnutls,gnutls_global_init,,[GNUTLS_CFLAGS=""],,[[libgnutls\\(-deb0\\)\\{0,1\\}]])
+                 AC_CHECK_FUNC(gnutls_cipher_init,,[WINE_NOTICE([libgnutls ${notice_platform}development files too old, bcrypt encryption won't be supported.])])])],
             [GNUTLS_CFLAGS=""])])
 fi
 WINE_WARNING_WITH(gnutls,[test "x$ac_cv_lib_soname_gnutls" = "x"],
@@ -1554,12 +1565,11 @@ then
       freebsd*)
         WINE_PACKAGE_FLAGS(HWLOC,[hwloc],,,,
             [AC_CHECK_HEADER([hwloc.h],
-                [AC_CHECK_LIB(hwloc,hwloc_topology_init,
+                [AC_CHECK_FUNC(hwloc_topology_init,
                     [AC_DEFINE(HAVE_LIBHWLOC, 1, [Define to 1 if you have the 'hwloc' library (-lhwloc).])],
-                    [HWLOC_LIBS=""],
-                    [$HWLOC_LIBS])],
+                    [HWLOC_LIBS=""])],
                 [HWLOC_LIBS=""])])
-        WINE_NOTICE_WITH(hwloc,[test "$ac_cv_lib_hwloc_hwloc_topology_init" != "yes"],
+        WINE_NOTICE_WITH(hwloc,[test "$ac_cv_func_hwloc_topology_init" != "yes"],
                          [hwloc ${notice_platform}development files not found, detailed CPU info on FreeBSD won't be supported.])
         ;;
     esac
@@ -1570,9 +1580,9 @@ if test "x$with_sane" != "xno"
 then
     WINE_PACKAGE_FLAGS(SANE,[sane-backends],,[`${SANE_CONFIG:-sane-config} --cflags 2>/dev/null`],[`${SANE_CONFIG:-sane-config} --ldflags 2>/dev/null`],
         [AC_CHECK_HEADER(sane/sane.h,
-            [AC_CHECK_LIB(sane,sane_init,[:],,[$SANE_LIBS])])])
+            [AC_CHECK_FUNC(sane_init,[:])])])
 fi
-WINE_NOTICE_WITH(sane,[test "$ac_cv_lib_sane_sane_init" != "yes"],
+WINE_NOTICE_WITH(sane,[test "$ac_cv_func_sane_init" != "yes"],
                  [libsane ${notice_platform}development files not found, scanners won't be supported.],
                  [enable_sane_ds])
 
@@ -1581,10 +1591,10 @@ if test "x$with_usb" != "xno"
 then
     WINE_PACKAGE_FLAGS(USB,[libusb-1.0],[-lusb-1.0],,,
         [AC_CHECK_HEADER([libusb.h],
-            [AC_CHECK_LIB(usb-1.0,libusb_interrupt_event_handler,[:],[USB_LIBS=""],[$USB_LIBS])],
+            [AC_CHECK_FUNC(libusb_interrupt_event_handler,[:],[USB_LIBS=""])],
             [USB_LIBS=""])])
 fi
-WINE_NOTICE_WITH(usb,[test "$ac_cv_lib_usb_1_0_libusb_interrupt_event_handler" != "yes"],
+WINE_NOTICE_WITH(usb,[test "$ac_cv_func_libusb_interrupt_event_handler" != "yes"],
                  [libusb-1.0 ${notice_platform}development files not found (or too old), USB devices won't be supported.],
                  [enable_wineusb_sys])
 
@@ -1602,21 +1612,20 @@ then
     WINE_PACKAGE_FLAGS(GPHOTO2,[libgphoto2],[-lgphoto2],
                        [`${GPHOTO2_CONFIG:-gphoto2-config} --cflags 2>/dev/null`],[`${GPHOTO2_CONFIG:-gphoto2-config} --libs 2>/dev/null`],
         [AC_CHECK_HEADER(gphoto2-camera.h,
-                        [AC_CHECK_LIB(gphoto2,gp_camera_new,[:],,[$GPHOTO2_LIBS])])])
+                        [AC_CHECK_FUNC(gp_camera_new,[:])])])
     WINE_PACKAGE_FLAGS(GPHOTO2_PORT,[libgphoto2_port],[-lgphoto2_port],
                        [`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --cflags 2>/dev/null`],
                        [`${GPHOTO2_PORT_CONFIG:-gphoto2-port-config} --libs 2>/dev/null`],
         [AC_CHECK_HEADER(gphoto2-port.h,
-                        [AC_CHECK_LIB(gphoto2_port,gp_port_info_list_new,
+                        [AC_CHECK_FUNC(gp_port_info_list_new,
                                       [AC_DEFINE(HAVE_GPHOTO2_PORT, 1, [Define if we have the libgphoto2_port development environment])],
-                                      [GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS=""],
-                                      [$GPHOTO2_PORT_LIBS])],
+                                      [GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS=""])],
                         [GPHOTO2_PORT_LIBS=""; GPHOTO2_PORT_CFLAGS=""])])
 fi
-WINE_NOTICE_WITH(gphoto,[test "$ac_cv_lib_gphoto2_gp_camera_new" != "yes"],
+WINE_NOTICE_WITH(gphoto,[test "$ac_cv_func_gp_camera_new" != "yes"],
                  [libgphoto2 ${notice_platform}development files not found, digital cameras won't be supported.],
                  [enable_gphoto2_ds])
-WINE_NOTICE_WITH(gphoto,[test "$ac_cv_lib_gphoto2_port_gp_port_info_list_new" != "yes"],
+WINE_NOTICE_WITH(gphoto,[test "$ac_cv_func_gp_port_info_list_new" != "yes"],
                  [libgphoto2_port ${notice_platform}development files not found, digital cameras won't be auto-detected.])
 
 
@@ -1670,7 +1679,7 @@ then
         [AC_CHECK_HEADERS([ft2build.h])
         if test "$ac_cv_header_ft2build_h" = "yes"
         then
-            WINE_CHECK_SONAME(freetype,FT_Init_FreeType,,[FREETYPE_LIBS=""],[$FREETYPE_LIBS])
+            WINE_CHECK_SONAME(freetype,FT_Init_FreeType,,[FREETYPE_LIBS=""])
         else
             FREETYPE_CFLAGS=""
             FREETYPE_LIBS=""
@@ -1705,7 +1714,7 @@ if test "x$with_pulse" != "xno";
 then
     WINE_PACKAGE_FLAGS(PULSE,[libpulse],,,,
         [AC_CHECK_HEADER([pulse/pulseaudio.h],
-            [AC_CHECK_LIB(pulse, pa_stream_is_corked,[:],[PULSE_LIBS=""],[$PULSE_LIBS])],
+            [AC_CHECK_FUNC(pa_stream_is_corked,[:],[PULSE_LIBS=""])],
             [PULSE_LIBS=""])])
 fi
 WINE_NOTICE_WITH(pulse, [test -z "$PULSE_LIBS"],
@@ -1719,13 +1728,13 @@ then
         [AC_CHECK_HEADERS([libavutil/avutil.h libavformat/avformat.h libavcodec/avcodec.h libavcodec/bsf.h])
          if test "$ac_cv_header_libavutil_avutil_h" = "yes" -a "$ac_cv_header_libavformat_avformat_h" = "yes" -a "$ac_cv_header_libavcodec_avcodec_h" = "yes"
          then
-            AC_CHECK_LIB(avutil,av_log_set_callback,
-              [AC_CHECK_LIB(avformat,av_find_input_format,
-                [AC_CHECK_LIB(avcodec,avcodec_get_name,
+            AC_CHECK_FUNC(av_log_set_callback,
+              [AC_CHECK_FUNC(av_find_input_format,
+                [AC_CHECK_FUNC(avcodec_get_name,
                   [AC_DEFINE(HAVE_FFMPEG, 1, [Define to 1 if you have the FFmpeg libraries.])],
-                  [FFMPEG_LIBS=""],[$FFMPEG_LIBS])],
-                [FFMPEG_LIBS=""],[$FFMPEG_LIBS])],
-              [FFMPEG_LIBS=""],[$FFMPEG_LIBS])
+                  [FFMPEG_LIBS=""])],
+                [FFMPEG_LIBS=""])],
+              [FFMPEG_LIBS=""])
          else
             FFMPEG_LIBS=""
          fi])
@@ -1742,13 +1751,13 @@ then
               AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <gst/gst.h>]],
                                                  [[static int a[sizeof(gint64) > 4 ? 1 : -1]; if (a[0]) return 0;]])],
                 [AC_MSG_RESULT([yes])
-                 AC_CHECK_LIB(gstreamer-1.0,gst_pad_new,[:],,[$GSTREAMER_LIBS])],
+                 AC_CHECK_FUNC(gst_pad_new,[:])],
                 [AC_MSG_RESULT([no])
                  ac_glib2_broken=yes
                  enable_winegstreamer=${enable_winegstreamer:-no}
                  WINE_NOTICE([glib-2.0 pkgconfig configuration is for the wrong architecture, winegstreamer won't be built.])])])])
 fi
-WINE_NOTICE_WITH(gstreamer,[test "x$ac_glib2_broken" != xyes -a "x$ac_cv_lib_gstreamer_1_0_gst_pad_new" != xyes],
+WINE_NOTICE_WITH(gstreamer,[test "x$ac_glib2_broken" != xyes -a "x$ac_cv_func_gst_pad_new" != xyes],
                  [gstreamer-1.0 base plugins ${notice_platform}development files not found, GStreamer won't be supported.],
                  [enable_winegstreamer])
 
@@ -1757,7 +1766,7 @@ AC_SUBST(ALSA_LIBS,"")
 if test "x$with_alsa" != "xno"
 then
     WINE_PACKAGE_FLAGS(ALSA,[alsa],[-lasound],,,
-        [AC_CHECK_LIB(asound,snd_pcm_hw_params_get_access_mask,[:],[ALSA_LIBS=""],[$ALSA_LIBS])])
+        [AC_CHECK_FUNC(snd_pcm_hw_params_get_access_mask,[:],[ALSA_LIBS=""])])
 fi
 WINE_NOTICE_WITH(alsa,[test -z "$ALSA_LIBS"],
                  [libasound ${notice_platform}development files not found, Alsa won't be supported.],
@@ -1790,9 +1799,9 @@ if test "x$with_udev" != "xno"
 then
     WINE_PACKAGE_FLAGS(UDEV,[libudev],[-ludev],,,
         [AC_CHECK_HEADERS(libudev.h,
-            [AC_CHECK_LIB(udev,udev_new,
-                AC_DEFINE(HAVE_UDEV,1,[Define to 1 if you have the 'udev' library (-ludev).]),
-                [UDEV_LIBS=""],[$UDEV_LIBS])],
+            [AC_CHECK_FUNC(udev_new,
+                [AC_DEFINE(HAVE_UDEV,1,[Define to 1 if you have the 'udev' library (-ludev).])],
+                [UDEV_LIBS=""])],
             [UDEV_LIBS=""])])
 fi
 WINE_NOTICE_WITH(udev,[test "x$UDEV_LIBS" = "x"],
@@ -1803,7 +1812,7 @@ if test "x$with_sdl" != "xno"
 then
     WINE_PACKAGE_FLAGS(SDL2,[sdl2],[-lSDL2],,,
         [AC_CHECK_HEADERS([SDL.h],
-            [WINE_CHECK_SONAME(SDL2,SDL_Init,,,[$SDL2_LIBS],[[libSDL2-2.0*]])])])
+            [WINE_CHECK_SONAME(SDL2,SDL_Init,,,,[[libSDL2-2.0*]])])])
 fi
 WINE_NOTICE_WITH(sdl,[test "x$ac_cv_lib_soname_SDL2" = "x"],
                  [libSDL2 ${notice_platform}development files not found, SDL2 won't be supported.])
@@ -1816,10 +1825,10 @@ then
     [AC_CHECK_HEADERS([capi20.h linux/capi.h],,,[#define __user])
     if test "$ac_cv_header_capi20_h" = "yes" -a "$ac_cv_header_linux_capi_h" = "yes"
     then
-        AC_CHECK_LIB(capi20,capi20_register,[:],[CAPI20_LIBS=""],[$CAPI20_LIBS])
+        AC_CHECK_FUNC(capi20_register,[:],[CAPI20_LIBS=""])
     fi])
 fi
-WINE_NOTICE_WITH(capi,[test "x$ac_cv_lib_capi20_capi20_register" != xyes],
+WINE_NOTICE_WITH(capi,[test "x$ac_cv_func_capi20_register" != xyes],
                  [libcapi20 ${notice_platform}development files not found, ISDN won't be supported.],
                  [enable_capi2032])
 
@@ -1832,7 +1841,7 @@ then
                        [AC_CHECK_HEADERS(cups/cups.h cups/ppd.h)
                         if test "$ac_cv_header_cups_cups_h" = "yes"
                         then
-                            WINE_CHECK_SONAME(cups,cupsGetDefault,,[CUPS_LIBS=""],[$CUPS_LIBS])
+                            WINE_CHECK_SONAME(cups,cupsGetDefault,,[CUPS_LIBS=""])
                         else
                             CUPS_CFLAGS=""
                             CUPS_LIBS=""
@@ -1846,7 +1855,7 @@ if test "x$with_fontconfig" != "xno"
 then
     WINE_PACKAGE_FLAGS(FONTCONFIG,[fontconfig],,[$X_CFLAGS],[$X_LIBS],
         [AC_CHECK_HEADER([fontconfig/fontconfig.h],
-                         [WINE_CHECK_SONAME(fontconfig,FcInit,,[FONTCONFIG_CFLAGS=""],[$FONTCONFIG_LIBS])],
+                         [WINE_CHECK_SONAME(fontconfig,FcInit,,[FONTCONFIG_CFLAGS=""])],
                          [FONTCONFIG_CFLAGS=""])])
 fi
 WINE_NOTICE_WITH(fontconfig,[test "x$ac_cv_lib_soname_fontconfig" = "x"],
@@ -1861,7 +1870,7 @@ then
         [AC_CHECK_HEADERS([krb5/krb5.h])
          if test "$ac_cv_header_krb5_krb5_h" = "yes"
          then
-             WINE_CHECK_SONAME(krb5,krb5_is_config_principal,,[KRB5_CFLAGS=""],[$KRB5_LIBS])
+             WINE_CHECK_SONAME(krb5,krb5_is_config_principal,,[KRB5_CFLAGS=""])
          else
              KRB5_CFLAGS=""
          fi])
@@ -1879,7 +1888,7 @@ then
         [AC_CHECK_HEADERS([gssapi/gssapi.h gssapi/gssapi_ext.h])
         if test "$ac_cv_header_gssapi_gssapi_h" = "yes" -a "$ac_cv_header_gssapi_gssapi_ext_h" = "yes"
         then
-            WINE_CHECK_SONAME(gssapi_krb5, gss_init_sec_context,,[GSSAPI_CFLAGS=""],[$GSSAPI_LIBS])
+            WINE_CHECK_SONAME(gssapi_krb5, gss_init_sec_context,,[GSSAPI_CFLAGS=""])
         else
             GSSAPI_CFLAGS=""
         fi])
@@ -1902,7 +1911,7 @@ dnl **** Check for libnetapi ****
 if test "x$with_netapi" != "xno"
 then
     WINE_PACKAGE_FLAGS(NETAPI,[netapi],,,,
-      [WINE_CHECK_SONAME(netapi,libnetapi_init,,[AC_DEFINE_UNQUOTED(SONAME_LIBNETAPI,["libnetapi.$LIBEXT"])],[$NETAPI_LIBS])])
+      [WINE_CHECK_SONAME(netapi,libnetapi_init,,[AC_DEFINE_UNQUOTED(SONAME_LIBNETAPI,["libnetapi.$LIBEXT"])])])
 fi
 WINE_NOTICE_WITH(netapi,[test "x$ac_cv_lib_soname_netapi" = "x"],
                  [libnetapi not found, Samba NetAPI won't be supported.],
@@ -2707,6 +2716,7 @@ WINE_CONFIG_MAKEFILE(dlls/dsdmo/tests)
 WINE_CONFIG_MAKEFILE(dlls/dsound)
 WINE_CONFIG_MAKEFILE(dlls/dsound/tests)
 WINE_CONFIG_MAKEFILE(dlls/dsquery)
+WINE_CONFIG_MAKEFILE(dlls/dsrole)
 WINE_CONFIG_MAKEFILE(dlls/dssenh)
 WINE_CONFIG_MAKEFILE(dlls/dssenh/tests)
 WINE_CONFIG_MAKEFILE(dlls/dsuiext)
@@ -3129,6 +3139,7 @@ WINE_CONFIG_MAKEFILE(dlls/rsabase)
 WINE_CONFIG_MAKEFILE(dlls/rsaenh)
 WINE_CONFIG_MAKEFILE(dlls/rsaenh/tests)
 WINE_CONFIG_MAKEFILE(dlls/rstrtmgr)
+WINE_CONFIG_MAKEFILE(dlls/rtscom)
 WINE_CONFIG_MAKEFILE(dlls/rtutils)
 WINE_CONFIG_MAKEFILE(dlls/rtworkq)
 WINE_CONFIG_MAKEFILE(dlls/rtworkq/tests)
@@ -3211,6 +3222,7 @@ WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt)
 WINE_CONFIG_MAKEFILE(dlls/threadpoolwinrt/tests)
 WINE_CONFIG_MAKEFILE(dlls/thumbcache)
 WINE_CONFIG_MAKEFILE(dlls/thumbcache/tests)
+WINE_CONFIG_MAKEFILE(dlls/tiptsf)
 WINE_CONFIG_MAKEFILE(dlls/toolhelp.dll16)
 WINE_CONFIG_MAKEFILE(dlls/traffic)
 WINE_CONFIG_MAKEFILE(dlls/twain.dll16)
@@ -3517,6 +3529,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/dlls/appwiz.cpl/addons.c b/dlls/appwiz.cpl/addons.c
index 76e369c91606..f0835e90ed5a 100644
--- a/dlls/appwiz.cpl/addons.c
+++ b/dlls/appwiz.cpl/addons.c
@@ -56,10 +56,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(appwizcpl);
 #define GECKO_SHA "???"
 #endif
 
-#define MONO_VERSION "11.1.0"
+#define MONO_VERSION "11.2.0"
 #if defined(__i386__) || defined(__x86_64__)
 #define MONO_ARCH "x86"
-#define MONO_SHA "deb0341431f8260b209fff6bc79ddcc5414b97f8e9236ab9fbdca4ce59e0a9b9"
+#define MONO_SHA "b4525679e7da30d4658ceb85739cbc55c771791054abbb4b3152fe96ded0b897"
 #else
 #define MONO_ARCH ""
 #define MONO_SHA "???"
diff --git a/dlls/bcrypt/bcrypt_main.c b/dlls/bcrypt/bcrypt_main.c
index 3ca369538b29..4426e7e74b26 100644
--- a/dlls/bcrypt/bcrypt_main.c
+++ b/dlls/bcrypt/bcrypt_main.c
@@ -221,8 +221,6 @@ struct secret
     struct object hdr;
     UCHAR        *derived_key;
     ULONG         derived_key_len;
-    struct key   *privkey;
-    struct key   *pubkey;
 };
 
 void * SYMCRYPT_CALL SymCryptCallbackAlloc( SIZE_T size )
@@ -1676,7 +1674,8 @@ static NTSTATUS decrypt_aes_ecb( const struct key *key, const UCHAR *input, ULON
 }
 
 static NTSTATUS decrypt_aes_gcm( struct key *key, const UCHAR *input, ULONG input_len,
-                                 const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *info, UCHAR *output )
+                                 const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *info, UCHAR *output, ULONG output_len,
+                                 ULONG *ret_len )
 {
     SYMCRYPT_ERROR error;
 
@@ -1684,6 +1683,9 @@ static NTSTATUS decrypt_aes_gcm( struct key *key, const UCHAR *input, ULONG inpu
         return STATUS_INVALID_PARAMETER;
     if (info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG) FIXME( "call chaining not implemented\n" );
 
+    if (!output) return STATUS_SUCCESS;
+    if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
+
     EnterCriticalSection( &key->s.cs );
 
     SymCryptGcmInit( &key->s.gcm.state, &key->s.gcm.handle, info->pbNonce, info->cbNonce );
@@ -1774,7 +1776,7 @@ static NTSTATUS decrypt_symmetric( struct key *key, const UCHAR *input, ULONG in
             return decrypt_aes_ecb( key, input, input_len, output, output_len, ret_len, flags );
 
         case CHAIN_MODE_GCM:
-            return decrypt_aes_gcm( key, input, input_len, info, output );
+            return decrypt_aes_gcm( key, input, input_len, info, output, output_len, ret_len );
 
         default:
             if (iv && iv_len != key->s.block_size) return STATUS_INVALID_PARAMETER;
@@ -2031,13 +2033,15 @@ static NTSTATUS encrypt_aes_ecb( const struct key *key, const UCHAR *input, ULON
 }
 
 static NTSTATUS encrypt_aes_gcm( struct key *key, const UCHAR *input, ULONG input_len,
-                                 const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *info, UCHAR *output )
+                                 const BCRYPT_AUTHENTICATED_CIPHER_MODE_INFO *info, UCHAR *output, ULONG output_len,
+                                 ULONG *ret_len )
 {
     if (!info || !info->pbNonce || !info->pbTag || info->cbTag < 12 || info->cbTag > 16)
         return STATUS_INVALID_PARAMETER;
     if (info->dwFlags & BCRYPT_AUTH_MODE_CHAIN_CALLS_FLAG) FIXME( "call chaining not implemented\n" );
 
     if (input && !input_len) return STATUS_SUCCESS;
+    if (output_len < *ret_len) return STATUS_BUFFER_TOO_SMALL;
 
     EnterCriticalSection( &key->s.cs );
 
@@ -2116,7 +2120,7 @@ static NTSTATUS encrypt_symmetric( struct key *key, const UCHAR *input, ULONG in
             return encrypt_aes_ecb( key, input, input_len, output, output_len, ret_len, flags );
 
         case CHAIN_MODE_GCM:
-            return encrypt_aes_gcm( key, input, input_len, info, output );
+            return encrypt_aes_gcm( key, input, input_len, info, output, output_len, ret_len );
 
         default:
             if (iv && iv_len != key->s.block_size) return STATUS_INVALID_PARAMETER;
@@ -2664,6 +2668,8 @@ static NTSTATUS import_rsa_key( enum alg_id alg, const UCHAR *input, ULONG input
     else if (blob->Magic != BCRYPT_RSAPUBLIC_MAGIC) return STATUS_NOT_SUPPORTED;
 
     if (blob->cbPublicExp > sizeof(exp64)) return NTE_BAD_DATA;
+    for (i = 0; i < blob->cbPublicExp; i++) exp64 += exp[i] << ((blob->cbPublicExp - i - 1) * 8);
+    if (exp64 == 1) return STATUS_INVALID_PARAMETER;
 
     size = sizeof(*blob) + blob->cbPublicExp + blob->cbModulus;
     if (key_flags & KEY_FLAG_PRIVATE) size += blob->cbPrime1 + blob->cbPrime2;
@@ -2680,7 +2686,6 @@ static NTSTATUS import_rsa_key( enum alg_id alg, const UCHAR *input, ULONG input
     else if (alg == ALG_ID_RSA_SIGN) set_flags |= SYMCRYPT_FLAG_RSAKEY_SIGN;
 
     mod = exp + blob->cbPublicExp;
-    for (i = 0; i < blob->cbPublicExp; i++) exp64 += exp[i] << ((blob->cbPublicExp - i - 1) * 8);
 
     if (key_flags & KEY_FLAG_PRIVATE)
     {
@@ -2729,7 +2734,7 @@ static NTSTATUS import_legacy_rsa_key( enum alg_id alg, const UCHAR *input, ULON
     key_size = len_from_bitlen( rsakey->bitlen );
     size += key_size;
     if (key_flags & KEY_FLAG_PRIVATE) size += key_size; /* prime1 + prime2 */
-    if (input_len < size) return STATUS_INVALID_PARAMETER;
+    if (input_len < size || rsakey->pubexp == 1) return STATUS_INVALID_PARAMETER;
 
     if ((status = alloc_key( alg, key_flags, &key )) || (status = alloc_rsa_key( key, rsakey->bitlen )))
     {
diff --git a/dlls/bcrypt/tests/bcrypt.c b/dlls/bcrypt/tests/bcrypt.c
index e7905f321458..75d9c3e166bd 100644
--- a/dlls/bcrypt/tests/bcrypt.c
+++ b/dlls/bcrypt/tests/bcrypt.c
@@ -1316,6 +1316,9 @@ static void test_BCryptEncrypt(void)
         ok(tag[i] == expected_tag[i], "%lu: %02x != %02x\n", i, tag[i], expected_tag[i]);
     ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv data.\n");
 
+    ret = BCryptEncrypt(key, data2, 32, &auth_info, ivbuf, 16, ciphertext, 31, &size, 0);
+    ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret);
+
     /* NULL initialization vector */
     size = 0;
     memset(ciphertext, 0xff, sizeof(ciphertext));
@@ -1916,6 +1919,16 @@ static void test_BCryptDecrypt(void)
     ok(!memcmp(plaintext, expected3, sizeof(expected3)), "wrong data\n");
     ok(!memcmp(ivbuf, iv, sizeof(iv)), "wrong iv.\n");
 
+    size = 0;
+    ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, NULL, 0, &size, 0);
+    ok(ret == STATUS_SUCCESS, "got %#lx\n", ret);
+    ok(size == 32, "got %lu\n", size);
+
+    size = 0;
+    ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, ivbuf, 16, plaintext, 31, &size, 0);
+    ok(ret == STATUS_BUFFER_TOO_SMALL, "got %#lx\n", ret);
+    ok(size == 32, "got %lu\n", size);
+
     size = 0;
     memset(plaintext, 0, sizeof(plaintext));
     ret = BCryptDecrypt(key, ciphertext4, 32, &auth_info, NULL, 0, plaintext, 32, &size, 0);
@@ -2900,6 +2913,31 @@ static void test_rsa_encrypt(void)
     }
 }
 
+/* legacy RSA key with public exponent 1 */
+static UCHAR legacy_rsa_key[] =
+{
+    0x07, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0xab, 0xef, 0xfa, 0xc6, 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92,
+    0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a,
+    0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78,
+    0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20,
+    0xf5, 0xf5, 0xf5, 0xc1, 0xed, 0x5c, 0x91, 0x36, 0x75, 0xb0, 0xa9, 0x9c, 0x04, 0xdb, 0x0c, 0x8c,
+    0xbf, 0x99, 0x75, 0x13, 0x7e, 0x87, 0x80, 0x4b, 0x71, 0x94, 0xb8, 0x00, 0xa0, 0x7d, 0xb7, 0x53,
+    0xdd, 0x20, 0x63, 0xee, 0xf7, 0x83, 0x41, 0xfe, 0x16, 0xa7, 0x6e, 0xdf, 0x21, 0x7d, 0x76, 0xc0,
+    0x85, 0xd5, 0x65, 0x7f, 0x00, 0x23, 0x57, 0x45, 0x52, 0x02, 0x9d, 0xea, 0x69, 0xac, 0x1f, 0xfd,
+    0x3f, 0x8c, 0x4a, 0xd0, 0x01, 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, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 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, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x64, 0xd5, 0xaa, 0xb1, 0xa6, 0x03, 0x18, 0x92, 0x03, 0xaa, 0x31, 0x2e,
+    0x48, 0x4b, 0x65, 0x20, 0x99, 0xcd, 0xc6, 0x0c, 0x15, 0x0c, 0xbf, 0x3e, 0xff, 0x78, 0x95, 0x67,
+    0xb2, 0x74, 0x5b, 0x60, 0x01, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+};
+
 static void test_RSA(void)
 {
     static UCHAR hash[] =
@@ -3134,6 +3172,9 @@ static void test_RSA(void)
     free(buf);
     BCryptDestroyKey(key);
 
+    ret = BCryptImportKeyPair(alg, NULL, LEGACY_RSAPRIVATE_BLOB, &key, legacy_rsa_key, sizeof(legacy_rsa_key), 0);
+    ok(ret == STATUS_INVALID_PARAMETER, "got %#lx\n", ret);
+
     ret = BCryptCloseAlgorithmProvider(alg, 0);
     ok(!ret, "got %#lx\n", ret);
 }
diff --git a/dlls/colorcnv/Makefile.in b/dlls/colorcnv/Makefile.in
index 1798af91c9ba..1873b0346fd0 100644
--- a/dlls/colorcnv/Makefile.in
+++ b/dlls/colorcnv/Makefile.in
@@ -1,6 +1,8 @@
 MODULE    = colorcnv.dll
-IMPORTS   = combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid
+IMPORTS   = $(FFMPEG_PE_LIBS) combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid
+EXTRAINCL = $(FFMPEG_PE_CFLAGS)
 
 SOURCES = \
+	color_converter.c \
 	colorcnv.c \
 	colorcnv.idl
diff --git a/dlls/colorcnv/color_converter.c b/dlls/colorcnv/color_converter.c
new file mode 100644
index 000000000000..1d5f48e615e7
--- /dev/null
+++ b/dlls/colorcnv/color_converter.c
@@ -0,0 +1,1505 @@
+/* Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+
+#include "d3d9types.h"
+#include "dmoreg.h"
+#include "dmort.h"
+#include "dshow.h"
+#include "dvdmedia.h"
+#include "mediaerr.h"
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
+#include "wmcodecdsp.h"
+
+#include <libavutil/avutil.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/opt.h>
+#include <libswscale/swscale.h>
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dmo);
+
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8);
+DEFINE_GUID(DMOVideoFormat_RGB32,D3DFMT_X8R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+DEFINE_GUID(DMOVideoFormat_RGB24,D3DFMT_R8G8B8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
+
+static const AVRational USER_TIME_BASE_Q = {1, 10000000};
+
+static const char *debugstr_avtime(INT64 time, AVRational time_base)
+{
+    time = av_rescale_q_rnd(time, time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX);
+    if (time == AV_NOPTS_VALUE)
+        return "(none)";
+    return wine_dbg_sprintf("%I64d", time);
+}
+
+static const char *debugstr_avframe(AVFrame *frame)
+{
+    return wine_dbg_sprintf("fmt %s %dx%d stride %d", av_get_pix_fmt_name(frame->format),
+            frame->width, frame->height, frame->linesize[0]);
+}
+
+static enum AVPixelFormat pixel_format_from_video_subtype(const GUID *subtype)
+{
+    switch (subtype->Data1)
+    {
+    /* MEDIASUBTYPE_AYUV */   case MAKEFOURCC('A','Y','U','V'): return AV_PIX_FMT_AYUV;
+    /* MEDIASUBTYPE_I420 */   case MAKEFOURCC('I','4','2','0'): return AV_PIX_FMT_YUV420P;
+    /* MEDIASUBTYPE_IYUV */   case MAKEFOURCC('I','Y','U','V'): return AV_PIX_FMT_YUV420P;
+    /* MEDIASUBTYPE_NV11 */   case MAKEFOURCC('N','V','1','1'): return AV_PIX_FMT_YUV411P;
+    /* MEDIASUBTYPE_NV12 */   case MAKEFOURCC('N','V','1','2'): return AV_PIX_FMT_NV12;
+    /* MEDIASUBTYPE_UYVY */   case MAKEFOURCC('U','Y','V','Y'): return AV_PIX_FMT_UYVY422;
+    /* MEDIASUBTYPE_V216 */   case MAKEFOURCC('V','2','1','6'): break;
+    /* MEDIASUBTYPE_V410 */   case MAKEFOURCC('V','4','1','0'): break;
+    /* MEDIASUBTYPE_Y41P */   case MAKEFOURCC('Y','4','1','P'): break;
+    /* MEDIASUBTYPE_Y41T */   case MAKEFOURCC('Y','4','1','T'): break;
+    /* MEDIASUBTYPE_Y42T */   case MAKEFOURCC('Y','4','2','T'): break;
+    /* MEDIASUBTYPE_YUY2 */   case MAKEFOURCC('Y','U','Y','2'): return AV_PIX_FMT_YUYV422;
+    /* MEDIASUBTYPE_YV12 */   case MAKEFOURCC('Y','V','1','2'): return AV_PIX_FMT_YUV420P;
+    /* MEDIASUBTYPE_YVU9 */   case MAKEFOURCC('Y','V','U','9'): break;
+    /* MEDIASUBTYPE_YVYU */   case MAKEFOURCC('Y','V','Y','U'): return AV_PIX_FMT_YVYU422;
+    /* MEDIASUBTYPE_RGB24 */  case 0xe436eb7d:                  return AV_PIX_FMT_BGR24;
+    /* MEDIASUBTYPE_RGB32 */  case 0xe436eb7e:                  return AV_PIX_FMT_BGR0;
+    /* MEDIASUBTYPE_RGB555 */ case 0xe436eb7c:                  return AV_PIX_FMT_RGB555;
+    /* MEDIASUBTYPE_RGB565 */ case 0xe436eb7b:                  return AV_PIX_FMT_RGB565;
+    /* MEDIASUBTYPE_RGB8 */   case 0xe436eb7a:                  return AV_PIX_FMT_RGB8;
+    }
+
+    FIXME("Unsupported subtype %s (%s)\n", debugstr_guid(subtype), debugstr_fourcc(subtype->Data1));
+    return AV_PIX_FMT_NONE;
+}
+
+static void video_frame_init_aperture(AVFrame *frame, const MFVIDEOFORMAT *format)
+{
+    /* unlike the video processor, color converter doesn't really support aperture */
+    frame->width = format->videoInfo.dwWidth;
+    frame->height = format->videoInfo.dwHeight;
+}
+
+static void media_buffer_release(void *opaque, uint8_t *data)
+{
+    IMediaBuffer *media_buffer = opaque;
+    IMF2DBuffer2 *buffer2;
+
+    if (SUCCEEDED(IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2)))
+    {
+        IMF2DBuffer2_Unlock2D(buffer2);
+        IMF2DBuffer2_Release(buffer2);
+    }
+    IMediaBuffer_Release(media_buffer);
+}
+
+static AVBufferRef *buffer_from_media_buffer(IMediaBuffer *media_buffer, int flags, LONG *pitch)
+{
+    BYTE *data, *scanline0;
+    IMF2DBuffer2 *buffer2;
+    AVBufferRef *buffer;
+    HRESULT hr;
+    DWORD size;
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2)))
+    {
+        MF2DBuffer_LockFlags lock_flags = (flags & AV_BUFFER_FLAG_READONLY) ? MF2DBuffer_LockFlags_Read
+                : MF2DBuffer_LockFlags_Write;
+        hr = IMF2DBuffer2_Lock2DSize(buffer2, lock_flags, &scanline0, pitch, &data, &size);
+        IMF2DBuffer2_Release(buffer2);
+    }
+    if (FAILED(hr))
+    {
+        if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &data, &size)))
+            return NULL;
+        if (!flags && FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &size)))
+            return NULL;
+        *pitch = 0;
+    }
+
+    if (!(buffer = av_buffer_create(data, size, media_buffer_release, media_buffer, flags)))
+        return NULL;
+    IMediaBuffer_AddRef(media_buffer);
+    return buffer;
+}
+
+static void video_frame_init_from_format(AVFrame *frame, const MFVIDEOFORMAT *format)
+{
+    frame->format = pixel_format_from_video_subtype(&format->guidFormat);
+    frame->width = format->videoInfo.dwWidth;
+    frame->height = format->videoInfo.dwHeight;
+    frame->color_range = AVCOL_RANGE_UNSPECIFIED;
+    frame->color_primaries = AVCOL_PRI_UNSPECIFIED;
+    frame->color_trc = AVCOL_TRC_UNSPECIFIED;
+    frame->colorspace = AVCOL_SPC_UNSPECIFIED;
+    frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
+}
+
+static int fill_arrays_with_format(uint8_t *planes[4], int strides[4], AVBufferRef *buffer,
+        const MFVIDEOFORMAT *format, LONG pitch)
+{
+    enum AVPixelFormat pix_fmt = pixel_format_from_video_subtype(&format->guidFormat);
+    UINT width = format->videoInfo.dwWidth, height = format->videoInfo.dwHeight;
+    int size;
+
+    size = av_image_fill_arrays(planes, strides, buffer->data, pix_fmt, width, height, 1);
+    TRACE("buffer %p / %#Ix size %d pitch %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size,
+            size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]);
+    if (size > buffer->size)
+    {
+        ERR("stride %lu linesize %u,%u,%u,%u size %#x buffer %#Ix\n", pitch, strides[0], strides[1],
+                strides[2], strides[3], size, buffer->size);
+        return -1;
+    }
+
+    if (pitch && abs(pitch) != strides[0])
+    {
+        int new_strides[4] = {0};
+        for (int i = 0; i < 4; i++) new_strides[i] = (abs(pitch) * strides[i]) / strides[0];
+        for (int i = 1; i < 4 && planes[i]; i++)
+        {
+            size_t height = (planes[i] - planes[i - 1]) / strides[i - 1];
+            planes[i] = planes[i - 1] + height * new_strides[i - 1];
+        }
+        memcpy(strides, new_strides, sizeof(new_strides));
+    }
+
+    /* unlike the video processor, color converter doesn't care about 2D buffer pitch */
+    if (format->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep)
+    {
+        planes[0] = planes[0] + strides[0] * (height - 1);
+        strides[0] = -strides[0];
+    }
+
+    TRACE("buffer %p / %#Ix size %d stride %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size,
+            size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]);
+    return size;
+}
+
+static BOOL check_arrays_alignment(uint8_t *planes[4], int strides[4], int size, int align)
+{
+    if (size % align)
+        return FALSE;
+    for (int i = 0; i < 4; i++)
+        if ((UINT_PTR)planes[i] % align)
+            return FALSE;
+    for (int i = 0; i < 4; i++)
+        if (strides[i] % align)
+            return FALSE;
+    return TRUE;
+}
+
+static BOOL video_frame_wrap_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, LONG pitch)
+{
+    int size;
+
+    TRACE("frame %p, info %p, buffer %p\n", frame, format, buffer);
+
+    video_frame_init_from_format(frame, format);
+    video_frame_init_aperture(frame, format);
+
+    if ((size = fill_arrays_with_format(frame->data, frame->linesize, buffer, format, pitch)) < 0)
+        return size;
+    /* swscale requires 16byte alignment for data pointers when SSE2 optimizations are used. */
+    if (!check_arrays_alignment(frame->data, frame->linesize, size, 16))
+    {
+        ERR("frame %s isn't aligned to 16 bytes\n", debugstr_avframe(frame));
+        return -1;
+    }
+
+    frame->opaque = (void *)-1;
+    frame->buf[0] = av_buffer_ref(buffer);
+    frame->extended_data = frame->data;
+    return size;
+}
+
+static int video_frame_copy_from_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer,
+        LONG pitch)
+{
+    int size, input_strides[4];
+    UINT8 *input_planes[4];
+
+    ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer);
+
+    size = fill_arrays_with_format(input_planes, input_strides, buffer, format, pitch);
+    av_image_copy(frame->data, frame->linesize, (const UINT8 **)input_planes, input_strides,
+            frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight);
+    return size;
+}
+
+static int video_frame_copy_to_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer,
+        LONG pitch)
+{
+    int size, output_strides[4];
+    UINT8 *output_planes[4];
+
+    ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer);
+
+    size = fill_arrays_with_format(output_planes, output_strides, buffer, format, pitch);
+    av_image_copy(output_planes, output_strides, (const UINT8 **)frame->data, frame->linesize,
+            frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight);
+    return size;
+}
+
+static const GUID *const input_types[] =
+{
+    &MEDIASUBTYPE_YV12,
+    &MEDIASUBTYPE_YUY2,
+    &MEDIASUBTYPE_UYVY,
+    &MEDIASUBTYPE_AYUV,
+    &MEDIASUBTYPE_NV12,
+    &MEDIASUBTYPE_RGB32,
+    &MEDIASUBTYPE_RGB565,
+    &MEDIASUBTYPE_I420,
+    &MEDIASUBTYPE_IYUV,
+    &MEDIASUBTYPE_YVYU,
+    &MEDIASUBTYPE_RGB24,
+    &MEDIASUBTYPE_RGB555,
+    &MEDIASUBTYPE_RGB8,
+    &MEDIASUBTYPE_V216,
+    &MEDIASUBTYPE_V410,
+    &MEDIASUBTYPE_NV11,
+    &MEDIASUBTYPE_Y41P,
+    &MEDIASUBTYPE_Y41T,
+    &MEDIASUBTYPE_Y42T,
+    &MEDIASUBTYPE_YVU9,
+};
+static const GUID *const output_types[] =
+{
+    &MEDIASUBTYPE_YV12,
+    &MEDIASUBTYPE_YUY2,
+    &MEDIASUBTYPE_UYVY,
+    &MEDIASUBTYPE_AYUV,
+    &MEDIASUBTYPE_NV12,
+    &MEDIASUBTYPE_RGB32,
+    &MEDIASUBTYPE_RGB565,
+    &MEDIASUBTYPE_I420,
+    &MEDIASUBTYPE_IYUV,
+    &MEDIASUBTYPE_YVYU,
+    &MEDIASUBTYPE_RGB24,
+    &MEDIASUBTYPE_RGB555,
+    &MEDIASUBTYPE_RGB8,
+    &MEDIASUBTYPE_V216,
+    &MEDIASUBTYPE_V410,
+    &MEDIASUBTYPE_NV11,
+};
+
+struct color_convert
+{
+    IUnknown IUnknown_inner;
+    IMFTransform IMFTransform_iface;
+    IMediaObject IMediaObject_iface;
+    IPropertyBag IPropertyBag_iface;
+    IPropertyStore IPropertyStore_iface;
+    IUnknown *outer;
+    LONG refcount;
+
+    DMO_MEDIA_TYPE input_type;
+    MFVIDEOFORMAT input_format;
+    MFT_INPUT_STREAM_INFO input_info;
+    DMO_MEDIA_TYPE output_type;
+    MFVIDEOFORMAT output_format;
+    MFT_OUTPUT_STREAM_INFO output_info;
+
+    SwsContext *context;
+    AVFrame input_frame;
+    AVFrame output_frame;
+    AVFrame current_frame;
+};
+
+static HRESULT color_convert_process_frame(struct color_convert *impl, AVFrame *input_frame,
+        DMO_OUTPUT_DATA_BUFFER *output)
+{
+    AVFrame output_frame = {0};
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    int size, ret;
+    HRESULT hr;
+    LONG pitch;
+
+    if (!(buffer = buffer_from_media_buffer(output->pBuffer, 0, &pitch)))
+        return E_OUTOFMEMORY;
+    if ((size = video_frame_wrap_buffer(&output_frame, &impl->output_format, buffer, pitch)) < 0)
+        av_frame_move_ref(&output_frame, &impl->output_frame);
+
+    TRACE("input %s output %s\n", debugstr_avframe(input_frame), debugstr_avframe(&output_frame));
+
+    if ((ret = sws_scale_frame(impl->context, &output_frame, input_frame)) < 0)
+        ERR("error ret %d (%s)\n", -ret, av_err2str(ret));
+    else if ((ret = size) < 0)
+        ret = video_frame_copy_to_buffer(&output_frame, &impl->output_format, buffer, pitch);
+
+    av_buffer_unref(&buffer);
+
+    if (!output_frame.opaque)
+        av_frame_move_ref(&impl->output_frame, &output_frame);
+    else
+        av_frame_unref(&output_frame);
+
+    output->dwStatus = 0;
+    IMediaBuffer_SetLength(output->pBuffer, ret >= 0 ? ret : 0);
+    if (ret < 0)
+        return E_FAIL;
+    if (!ret)
+        return S_FALSE;
+
+    if (input_frame->flags & AV_FRAME_FLAG_KEY)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
+    output->rtTimestamp = input_frame->pts;
+    if (output->rtTimestamp != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME;
+    output->rtTimelength = input_frame->duration;
+    if (output->rtTimelength != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(output->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (output->rtTimestamp != INT64_MIN)
+            IMFSample_SetSampleTime(sample, output->rtTimestamp);
+        if (output->rtTimelength != INT64_MIN)
+            IMFSample_SetSampleDuration(sample, output->rtTimelength);
+        if (output->dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT)
+            IMFSample_SetUINT32(sample, &MFSampleExtension_CleanPoint, 1);
+        IMFSample_Release(sample);
+    }
+
+    TRACE("returning output size %#x, pts %s, duration %s status %#lx\n", ret,
+            debugstr_avtime(output->rtTimestamp, USER_TIME_BASE_Q),
+            debugstr_avtime(output->rtTimelength, USER_TIME_BASE_Q), output->dwStatus);
+    return S_OK;
+}
+
+static HRESULT color_convert_process_input(struct color_convert *impl, const DMO_OUTPUT_DATA_BUFFER *input)
+{
+    LONGLONG pts = input->rtTimestamp, duration = input->rtTimelength;
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    HRESULT hr;
+    LONG pitch;
+    int ret;
+
+    if (!impl->context)
+        return DMO_E_TYPE_NOT_SET;
+    if (impl->current_frame.width)
+        return DMO_E_NOTACCEPTING;
+
+    if (!(buffer = buffer_from_media_buffer(input->pBuffer, AV_BUFFER_FLAG_READONLY, &pitch)))
+        return E_OUTOFMEMORY;
+    if ((ret = video_frame_wrap_buffer(&impl->current_frame, &impl->input_format, buffer, pitch)) < 0)
+    {
+        ret = video_frame_copy_from_buffer(&impl->input_frame, &impl->input_format, buffer, pitch);
+        av_frame_move_ref(&impl->current_frame, &impl->input_frame);
+    }
+    av_buffer_unref(&buffer);
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(input->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (FAILED(IMFSample_GetSampleTime(sample, &pts)))
+            pts = INT64_MIN;
+        if (FAILED(IMFSample_GetSampleDuration(sample, &duration)))
+            duration = INT64_MIN;
+        IMFSample_Release(sample);
+    }
+
+    impl->current_frame.pts = pts;
+    impl->current_frame.duration = duration;
+    TRACE("input frame size %ux%u, time %s, duration %s\n", impl->current_frame.width,
+            impl->current_frame.height, debugstr_avtime(impl->current_frame.pts, USER_TIME_BASE_Q),
+            debugstr_avtime(impl->current_frame.duration, USER_TIME_BASE_Q));
+    return S_OK;
+}
+
+static HRESULT color_convert_process_output(struct color_convert *impl, DMO_OUTPUT_DATA_BUFFER *output)
+{
+    HRESULT hr;
+
+    if (!impl->context)
+        return DMO_E_TYPE_NOT_SET;
+    if (!impl->current_frame.width)
+        return S_FALSE;
+
+    hr = color_convert_process_frame(impl, &impl->current_frame, output);
+    if (!impl->current_frame.opaque)
+        av_frame_move_ref(&impl->input_frame, &impl->current_frame);
+    else
+        av_frame_unref(&impl->current_frame);
+
+    return hr;
+}
+
+static void color_convert_cleanup(struct color_convert *impl)
+{
+    memset(&impl->input_format, 0, sizeof(impl->input_format));
+    memset(&impl->output_format, 0, sizeof(impl->output_format));
+    av_frame_unref(&impl->current_frame);
+    av_frame_unref(&impl->output_frame);
+    av_frame_unref(&impl->input_frame);
+    sws_free_context(&impl->context);
+}
+
+static BOOL get_default_stride_sign(const BITMAPINFOHEADER *header)
+{
+    return header->biCompression == BI_RGB || header->biCompression == BI_BITFIELDS ? -1 : 1;
+}
+
+static const GUID *get_dmo_subtype(const GUID *subtype)
+{
+    if (IsEqualGUID(subtype, &MFVideoFormat_RGB8))
+        return &MEDIASUBTYPE_RGB8;
+    if (IsEqualGUID(subtype, &MFVideoFormat_RGB555))
+        return &MEDIASUBTYPE_RGB555;
+    if (IsEqualGUID(subtype, &MFVideoFormat_RGB565))
+        return &MEDIASUBTYPE_RGB565;
+    if (IsEqualGUID(subtype, &MFVideoFormat_RGB24))
+        return &MEDIASUBTYPE_RGB24;
+    if (IsEqualGUID(subtype, &MFVideoFormat_RGB32))
+        return &MEDIASUBTYPE_RGB32;
+    return subtype;
+}
+
+static HRESULT init_video_format(const DMO_MEDIA_TYPE *type, MFVIDEOFORMAT *format)
+{
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo))
+    {
+        const VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)type->pbFormat;
+        memset(format, 0, sizeof(*format));
+        format->videoInfo.dwWidth = vih->bmiHeader.biWidth;
+        format->videoInfo.dwHeight = abs(vih->bmiHeader.biHeight);
+        if (get_default_stride_sign(&vih->bmiHeader) < 0 && vih->bmiHeader.biHeight > 0)
+            format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
+        format->guidFormat = type->subtype;
+        return S_OK;
+    }
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2))
+    {
+        const VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2 *)type->pbFormat;
+        memset(format, 0, sizeof(*format));
+        format->videoInfo.dwWidth = vih->bmiHeader.biWidth;
+        format->videoInfo.dwHeight = abs(vih->bmiHeader.biHeight);
+        if (get_default_stride_sign(&vih->bmiHeader) < 0 && vih->bmiHeader.biHeight > 0)
+            format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
+        format->guidFormat = type->subtype;
+        return S_OK;
+    }
+    if (IsEqualGUID(&type->formattype, &FORMAT_MFVideoFormat))
+    {
+        *format = *(MFVIDEOFORMAT *)type->pbFormat;
+        /* normalize subtype with other formats for pixel_format_from_video_subtype */
+        format->guidFormat = *get_dmo_subtype(&format->guidFormat);
+        return S_OK;
+    }
+
+    FIXME("Format %s not implemented\n", debugstr_guid(&type->formattype));
+    return E_NOTIMPL;
+}
+
+static HRESULT color_convert_init(struct color_convert *impl)
+{
+    HRESULT hr;
+    int ret;
+
+    color_convert_cleanup(impl);
+
+    if (!(impl->context = sws_alloc_context()))
+        return E_OUTOFMEMORY;
+    if (FAILED(hr = init_video_format(&impl->input_type, &impl->input_format))
+            || FAILED(hr = init_video_format(&impl->output_type, &impl->output_format)))
+    {
+        color_convert_cleanup(impl);
+        return hr;
+    }
+
+    video_frame_init_from_format(&impl->input_frame, &impl->input_format);
+    if ((ret = av_frame_get_buffer(&impl->input_frame, 0)) < 0)
+        goto failed;
+    video_frame_init_aperture(&impl->input_frame, &impl->input_format);
+
+    video_frame_init_from_format(&impl->output_frame, &impl->output_format);
+    if ((ret = av_frame_get_buffer(&impl->output_frame, 0)) < 0)
+        goto failed;
+    video_frame_init_aperture(&impl->output_frame, &impl->output_format);
+
+    av_opt_set(impl->context, "sws_flags", "neighbor", 0);
+    av_opt_set_int(impl->context, "threads", 0, 0);
+    av_opt_set_int(impl->context, "srcw", impl->input_frame.width, 0);
+    av_opt_set_int(impl->context, "srch", impl->input_frame.height, 0);
+    av_opt_set_pixel_fmt(impl->context, "src_format", impl->input_frame.format, 0);
+    av_opt_set_int(impl->context, "dstw", impl->output_frame.width, 0);
+    av_opt_set_int(impl->context, "dsth", impl->output_frame.height, 0);
+    av_opt_set_pixel_fmt(impl->context, "dst_format", impl->output_frame.format, 0);
+
+    if ((ret = sws_init_context(impl->context, NULL, NULL)) < 0)
+        goto failed;
+
+    TRACE("input %s -> output %s\n", debugstr_avframe(&impl->input_frame), debugstr_avframe(&impl->output_frame));
+    return S_OK;
+
+failed:
+    ERR("ret %d\n", ret);
+    color_convert_cleanup(impl);
+    return E_FAIL;
+}
+
+static struct color_convert *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct color_convert, IUnknown_inner);
+}
+
+static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+    struct color_convert *impl = impl_from_IUnknown(iface);
+
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown))
+        *out = &impl->IUnknown_inner;
+    else if (IsEqualGUID(iid, &IID_IMFTransform))
+        *out = &impl->IMFTransform_iface;
+    else if (IsEqualGUID(iid, &IID_IMediaObject))
+        *out = &impl->IMediaObject_iface;
+    else if (IsEqualIID(iid, &IID_IPropertyBag))
+        *out = &impl->IPropertyBag_iface;
+    else if (IsEqualIID(iid, &IID_IPropertyStore))
+        *out = &impl->IPropertyStore_iface;
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI unknown_AddRef(IUnknown *iface)
+{
+    struct color_convert *impl = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&impl->refcount);
+
+    TRACE("iface %p increasing refcount to %lu.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI unknown_Release(IUnknown *iface)
+{
+    struct color_convert *impl = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&impl->refcount);
+
+    TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        color_convert_cleanup(impl);
+        free(impl);
+    }
+
+    return refcount;
+}
+
+static const IUnknownVtbl unknown_vtbl =
+{
+    unknown_QueryInterface,
+    unknown_AddRef,
+    unknown_Release,
+};
+
+static HRESULT MF_RESULT_FROM_DMO(HRESULT hr)
+{
+    switch (hr)
+    {
+    case DMO_E_INVALIDSTREAMINDEX: return MF_E_INVALIDSTREAMNUMBER;
+    case DMO_E_INVALIDTYPE: return MF_E_INVALIDMEDIATYPE;
+    case DMO_E_TYPE_NOT_SET: return MF_E_TRANSFORM_TYPE_NOT_SET;
+    case DMO_E_NOTACCEPTING: return MF_E_NOTACCEPTING;
+    case DMO_E_TYPE_NOT_ACCEPTED: return MF_E_INVALIDMEDIATYPE;
+    case DMO_E_NO_MORE_ITEMS: return MF_E_NO_MORE_TYPES;
+    case S_FALSE: return MF_E_TRANSFORM_NEED_MORE_INPUT;
+    }
+
+    return hr;
+}
+
+static struct color_convert *impl_from_IMFTransform(IMFTransform *iface)
+{
+    return CONTAINING_RECORD(iface, struct color_convert, IMFTransform_iface);
+}
+
+static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI transform_AddRef(IMFTransform *iface)
+{
+    return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer);
+}
+
+static ULONG WINAPI transform_Release(IMFTransform *iface)
+{
+    return IUnknown_Release(impl_from_IMFTransform(iface)->outer);
+}
+
+static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
+        DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
+{
+    TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
+            iface, input_minimum, input_maximum, output_minimum, output_maximum);
+    *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+    TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
+    *inputs = *outputs = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+        DWORD output_size, DWORD *outputs)
+{
+    TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
+            input_size, inputs, output_size, outputs);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
+
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+    {
+        memset(info, 0, sizeof(*info));
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    }
+
+    *info = impl->input_info;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
+
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+    {
+        memset(info, 0, sizeof(*info));
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    }
+
+    *info = impl->output_info;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+    TRACE("iface %p, attributes %p.\n", iface, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
+{
+    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
+{
+    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+    TRACE("iface %p, id %#lx.\n", iface, id);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+    TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
+    return E_NOTIMPL;
+}
+
+/* some exotic YUV formats aren't supported by MFCreateMediaTypeFromRepresentation, fill missing attributes */
+static HRESULT create_media_type_from_dmo(DMO_MEDIA_TYPE *mt, IMFMediaType **type)
+{
+    HRESULT hr;
+
+    if (FAILED(hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, mt, type)))
+        return hr;
+    if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_RGB8))
+        IMFMediaType_SetGUID(*type, &MF_MT_SUBTYPE, &mt->subtype);
+    IMFMediaType_SetUINT32(*type, &MF_MT_FIXED_SIZE_SAMPLES, 1);
+
+    return hr;
+}
+
+static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+        IMFMediaType **type)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE mt = {0};
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
+
+    if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetInputType(&impl->IMediaObject_iface, id, index, &mt))))
+        return hr;
+    hr = create_media_type_from_dmo(&mt, type);
+    MoFreeMediaType(&mt);
+    return hr;
+}
+
+static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+        IMFMediaType **type)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE mt = {0};
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
+
+    if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetOutputType(&impl->IMediaObject_iface, id, index, &mt))))
+        return hr;
+    hr = create_media_type_from_dmo(&mt, type);
+    MoFreeMediaType(&mt);
+    return hr;
+}
+
+static HRESULT init_dmo_media_type(IMFMediaType *type, DMO_MEDIA_TYPE *mt)
+{
+    MFVIDEOFORMAT *format;
+    HRESULT hr;
+
+    if (FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, FORMAT_MFVideoFormat, (AM_MEDIA_TYPE *)mt)))
+        return hr;
+
+    format = (MFVIDEOFORMAT *)mt->pbFormat;
+    mt->subtype = *get_dmo_subtype(&format->guidFormat); /* need to use DMO subtypes to be accepted */
+    if (!format->videoInfo.PixelAspectRatio.Numerator)
+        format->videoInfo.PixelAspectRatio.Numerator = 1;
+    if (!format->videoInfo.PixelAspectRatio.Denominator)
+        format->videoInfo.PixelAspectRatio.Denominator = 1;
+
+    return hr;
+}
+
+static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+    DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0;
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL;
+    HRESULT hr;
+
+    TRACE("converter %p, id %#lx, type %p, flags %#lx.\n", impl, id, type, flags);
+
+    if (type && FAILED(hr = init_dmo_media_type(type, &tmp)))
+        return hr;
+    hr = MF_RESULT_FROM_DMO(IMediaObject_SetInputType(&impl->IMediaObject_iface, id, mt, dmo_flags));
+    MoFreeMediaType(&tmp);
+    return hr;
+}
+
+static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+    DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0;
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL;
+    HRESULT hr;
+
+    TRACE("converter %p, id %#lx, type %p, flags %#lx.\n", impl, id, type, flags);
+
+    if (type && FAILED(hr = init_dmo_media_type(type, &tmp)))
+        return hr;
+    hr = MF_RESULT_FROM_DMO(IMediaObject_SetOutputType(&impl->IMediaObject_iface, id, mt, dmo_flags));
+    MoFreeMediaType(&tmp);
+    return hr;
+}
+
+static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+
+    TRACE("converter %p, id %#lx, type %p.\n", impl, id, type);
+
+    if (id != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL))
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->input_type, type);
+}
+
+static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+
+    TRACE("converter %p, id %#lx, type %p.\n", impl, id, type);
+
+    if (id != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+    if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->output_type, type);
+}
+
+static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+    FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+    FIXME("iface %p, flags %p stub!\n", iface, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+    TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+    FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+    FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param);
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    IMediaBuffer *dmo_buffer;
+    IMFMediaBuffer *buffer;
+    HRESULT hr;
+
+    TRACE("converter %p, id %#lx, sample %p, flags %#lx.\n", impl, id, sample, flags);
+
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+        return hr;
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &dmo_buffer)))
+    {
+        hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessInput(&impl->IMediaObject_iface, id, dmo_buffer, 0, 0, 0));
+        IMediaBuffer_Release(dmo_buffer);
+    }
+    IMFMediaBuffer_Release(buffer);
+
+    return hr;
+}
+
+static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+        MFT_OUTPUT_DATA_BUFFER *output, DWORD *output_status)
+{
+    struct color_convert *impl = impl_from_IMFTransform(iface);
+    DMO_OUTPUT_DATA_BUFFER dmo_output = {0};
+    IMFMediaBuffer *buffer;
+    DWORD dmo_status;
+    HRESULT hr;
+
+    TRACE("converter %p, flags %#lx, count %lu, output %p, output_status %p.\n", impl, flags, count,
+            output, output_status);
+
+    if (count != 1)
+        return E_INVALIDARG;
+
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(output->pSample, &buffer)))
+        return hr;
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(output->pSample, buffer, 0,
+            &dmo_output.pBuffer)))
+    {
+        hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessOutput(&impl->IMediaObject_iface, flags, 1,
+                &dmo_output, &dmo_status));
+        IMediaBuffer_Release(dmo_output.pBuffer);
+    }
+    IMFMediaBuffer_Release(buffer);
+
+    output->dwStatus = *output_status = 0;
+    return hr;
+}
+
+static const IMFTransformVtbl transform_vtbl =
+{
+    transform_QueryInterface,
+    transform_AddRef,
+    transform_Release,
+    transform_GetStreamLimits,
+    transform_GetStreamCount,
+    transform_GetStreamIDs,
+    transform_GetInputStreamInfo,
+    transform_GetOutputStreamInfo,
+    transform_GetAttributes,
+    transform_GetInputStreamAttributes,
+    transform_GetOutputStreamAttributes,
+    transform_DeleteInputStream,
+    transform_AddInputStreams,
+    transform_GetInputAvailableType,
+    transform_GetOutputAvailableType,
+    transform_SetInputType,
+    transform_SetOutputType,
+    transform_GetInputCurrentType,
+    transform_GetOutputCurrentType,
+    transform_GetInputStatus,
+    transform_GetOutputStatus,
+    transform_SetOutputBounds,
+    transform_ProcessEvent,
+    transform_ProcessMessage,
+    transform_ProcessInput,
+    transform_ProcessOutput,
+};
+
+static struct color_convert *impl_from_IMediaObject(IMediaObject *iface)
+{
+    return CONTAINING_RECORD(iface, struct color_convert, IMediaObject_iface);
+}
+
+static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj)
+{
+    return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj);
+}
+
+static ULONG WINAPI media_object_AddRef(IMediaObject *iface)
+{
+    return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer);
+}
+
+static ULONG WINAPI media_object_Release(IMediaObject *iface)
+{
+    return IUnknown_Release(impl_from_IMediaObject(iface)->outer);
+}
+
+static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output)
+{
+    FIXME("iface %p, input %p, output %p stub!\n", iface, input, output);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT get_available_dmo_media_type(const GUID *subtype, DMO_MEDIA_TYPE *type, BOOL output)
+{
+    VIDEOINFOHEADER *vih;
+
+    if (!(vih = CoTaskMemAlloc(sizeof(*vih))))
+        return E_OUTOFMEMORY;
+    memset(vih, 0, sizeof(*vih));
+
+    memset(type, 0, sizeof(*type));
+    type->majortype = MEDIATYPE_Video;
+    type->formattype = FORMAT_VideoInfo;
+    type->subtype = *subtype;
+    type->pbFormat = (BYTE *)vih;
+    type->cbFormat = sizeof(*vih);
+    return S_OK;
+}
+
+static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index,
+        DMO_MEDIA_TYPE *type)
+{
+    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
+
+    if (index > 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (type_index >= ARRAY_SIZE(input_types))
+        return DMO_E_NO_MORE_ITEMS;
+    return get_available_dmo_media_type(input_types[type_index], type, FALSE);
+}
+
+static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index,
+        DMO_MEDIA_TYPE *type)
+{
+    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
+
+    if (index > 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (type_index >= ARRAY_SIZE(output_types))
+        return DMO_E_NO_MORE_ITEMS;
+    return get_available_dmo_media_type(output_types[type_index], type, TRUE);
+}
+
+static HRESULT check_dmo_media_type(const DMO_MEDIA_TYPE *type, UINT32 *image_size,
+        const GUID *const *formats, UINT format_count)
+{
+    ULONG i;
+
+    if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
+        return DMO_E_INVALIDTYPE;
+    for (i = 0; i < format_count; ++i)
+        if (IsEqualGUID(&type->subtype, formats[i]))
+            break;
+    if (i == format_count)
+        return DMO_E_INVALIDTYPE;
+
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)
+            && type->cbFormat >= sizeof(VIDEOINFOHEADER))
+    {
+        VIDEOINFOHEADER *vih = (VIDEOINFOHEADER *)type->pbFormat;
+        if (!vih->bmiHeader.biWidth || !vih->bmiHeader.biHeight)
+            return DMO_E_INVALIDTYPE;
+        *image_size = vih->bmiHeader.biSizeImage;
+        return S_OK;
+    }
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)
+            && type->cbFormat >= sizeof(VIDEOINFOHEADER2))
+    {
+        VIDEOINFOHEADER2 *vih = (VIDEOINFOHEADER2 *)type->pbFormat;
+        if (!vih->bmiHeader.biWidth || !vih->bmiHeader.biHeight)
+            return DMO_E_INVALIDTYPE;
+        *image_size = vih->bmiHeader.biSizeImage;
+        return S_OK;
+    }
+    if (IsEqualGUID(&type->formattype, &FORMAT_MFVideoFormat)
+            && type->cbFormat >= sizeof(MFVIDEOFORMAT))
+    {
+        MFVIDEOFORMAT *fmt = (MFVIDEOFORMAT *)type->pbFormat;
+        if (!fmt->videoInfo.dwWidth || !fmt->videoInfo.dwHeight)
+            return DMO_E_INVALIDTYPE;
+        return MFCalculateImageSize(&type->subtype, fmt->videoInfo.dwWidth, fmt->videoInfo.dwHeight,
+            (UINT32 *)image_size);
+    }
+
+    return DMO_E_INVALIDTYPE;
+}
+
+static void clear_dmo_media_type(DMO_MEDIA_TYPE *mt)
+{
+    MoFreeMediaType(mt);
+    memset(mt, 0, sizeof(*mt));
+}
+
+static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index,
+        const DMO_MEDIA_TYPE *type, DWORD flags)
+{
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+    UINT32 image_size;
+    HRESULT hr;
+
+    TRACE("converter %p, index %#lx, type %p, flags %#lx.\n", impl, index, type, flags);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (!type)
+    {
+        clear_dmo_media_type(&impl->input_type);
+        color_convert_cleanup(impl);
+        return S_OK;
+    }
+
+    if (FAILED(hr = check_dmo_media_type(type, &image_size, input_types, ARRAY_SIZE(input_types))))
+        return hr;
+    if (flags & DMO_SET_TYPEF_TEST_ONLY)
+        return S_OK;
+
+    clear_dmo_media_type(&impl->input_type);
+    if (FAILED(hr = MoCopyMediaType(&impl->input_type, type)))
+        return hr;
+    impl->input_info.cbSize = image_size;
+
+    if (!IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)
+            && FAILED(hr = color_convert_init(impl)))
+    {
+        clear_dmo_media_type(&impl->input_type);
+        impl->input_info.cbSize = 0;
+    }
+    return hr;
+}
+
+static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index,
+        const DMO_MEDIA_TYPE *type, DWORD flags)
+{
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+    UINT32 image_size;
+    HRESULT hr;
+
+    TRACE("converter %p, index %#lx, type %p, flags %#lx.\n", impl, index, type, flags);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (!type)
+    {
+        clear_dmo_media_type(&impl->output_type);
+        color_convert_cleanup(impl);
+        return S_OK;
+    }
+
+    if (FAILED(hr = check_dmo_media_type(type, &image_size, output_types, ARRAY_SIZE(output_types))))
+        return hr;
+    if (flags & DMO_SET_TYPEF_TEST_ONLY)
+        return S_OK;
+
+    clear_dmo_media_type(&impl->output_type);
+    if (FAILED(hr = MoCopyMediaType(&impl->output_type, type)))
+        return hr;
+    impl->output_info.cbSize = image_size;
+
+    if (!IsEqualGUID(&impl->input_type.majortype, &GUID_NULL)
+            && FAILED(hr = color_convert_init(impl)))
+    {
+        clear_dmo_media_type(&impl->output_type);
+        impl->output_info.cbSize = 0;
+    }
+    return hr;
+}
+
+static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
+{
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, index %#lx, type %p.\n", iface, index, type);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL))
+        return DMO_E_TYPE_NOT_SET;
+    return MoCopyMediaType(type, &impl->input_type);
+}
+
+static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
+{
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, index %#lx, type %p.\n", iface, index, type);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+        return DMO_E_TYPE_NOT_SET;
+    return MoCopyMediaType(type, &impl->output_type);
+}
+
+static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size,
+        DWORD *lookahead, DWORD *alignment)
+{
+    FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size,
+            lookahead, alignment);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
+{
+    FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
+{
+    FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency)
+{
+    FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency));
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_Flush(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index)
+{
+    FIXME("iface %p, index %lu stub!\n", iface, index);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index,
+        IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
+{
+    DMO_OUTPUT_DATA_BUFFER input = {.pBuffer = buffer, .dwStatus = flags, .rtTimestamp = timestamp,
+            .rtTimelength = timelength};
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+
+    TRACE("converter %p, index %lu, buffer %p, flags %#lx, timestamp %I64d, timelength %I64d\n",
+            impl, index, buffer, flags, timestamp, timelength);
+
+    return color_convert_process_input(impl, &input);
+}
+
+static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count,
+        DMO_OUTPUT_DATA_BUFFER *output, DWORD *output_status)
+{
+    struct color_convert *impl = impl_from_IMediaObject(iface);
+
+    TRACE("converter %p, flags %#lx, count %lu, output %p, output_status %p\n", impl, flags, count,
+            output, output_status);
+
+    if (count != 1)
+        return E_INVALIDARG;
+    if (flags)
+        FIXME("Unimplemented flags %#lx\n", flags);
+
+    return color_convert_process_output(impl, output);
+}
+
+static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
+{
+    FIXME("iface %p, lock %ld stub!\n", iface, lock);
+    return E_NOTIMPL;
+}
+
+static const IMediaObjectVtbl media_object_vtbl =
+{
+    media_object_QueryInterface,
+    media_object_AddRef,
+    media_object_Release,
+    media_object_GetStreamCount,
+    media_object_GetInputStreamInfo,
+    media_object_GetOutputStreamInfo,
+    media_object_GetInputType,
+    media_object_GetOutputType,
+    media_object_SetInputType,
+    media_object_SetOutputType,
+    media_object_GetInputCurrentType,
+    media_object_GetOutputCurrentType,
+    media_object_GetInputSizeInfo,
+    media_object_GetOutputSizeInfo,
+    media_object_GetInputMaxLatency,
+    media_object_SetInputMaxLatency,
+    media_object_Flush,
+    media_object_Discontinuity,
+    media_object_AllocateStreamingResources,
+    media_object_FreeStreamingResources,
+    media_object_GetInputStatus,
+    media_object_ProcessInput,
+    media_object_ProcessOutput,
+    media_object_Lock,
+};
+
+static struct color_convert *impl_from_IPropertyBag(IPropertyBag *iface)
+{
+    return CONTAINING_RECORD(iface, struct color_convert, IPropertyBag_iface);
+}
+
+static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface)
+{
+    return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer);
+}
+
+static ULONG WINAPI property_bag_Release(IPropertyBag *iface)
+{
+    return IUnknown_Release(impl_from_IPropertyBag(iface)->outer);
+}
+
+static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value,
+        IErrorLog *error_log)
+{
+    FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value)
+{
+    FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value);
+    return S_OK;
+}
+
+static const IPropertyBagVtbl property_bag_vtbl =
+{
+    property_bag_QueryInterface,
+    property_bag_AddRef,
+    property_bag_Release,
+    property_bag_Read,
+    property_bag_Write,
+};
+
+static struct color_convert *impl_from_IPropertyStore(IPropertyStore *iface)
+{
+    return CONTAINING_RECORD(iface, struct color_convert, IPropertyStore_iface);
+}
+
+static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI property_store_AddRef(IPropertyStore *iface)
+{
+    return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer);
+}
+
+static ULONG WINAPI property_store_Release(IPropertyStore *iface)
+{
+    return IUnknown_Release(impl_from_IPropertyStore(iface)->outer);
+}
+
+static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count)
+{
+    FIXME("iface %p, count %p stub!\n", iface, count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key)
+{
+    FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
+{
+    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
+{
+    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_Commit(IPropertyStore *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static const IPropertyStoreVtbl property_store_vtbl =
+{
+    property_store_QueryInterface,
+    property_store_AddRef,
+    property_store_Release,
+    property_store_GetCount,
+    property_store_GetAt,
+    property_store_GetValue,
+    property_store_SetValue,
+    property_store_Commit,
+};
+
+static const char *debugstr_version(UINT version)
+{
+    return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),
+            AV_VERSION_MICRO(version));
+}
+
+static HRESULT WINAPI color_converter_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
+        REFIID riid, void **out)
+{
+    struct color_convert *impl;
+    HRESULT hr;
+
+    TRACE("outer %p, riid %s, out %p.\n", outer, debugstr_guid(riid), out);
+
+    if (outer && !IsEqualGUID(riid, &IID_IUnknown))
+        return E_NOINTERFACE;
+
+    TRACE("avutil version %s\n", debugstr_version(avutil_version()));
+    TRACE("swscale version %s\n", debugstr_version(swscale_version()));
+
+    if (!(impl = calloc(1, sizeof(*impl))))
+        return E_OUTOFMEMORY;
+    impl->IUnknown_inner.lpVtbl = &unknown_vtbl;
+    impl->IMFTransform_iface.lpVtbl = &transform_vtbl;
+    impl->IMediaObject_iface.lpVtbl = &media_object_vtbl;
+    impl->IPropertyBag_iface.lpVtbl = &property_bag_vtbl;
+    impl->IPropertyStore_iface.lpVtbl = &property_store_vtbl;
+    impl->refcount = 1;
+    impl->outer = outer ? outer : &impl->IUnknown_inner;
+
+    impl->input_info.cbAlignment = 1;
+    impl->output_info.cbAlignment = 1;
+
+    TRACE("Created converter %p\n", impl);
+
+    hr = IUnknown_QueryInterface(&impl->IUnknown_inner, riid, out);
+    IUnknown_Release(&impl->IUnknown_inner);
+    return hr;
+}
+
+static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
+{
+    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
+    return *out ? S_OK : E_NOINTERFACE;
+}
+static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+static ULONG WINAPI class_factory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    return S_OK;
+}
+
+static const IClassFactoryVtbl color_converter_factory_vtbl =
+{
+    class_factory_QueryInterface,
+    class_factory_AddRef,
+    class_factory_Release,
+    color_converter_factory_CreateInstance,
+    class_factory_LockServer,
+};
+
+IClassFactory color_converter_factory = {&color_converter_factory_vtbl};
diff --git a/dlls/colorcnv/colorcnv.c b/dlls/colorcnv/colorcnv.c
index e9bf90932bc9..467a0df8c82e 100644
--- a/dlls/colorcnv/colorcnv.c
+++ b/dlls/colorcnv/colorcnv.c
@@ -25,11 +25,22 @@
 
 #include "d3d9.h"
 #include "dmoreg.h"
+#include "dmort.h"
 #include "dshow.h"
+#include "dvdmedia.h"
+#include "mediaerr.h"
 #include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
 #include "rpcproxy.h"
 #include "wmcodecdsp.h"
 
+#include <libavutil/avutil.h>
+#include <libavutil/opt.h>
+#include <libavutil/imgutils.h>
+#include <libswscale/swscale.h>
+
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(dmo);
@@ -43,41 +54,7 @@ DEFINE_GUID(DMOVideoFormat_RGB565,D3DFMT_R5G6B5,0x524f,0x11ce,0x9f,0x53,0x00,0x2
 DEFINE_GUID(DMOVideoFormat_RGB555,D3DFMT_X1R5G5B5,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
 DEFINE_GUID(DMOVideoFormat_RGB8,D3DFMT_P8,0x524f,0x11ce,0x9f,0x53,0x00,0x20,0xaf,0x0b,0xa7,0x70);
 
-static HRESULT WINAPI color_converter_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
-        REFIID riid, void **out)
-{
-    static const GUID CLSID_wg_color_converter = {0xf47e2da5,0xe370,0x47b7,{0x90,0x3a,0x07,0x8d,0xdd,0x45,0xa5,0xcc}};
-    return CoCreateInstance(&CLSID_wg_color_converter, outer, CLSCTX_INPROC_SERVER, riid, out);
-}
-
-static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
-{
-    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
-    return *out ? S_OK : E_NOINTERFACE;
-}
-static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
-{
-    return 2;
-}
-static ULONG WINAPI class_factory_Release(IClassFactory *iface)
-{
-    return 1;
-}
-static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
-{
-    return S_OK;
-}
-
-static const IClassFactoryVtbl color_converter_factory_vtbl =
-{
-    class_factory_QueryInterface,
-    class_factory_AddRef,
-    class_factory_Release,
-    color_converter_factory_CreateInstance,
-    class_factory_LockServer,
-};
-
-static IClassFactory color_converter_factory = {&color_converter_factory_vtbl};
+extern IClassFactory color_converter_factory;
 
 /***********************************************************************
  *              DllGetClassObject (colorcnv.@)
diff --git a/dlls/comctl32/rebar.c b/dlls/comctl32/rebar.c
index 27270a9b63c1..15bc0d5aaeca 100644
--- a/dlls/comctl32/rebar.c
+++ b/dlls/comctl32/rebar.c
@@ -465,7 +465,7 @@ static int round_child_height(const REBAR_BAND *lpBand, int cyHeight)
 {
     int cy = 0;
     if (lpBand->cyIntegral == 0)
-        return cyHeight;
+        return min(cyHeight, lpBand->cyMaxChild);
     cy = max(cyHeight - (int)lpBand->cyMinChild, 0);
     cy = lpBand->cyMinChild + (cy/lpBand->cyIntegral) * lpBand->cyIntegral;
     cy = min(cy, lpBand->cyMaxChild);
diff --git a/dlls/comctl32/tests/rebar.c b/dlls/comctl32/tests/rebar.c
index d2c1e68d354b..188771651930 100644
--- a/dlls/comctl32/tests/rebar.c
+++ b/dlls/comctl32/tests/rebar.c
@@ -246,7 +246,7 @@ static void rbsize_add_band(rbsize_result_t *rbsr, int left, int top, int right,
 
 static rbsize_result_t *rbsize_results;
 
-#define rbsize_results_num 27
+#define rbsize_results_num 28
 
 static void rbsize_results_init(void)
 {
@@ -430,6 +430,10 @@ static void rbsize_results_init(void)
     rbsize_add_band(&rbsize_results[26], 0, 0, 90, 65, 0x40, 90);
     rbsize_add_band(&rbsize_results[26], 90, 0, 163, 65, 0x40, 90);
     rbsize_add_band(&rbsize_results[26], 163, 0, 226, 65, 0x40, 90);
+
+    rbsize_results[27] = rbsize_init(0, 0, 672, 65, 56, 1, 1);
+    rbsize_add_row(&rbsize_results[27], 65);
+    rbsize_add_band(&rbsize_results[27], 0, 0, 672, 65, 0x40, 90);
 }
 
 static void rbsize_results_free(void)
@@ -684,6 +688,22 @@ static void test_layout(void)
 
     DestroyWindow(hRebar);
 
+    /* VARHEIGHT resizing test with cyIntegral == 0 on a horizontal rebar */
+    hRebar = create_rebar_control(0);
+    SetWindowLongA(hRebar, GWL_STYLE, GetWindowLongA(hRebar, GWL_STYLE) | RBS_AUTOSIZE);
+    rbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE | RBBIM_STYLE;
+    rbi.fStyle = RBBS_VARIABLEHEIGHT;
+    rbi.cx = 90;
+    rbi.cyMinChild = 40;
+    rbi.cyMaxChild = 65;
+    rbi.cyIntegral = 0;
+    rbi.cyChild = 111;
+    rbi.hwndChild = build_toolbar(0, hRebar);
+    SendMessageA(hRebar, RB_INSERTBANDA, -1, (LPARAM)&rbi);
+    check_sizes();
+
+    DestroyWindow(hRebar);
+
     rbsize_results_free();
 }
 
diff --git a/dlls/comctl32/tests/v6util.h b/dlls/comctl32/tests/v6util.h
index a4e928f51bff..c88223ef4b92 100644
--- a/dlls/comctl32/tests/v6util.h
+++ b/dlls/comctl32/tests/v6util.h
@@ -22,7 +22,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/d2d1/geometry.c b/dlls/d2d1/geometry.c
index 938163902846..b6903d01024a 100644
--- a/dlls/d2d1/geometry.c
+++ b/dlls/d2d1/geometry.c
@@ -1446,6 +1446,7 @@ static void d2d_figure_cleanup(struct d2d_figure *figure)
     free(figure->original_bezier_controls);
     free(figure->bezier_controls);
     free(figure->vertices);
+    free(figure->vertex_types);
     free(figure->segments.data);
     memset(figure, 0, sizeof(*figure));
 }
diff --git a/dlls/d3dcompiler_43/reflection.c b/dlls/d3dcompiler_43/reflection.c
index 21b367f5002a..182b3c99b637 100644
--- a/dlls/d3dcompiler_43/reflection.c
+++ b/dlls/d3dcompiler_43/reflection.c
@@ -54,18 +54,6 @@ enum D3DCOMPILER_SIGNATURE_ELEMENT_SIZE
 
 #define D3DCOMPILER_SHDR_SHADER_TYPE_CS 0x4353
 
-enum d3dcompiler_shader_type
-{
-    D3DCOMPILER_SHADER_TYPE_CS = 5,
-};
-
-struct d3dcompiler_shader_signature
-{
-    D3D11_SIGNATURE_PARAMETER_DESC *elements;
-    unsigned int element_count;
-    char *string_data;
-};
-
 struct d3dcompiler_shader_reflection_type
 {
     ID3D11ShaderReflectionType ID3D11ShaderReflectionType_iface;
@@ -131,6 +119,9 @@ struct d3dcompiler_shader_reflection
 
     enum D3DCOMPILER_REFLECTION_VERSION interface_version;
 
+    struct vkd3d_shader_scan_signature_info signature_info;
+    struct vkd3d_shader_scan_thread_group_size_info thread_group_size_info;
+
     uint32_t target;
     char *creator;
     UINT flags;
@@ -166,13 +157,7 @@ struct d3dcompiler_shader_reflection
     D3D_TESSELLATOR_OUTPUT_PRIMITIVE hs_output_primitive;
     D3D_TESSELLATOR_PARTITIONING hs_partitioning;
     D3D_TESSELLATOR_DOMAIN tessellator_domain;
-    UINT thread_group_size_x;
-    UINT thread_group_size_y;
-    UINT thread_group_size_z;
 
-    struct d3dcompiler_shader_signature *isgn;
-    struct d3dcompiler_shader_signature *osgn;
-    struct d3dcompiler_shader_signature *pcsg;
     char *resource_string;
     D3D12_SHADER_INPUT_BIND_DESC *bound_resources;
     struct d3dcompiler_shader_reflection_constant_buffer *constant_buffers;
@@ -267,14 +252,6 @@ static void d3dcompiler_shader_reflection_type_destroy(struct wine_rb_entry *ent
     free(t);
 }
 
-static void free_signature(struct d3dcompiler_shader_signature *sig)
-{
-    TRACE("Free signature %p\n", sig);
-
-    free(sig->elements);
-    free(sig->string_data);
-}
-
 static void free_variable(struct d3dcompiler_shader_reflection_variable *var)
 {
     if (var)
@@ -304,24 +281,6 @@ static void reflection_cleanup(struct d3dcompiler_shader_reflection *ref)
 {
     TRACE("Cleanup %p\n", ref);
 
-    if (ref->isgn)
-    {
-        free_signature(ref->isgn);
-        free(ref->isgn);
-    }
-
-    if (ref->osgn)
-    {
-        free_signature(ref->osgn);
-        free(ref->osgn);
-    }
-
-    if (ref->pcsg)
-    {
-        free_signature(ref->pcsg);
-        free(ref->pcsg);
-    }
-
     if (ref->constant_buffers)
     {
         unsigned int i;
@@ -337,6 +296,8 @@ static void reflection_cleanup(struct d3dcompiler_shader_reflection *ref)
     free(ref->bound_resources);
     free(ref->resource_string);
     free(ref->creator);
+
+    vkd3d_shader_free_scan_signature_info(&ref->signature_info);
 }
 
 /* IUnknown methods */
@@ -410,8 +371,8 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetDesc(ID3D11Sha
     desc->Flags = reflection->flags;
     desc->ConstantBuffers = reflection->constant_buffer_count;
     desc->BoundResources = reflection->bound_resource_count;
-    desc->InputParameters = reflection->isgn ? reflection->isgn->element_count : 0;
-    desc->OutputParameters = reflection->osgn ? reflection->osgn->element_count : 0;
+    desc->InputParameters = reflection->signature_info.input.element_count;
+    desc->OutputParameters = reflection->signature_info.output.element_count;
     desc->InstructionCount = reflection->instruction_count;
     desc->TempRegisterCount = reflection->temp_register_count;
     desc->TempArrayCount = reflection->temp_array_count;
@@ -435,7 +396,7 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetDesc(ID3D11Sha
     desc->GSMaxOutputVertexCount = reflection->gs_max_output_vertex_count;
 #if D3D_COMPILER_VERSION
     desc->InputPrimitive = reflection->input_primitive;
-    desc->PatchConstantParameters = reflection->pcsg ? reflection->pcsg->element_count : 0;
+    desc->PatchConstantParameters = reflection->signature_info.patch_constant.element_count;
     desc->cGSInstanceCount = 0;
     desc->cControlPoints = reflection->c_control_points;
     desc->HSOutputPrimitive = reflection->hs_output_primitive;
@@ -515,40 +476,53 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetResourceBindin
     return S_OK;
 }
 
-static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetInputParameterDesc(
-        ID3D11ShaderReflection *iface, UINT index, D3D11_SIGNATURE_PARAMETER_DESC *desc)
+static HRESULT get_signature_parameter(const struct vkd3d_shader_signature *signature,
+        unsigned int index, D3D11_SIGNATURE_PARAMETER_DESC *desc, bool output)
 {
-    struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
-
-    TRACE("iface %p, index %u, desc %p\n", iface, index, desc);
+    const struct vkd3d_shader_signature_element *e;
 
-    if (!desc || !reflection->isgn || index >= reflection->isgn->element_count)
+    if (!desc || index >= signature->element_count)
     {
-        WARN("Invalid argument specified\n");
+        WARN("Invalid argument specified.\n");
         return E_INVALIDARG;
     }
+    e = &signature->elements[index];
 
-    *desc = reflection->isgn->elements[index];
+    desc->SemanticName = e->semantic_name;
+    desc->SemanticIndex = e->semantic_index;
+    desc->Register = e->register_index;
+    desc->SystemValueType = (D3D_NAME)e->sysval_semantic;
+    desc->ComponentType = (D3D_REGISTER_COMPONENT_TYPE)e->component_type;
+    desc->Mask = e->mask;
+    desc->ReadWriteMask = output ? (0xf ^ e->used_mask) : e->used_mask;
+#if D3D_COMPILER_VERSION
+    desc->Stream = e->stream_index;
+#endif
+#if D3D_COMPILER_VERSION >= 46
+    desc->MinPrecision = (D3D_MIN_PRECISION)e->min_precision;
+#endif
 
     return S_OK;
 }
 
-static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetOutputParameterDesc(
+static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetInputParameterDesc(
         ID3D11ShaderReflection *iface, UINT index, D3D11_SIGNATURE_PARAMETER_DESC *desc)
 {
     struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
 
-    TRACE("iface %p, index %u, desc %p\n", iface, index, desc);
+    TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
 
-    if (!desc || !reflection->osgn || index >= reflection->osgn->element_count)
-    {
-        WARN("Invalid argument specified\n");
-        return E_INVALIDARG;
-    }
+    return get_signature_parameter(&reflection->signature_info.input, index, desc, false);
+}
+
+static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetOutputParameterDesc(
+        ID3D11ShaderReflection *iface, UINT index, D3D11_SIGNATURE_PARAMETER_DESC *desc)
+{
+    struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
 
-    *desc = reflection->osgn->elements[index];
+    TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
 
-    return S_OK;
+    return get_signature_parameter(&reflection->signature_info.output, index, desc, true);
 }
 
 #if D3D_COMPILER_VERSION
@@ -556,18 +530,11 @@ static HRESULT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetPatchConstantP
         ID3D11ShaderReflection *iface, UINT index, D3D11_SIGNATURE_PARAMETER_DESC *desc)
 {
     struct d3dcompiler_shader_reflection *reflection = impl_from_ID3D11ShaderReflection(iface);
+    bool output = ((reflection->version & 0xffff0000) >> 16) == D3D12_SHVER_HULL_SHADER;
 
-    TRACE("iface %p, index %u, desc %p\n", iface, index, desc);
-
-    if (!desc || !reflection->pcsg || index >= reflection->pcsg->element_count)
-    {
-        WARN("Invalid argument specified\n");
-        return E_INVALIDARG;
-    }
-
-    *desc = reflection->pcsg->elements[index];
+    TRACE("iface %p, index %u, desc %p.\n", iface, index, desc);
 
-    return S_OK;
+    return get_signature_parameter(&reflection->signature_info.patch_constant, index, desc, output);
 }
 
 static struct ID3D11ShaderReflectionVariable * STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetVariableByName(
@@ -718,9 +685,9 @@ static UINT STDMETHODCALLTYPE d3dcompiler_shader_reflection_GetThreadGroupSize(
         return E_INVALIDARG;
     }
 
-    *sizex = reflection->thread_group_size_x;
-    *sizey = reflection->thread_group_size_y;
-    *sizez = reflection->thread_group_size_z;
+    *sizex = reflection->thread_group_size_info.x;
+    *sizey = reflection->thread_group_size_info.y;
+    *sizez = reflection->thread_group_size_info.z;
 
     return *sizex * *sizey * *sizez;
 }
@@ -1670,286 +1637,66 @@ err_out:
     return hr;
 }
 
-static HRESULT d3dcompiler_parse_signature(struct d3dcompiler_shader_signature *s,
-        const struct vkd3d_shader_dxbc_section_desc *section)
+static HRESULT d3dcompiler_shader_reflection_init(struct d3dcompiler_shader_reflection *reflection,
+        const void *data, SIZE_T data_size)
 {
-    enum D3DCOMPILER_SIGNATURE_ELEMENT_SIZE element_size;
-    const char *ptr = section->data.code;
-    D3D11_SIGNATURE_PARAMETER_DESC *d;
-    unsigned int string_data_offset;
-    unsigned int string_data_size;
-    unsigned int i, count;
-    char *string_data;
+    struct vkd3d_shader_compile_info compile_info = {.type = VKD3D_SHADER_STRUCTURE_TYPE_COMPILE_INFO};
+    struct vkd3d_shader_dxbc_desc src_dxbc_desc;
+    HRESULT hr = S_OK;
+    unsigned int i;
+    int ret;
 
-    switch (section->tag)
-    {
-        case TAG_OSG5:
-            element_size = D3DCOMPILER_SIGNATURE_ELEMENT_SIZE7;
-            break;
-
-        case TAG_ISGN:
-        case TAG_OSGN:
-        case TAG_PCSG:
-            element_size = D3DCOMPILER_SIGNATURE_ELEMENT_SIZE6;
-            break;
-
-        default:
-            FIXME("Unhandled section %s!\n", debugstr_fourcc(section->tag));
-            element_size = D3DCOMPILER_SIGNATURE_ELEMENT_SIZE6;
-            break;
-    }
+    compile_info.next = &reflection->signature_info;
+    compile_info.source.code = data;
+    compile_info.source.size = data_size;
+    compile_info.source_type = VKD3D_SHADER_SOURCE_DXBC_TPF;
 
-    count = read_u32(&ptr);
-    TRACE("%u elements\n", count);
+    reflection->signature_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_SIGNATURE_INFO;
+    reflection->signature_info.next = &reflection->thread_group_size_info;
 
-    skip_u32_unknown(&ptr, 1);
+    reflection->thread_group_size_info.type = VKD3D_SHADER_STRUCTURE_TYPE_SCAN_THREAD_GROUP_SIZE_INFO;
 
-    d = calloc(count, sizeof(*d));
-    if (!d)
+    if ((ret = vkd3d_shader_scan(&compile_info, NULL)) < 0)
     {
-        ERR("Failed to allocate signature memory.\n");
-        return E_OUTOFMEMORY;
+        WARN("Failed to scan shader, ret %d.\n", ret);
+        return E_FAIL;
     }
 
-    /* 2 u32s for the header, element_size for each element. */
-    string_data_offset = 2 * sizeof(uint32_t) + count * element_size * sizeof(uint32_t);
-    string_data_size = section->data.size - string_data_offset;
+    wine_rb_init(&reflection->types, d3dcompiler_shader_reflection_type_compare);
 
-    string_data = malloc(string_data_size);
-    if (!string_data)
+    if ((ret = vkd3d_shader_parse_dxbc(&compile_info.source, 0, &src_dxbc_desc, NULL)) < 0)
     {
-        ERR("Failed to allocate string data memory.\n");
-        free(d);
-        return E_OUTOFMEMORY;
+        WARN("Failed to parse reflection, ret %d.\n", ret);
+        vkd3d_shader_free_scan_signature_info(&reflection->signature_info);
+        return E_FAIL;
     }
-    memcpy(string_data, (const char *)section->data.code + string_data_offset, string_data_size);
 
-    for (i = 0; i < count; ++i)
+    for (i = 0; i < src_dxbc_desc.section_count; ++i)
     {
-        uint32_t name_offset, mask;
+        const struct vkd3d_shader_dxbc_section_desc *section = &src_dxbc_desc.sections[i];
 
-#if D3D_COMPILER_VERSION >= 46
-        /* FIXME */
-        d[i].MinPrecision = D3D_MIN_PRECISION_DEFAULT;
-#endif
-#if D3D_COMPILER_VERSION
-        if (element_size == D3DCOMPILER_SIGNATURE_ELEMENT_SIZE7)
+        if (section->tag == TAG_RDEF)
         {
-            d[i].Stream = read_u32(&ptr);
-        }
-#endif
-
-        name_offset = read_u32(&ptr);
-        d[i].SemanticName = string_data + (name_offset - string_data_offset);
-        d[i].SemanticIndex = read_u32(&ptr);
-        d[i].SystemValueType = read_u32(&ptr);
-        d[i].ComponentType = read_u32(&ptr);
-        d[i].Register = read_u32(&ptr);
-        mask = read_u32(&ptr);
-        d[i].ReadWriteMask = (mask >> 8) & 0xff;
-        d[i].Mask = mask & 0xff;
-
-        if (!stricmp(d[i].SemanticName, "sv_depth"))
-            d[i].SystemValueType = D3D_NAME_DEPTH;
-        else if (!stricmp(d[i].SemanticName, "sv_coverage"))
-            d[i].SystemValueType = D3D_NAME_COVERAGE;
-        else if (!stricmp(d[i].SemanticName, "sv_depthgreaterequal"))
-            d[i].SystemValueType = D3D_NAME_DEPTH_GREATER_EQUAL;
-        else if (!stricmp(d[i].SemanticName, "sv_depthlessequal"))
-            d[i].SystemValueType = D3D_NAME_DEPTH_LESS_EQUAL;
-        else if (!stricmp(d[i].SemanticName, "sv_target"))
-            d[i].SystemValueType = D3D_NAME_TARGET;
-    }
-
-    s->elements = d;
-    s->element_count = count;
-    s->string_data = string_data;
-
-    return S_OK;
-}
-
-#define SM4_OPCODE_MASK                 0xff
-#define SM4_INSTRUCTION_LENGTH_SHIFT    24
-#define SM4_INSTRUCTION_LENGTH_MASK     (0x1fu << SM4_INSTRUCTION_LENGTH_SHIFT)
-
-enum sm4_opcode
-{
-    SM5_OP_DCL_THREAD_GROUP                 = 0x9b,
-};
-
-static HRESULT d3dcompiler_parse_shdr(struct d3dcompiler_shader_reflection *r, const char *data, size_t data_size)
-{
-    uint32_t opcode_token, opcode;
-    uint32_t size, shader_type;
-    const char *ptr = data;
-    const uint32_t *u_ptr;
-    unsigned int len;
-
-    r->version = read_u32(&ptr);
-    TRACE("Shader version: %u\n", r->version);
-
-    shader_type = (r->version & D3DCOMPILER_SHADER_TARGET_SHADERTYPE_MASK)
-            >> D3DCOMPILER_SHADER_TARGET_SHADERTYPE_SHIFT;
-
-    if (shader_type != D3DCOMPILER_SHADER_TYPE_CS)
-    {
-        /* TODO: Check if anything else is needed from the SHDR or SHEX blob. */
-        return S_OK;
-    }
-
-    size = read_u32(&ptr);
-    TRACE("size %u.\n", size);
-    if (size * sizeof(uint32_t) != data_size || size < 2)
-    {
-        WARN("Invalid size %u.\n", size);
-        return E_FAIL;
-    }
-    size -= 2;
-    u_ptr = (uint32_t *)ptr;
-    while (size)
-    {
-        opcode_token = *u_ptr;
-        opcode = opcode_token & SM4_OPCODE_MASK;
-        len = (opcode_token & SM4_INSTRUCTION_LENGTH_MASK) >> SM4_INSTRUCTION_LENGTH_SHIFT;
-        if (!len)
-        {
-            if (size < 2)
+            if (FAILED(hr = d3dcompiler_parse_rdef(reflection, section->data.code, section->data.size)))
             {
-                WARN("End of byte-code, failed to read length token.\n");
-                return E_FAIL;
+                WARN("Failed to parse RDEF section.\n");
+                goto err_out;
             }
-            len = u_ptr[1];
         }
-        if (!len || size < len)
+        else if (section->tag == TAG_SHDR || section->tag == TAG_SHEX)
         {
-            WARN("Invalid instruction length %u, size %u.\n", len, size);
-            return E_FAIL;
+            const char *ptr = section->data.code;
+
+            reflection->version = read_u32(&ptr);
+            TRACE("Shader version: 0x%08x.\n", reflection->version);
         }
-        if (opcode == SM5_OP_DCL_THREAD_GROUP)
+        else if (section->tag == TAG_STAT)
         {
-            if (len != 4)
+            if (FAILED(hr = d3dcompiler_parse_stat(reflection, section->data.code, section->data.size)))
             {
-                WARN("Invalid dcl_thread_group opcode length %u.\n", len);
-                return E_FAIL;
+                WARN("Failed to parse STAT section.\n");
+                goto err_out;
             }
-            r->thread_group_size_x = u_ptr[1];
-            r->thread_group_size_y = u_ptr[2];
-            r->thread_group_size_z = u_ptr[3];
-            TRACE("Found dcl_thread_group %u, %u, %u.\n",
-                    r->thread_group_size_x, r->thread_group_size_y, r->thread_group_size_z);
-        }
-        size -= len;
-        u_ptr += len;
-    }
-    return S_OK;
-}
-
-static HRESULT d3dcompiler_shader_reflection_init(struct d3dcompiler_shader_reflection *reflection,
-        const void *data, SIZE_T data_size)
-{
-    const struct vkd3d_shader_code src_dxbc = {.code = data, .size = data_size};
-    struct vkd3d_shader_dxbc_desc src_dxbc_desc;
-    HRESULT hr = S_OK;
-    unsigned int i;
-    int ret;
-
-    wine_rb_init(&reflection->types, d3dcompiler_shader_reflection_type_compare);
-
-    if ((ret = vkd3d_shader_parse_dxbc(&src_dxbc, 0, &src_dxbc_desc, NULL)) < 0)
-    {
-        WARN("Failed to parse reflection, ret %d.\n", ret);
-        return E_FAIL;
-    }
-
-    for (i = 0; i < src_dxbc_desc.section_count; ++i)
-    {
-        const struct vkd3d_shader_dxbc_section_desc *section = &src_dxbc_desc.sections[i];
-
-        switch (section->tag)
-        {
-            case TAG_RDEF:
-                hr = d3dcompiler_parse_rdef(reflection, section->data.code, section->data.size);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse RDEF section.\n");
-                    goto err_out;
-                }
-                break;
-
-            case TAG_ISGN:
-                reflection->isgn = calloc(1, sizeof(*reflection->isgn));
-                if (!reflection->isgn)
-                {
-                    ERR("Failed to allocate ISGN memory.\n");
-                    hr = E_OUTOFMEMORY;
-                    goto err_out;
-                }
-
-                hr = d3dcompiler_parse_signature(reflection->isgn, section);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse section ISGN.\n");
-                    goto err_out;
-                }
-                break;
-
-            case TAG_OSG5:
-            case TAG_OSGN:
-                reflection->osgn = calloc(1, sizeof(*reflection->osgn));
-                if (!reflection->osgn)
-                {
-                    ERR("Failed to allocate OSGN memory.\n");
-                    hr = E_OUTOFMEMORY;
-                    goto err_out;
-                }
-
-                hr = d3dcompiler_parse_signature(reflection->osgn, section);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse section OSGN.\n");
-                    goto err_out;
-                }
-                break;
-
-            case TAG_PCSG:
-                reflection->pcsg = calloc(1, sizeof(*reflection->pcsg));
-                if (!reflection->pcsg)
-                {
-                    ERR("Failed to allocate PCSG memory.\n");
-                    hr = E_OUTOFMEMORY;
-                    goto err_out;
-                }
-
-                hr = d3dcompiler_parse_signature(reflection->pcsg, section);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse section PCSG.\n");
-                    goto err_out;
-                }
-                break;
-
-            case TAG_SHEX:
-            case TAG_SHDR:
-                hr = d3dcompiler_parse_shdr(reflection, section->data.code, section->data.size);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse SHDR section.\n");
-                    goto err_out;
-                }
-                break;
-
-            case TAG_STAT:
-                hr = d3dcompiler_parse_stat(reflection, section->data.code, section->data.size);
-                if (FAILED(hr))
-                {
-                    WARN("Failed to parse section STAT.\n");
-                    goto err_out;
-                }
-                break;
-
-            default:
-                FIXME("Unhandled section %s!\n", debugstr_fourcc(section->tag));
-                break;
         }
     }
 
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 9277eea5e960..cf7f01d4b452 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -144,6 +144,7 @@ static HRESULT insert_cache_entry( DIDEVICEINSTANCEW *instance, DWORD joy_id, co
                    debugstr_w( path ), next->joy_id );
             next->instance = *instance;
             wcscpy( next->path, path );
+            CharLowerW( next->path );
             return S_OK;
         }
     }
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c
index ddcbddc98800..6aac9ea14e54 100644
--- a/dlls/dinput/tests/joystick8.c
+++ b/dlls/dinput/tests/joystick8.c
@@ -6037,6 +6037,8 @@ static void check_device_hid_serial_( int line, IDirectInputDevice8W *device, co
 
     hr = IDirectInputDevice8_GetProperty( device, DIPROP_GUIDANDPATH, &prop_guid_path.diph );
     ok_(__FILE__, line)( hr == S_OK, "Unexpected hr %#lx.\n", hr );
+    ok_(__FILE__, line)( !!wcsstr(prop_guid_path.wszPath, L"hid"), "Unexpected path %s.\n",
+            debugstr_w(prop_guid_path.wszPath) );
 
     file_handle = CreateFileW( prop_guid_path.wszPath, FILE_READ_ACCESS | FILE_WRITE_ACCESS,
                                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
diff --git a/dlls/dpnet/threadpool.c b/dlls/dpnet/threadpool.c
index 5e081f3fd2ed..b9b18b6ba69a 100644
--- a/dlls/dpnet/threadpool.c
+++ b/dlls/dpnet/threadpool.c
@@ -36,8 +36,6 @@
 WINE_DEFAULT_DEBUG_CHANNEL(dpnet);
 
 static PFNDPNMESSAGEHANDLER threadpool_msghandler = NULL;
-static DWORD threadpool_flags       = 0;
-static void *threadpool_usercontext = NULL;
 
 static inline IDirectPlay8ThreadPoolImpl *impl_from_IDirectPlay8ThreadPool(IDirectPlay8ThreadPool *iface)
 {
@@ -93,8 +91,6 @@ static HRESULT WINAPI IDirectPlay8ThreadPoolImpl_Initialize(IDirectPlay8ThreadPo
         return DPNERR_ALREADYINITIALIZED;
 
     threadpool_msghandler  = pfn;
-    threadpool_flags       = dwFlags;
-    threadpool_usercontext = pvUserContext;
 
     return DPN_OK;
 }
diff --git a/dlls/dsound/dsound_convert.c b/dlls/dsound/dsound_convert.c
index bdd62c8e51fb..c1acc95652c2 100644
--- a/dlls/dsound/dsound_convert.c
+++ b/dlls/dsound/dsound_convert.c
@@ -111,42 +111,6 @@ float get_mono(const IDirectSoundBufferImpl *dsb, BYTE *base, DWORD channel)
     return val;
 }
 
-static inline unsigned char f_to_8(float value)
-{
-    if(value <= -1.f)
-        return 0;
-    if(value >= 1.f * 0x7f / 0x80)
-        return 0xFF;
-    return lrintf((value + 1.f) * 0x80);
-}
-
-static inline SHORT f_to_16(float value)
-{
-    if(value <= -1.f)
-        return 0x8000;
-    if(value >= 1.f * 0x7FFF / 0x8000)
-        return 0x7FFF;
-    return le16(lrintf(value * 0x8000));
-}
-
-static LONG f_to_24(float value)
-{
-    if(value <= -1.f)
-        return 0x80000000;
-    if(value >= 1.f * 0x7FFFFF / 0x800000)
-        return 0x7FFFFF00;
-    return lrintf(value * 0x80000000U);
-}
-
-static inline LONG f_to_32(float value)
-{
-    if(value <= -1.f)
-        return 0x80000000;
-    if(value >= 1.f)
-        return 0x7FFFFFFF;
-    return le32(lrintf(value * 0x80000000U));
-}
-
 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value)
 {
     BYTE *buf = (BYTE *)dsb->device->tmp_buffer;
@@ -327,57 +291,3 @@ void mixieee32(float *src, float *dst, unsigned samples)
     while (samples--)
         *(dst++) += *(src++);
 }
-
-static void norm8(float *src, unsigned char *dst, unsigned samples)
-{
-    TRACE("%p - %p %d\n", src, dst, samples);
-    while (samples--)
-    {
-        *dst = f_to_8(*src);
-        ++dst;
-        ++src;
-    }
-}
-
-static void norm16(float *src, SHORT *dst, unsigned samples)
-{
-    TRACE("%p - %p %d\n", src, dst, samples);
-    while (samples--)
-    {
-        *dst = f_to_16(*src);
-        ++dst;
-        ++src;
-    }
-}
-
-static void norm24(float *src, BYTE *dst, unsigned samples)
-{
-    TRACE("%p - %p %d\n", src, dst, samples);
-    while (samples--)
-    {
-        LONG t = f_to_24(*src);
-        dst[0] = (t >> 8) & 0xFF;
-        dst[1] = (t >> 16) & 0xFF;
-        dst[2] = t >> 24;
-        dst += 3;
-        ++src;
-    }
-}
-
-static void norm32(float *src, INT *dst, unsigned samples)
-{
-    TRACE("%p - %p %d\n", src, dst, samples);
-    while (samples--)
-    {
-        *dst = f_to_32(*src);
-        ++dst;
-        ++src;
-    }
-}
-
-const normfunc normfunctions[4] = {
-    (normfunc)norm8,
-    (normfunc)norm16,
-    (normfunc)norm24,
-    (normfunc)norm32,
-};
diff --git a/dlls/dsound/dsound_private.h b/dlls/dsound/dsound_private.h
index 7e6768a21a8e..c9b8a1b202d8 100644
--- a/dlls/dsound/dsound_private.h
+++ b/dlls/dsound/dsound_private.h
@@ -49,8 +49,6 @@ extern const bitsgetfunc getbpp[5];
 void putieee32(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void putieee32_sum(const IDirectSoundBufferImpl *dsb, DWORD pos, DWORD channel, float value);
 void mixieee32(float *src, float *dst, unsigned samples);
-typedef void (*normfunc)(const void *, void *, unsigned);
-extern const normfunc normfunctions[4];
 
 typedef struct _DSVOLUMEPAN
 {
@@ -93,8 +91,6 @@ struct DirectSoundDevice
 
     DSVOLUMEPAN                 volpan;
 
-    normfunc normfunction;
-
     /* DirectSound3DListener fields */
     DS3DLISTENER                ds3dl;
     BOOL                        ds3dl_need_recalc;
diff --git a/dlls/dsound/mixer.c b/dlls/dsound/mixer.c
index 3b7715e0c69c..c8d0ea369d29 100644
--- a/dlls/dsound/mixer.c
+++ b/dlls/dsound/mixer.c
@@ -879,7 +879,6 @@ static void DSOUND_WaveQueue(DirectSoundDevice *device, LPBYTE pos, DWORD bytes)
  * secondary->buffer (secondary format)
  *   =[Resample]=> device->tmp_buffer (float format)
  *   =[Volume]=> device->tmp_buffer (float format)
- *   =[Reformat]=> device->buffer (device format, skipped on float)
  */
 static void DSOUND_PerformMix(DirectSoundDevice *device)
 {
@@ -934,16 +933,7 @@ static void DSOUND_PerformMix(DirectSoundDevice *device)
 
 		memset(buffer, nfiller, frames * block);
 
-		if (!device->normfunction)
-			DSOUND_MixToPrimary(device, buffer, frames);
-		else {
-			memset(device->buffer, nfiller, device->buflen);
-
-			/* do the mixing */
-			DSOUND_MixToPrimary(device, (float*)device->buffer, frames);
-
-			device->normfunction(device->buffer, buffer, frames * device->pwfx->nChannels);
-		}
+                DSOUND_MixToPrimary(device, buffer, frames);
 
 		hr = IAudioRenderClient_ReleaseBuffer(device->render, frames, 0);
 		if(FAILED(hr))
diff --git a/dlls/dsound/primary.c b/dlls/dsound/primary.c
index e180dbaeacd4..bd992f789842 100644
--- a/dlls/dsound/primary.c
+++ b/dlls/dsound/primary.c
@@ -24,6 +24,7 @@
  */
 
 #include <stdarg.h>
+#include <assert.h>
 
 #define COBJMACROS
 #include "windef.h"
@@ -210,7 +211,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,
     IDirectSoundBufferImpl** dsb = device->buffers;
     LPBYTE newbuf;
     DWORD new_buflen;
-    BOOL mixfloat = FALSE;
     int i;
 
     TRACE("(%p)\n", device);
@@ -218,16 +218,10 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,
     new_buflen = device->buflen;
     new_buflen -= new_buflen % wfx->nBlockAlign;
 
-    if (wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
-        (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
-         IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
-        mixfloat = TRUE;
-
     /* reallocate emulated primary buffer */
-    if (forcewave || !mixfloat) {
-        if (!forcewave)
-            new_buflen = frames * wfx->nChannels * sizeof(float);
-
+    if (forcewave)
+    {
+        /* forcewave means DSSCL_WRITEPRIMARY, which implies no mixing */
         newbuf = realloc(device->buffer, new_buflen);
 
         if (!newbuf) {
@@ -236,6 +230,10 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,
         }
         FillMemory(newbuf, new_buflen, (wfx->wBitsPerSample == 8) ? 128 : 0);
     } else {
+        assert(wfx->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+               (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+                IsEqualGUID(&((WAVEFORMATEXTENSIBLE*)wfx)->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)));
+
         free(device->buffer);
         newbuf = NULL;
     }
@@ -249,11 +247,6 @@ static HRESULT DSOUND_PrimaryOpen(DirectSoundDevice *device, WAVEFORMATEX *wfx,
 
     TRACE("buflen: %lu, frames %lu\n", device->buflen, frames);
 
-    if (!mixfloat)
-        device->normfunction = normfunctions[wfx->wBitsPerSample/8 - 1];
-    else
-        device->normfunction = NULL;
-
     device->playpos = 0;
 
     for (i = 0; i < device->nrofbuffers; i++) {
diff --git a/dlls/dsrole/Makefile.in b/dlls/dsrole/Makefile.in
new file mode 100644
index 000000000000..b0bc5f3033c6
--- /dev/null
+++ b/dlls/dsrole/Makefile.in
@@ -0,0 +1,5 @@
+MODULE    = dsrole.dll
+IMPORTS   = advapi32
+
+SOURCES = \
+	dsrole.c
diff --git a/dlls/dsrole/dsrole.c b/dlls/dsrole/dsrole.c
new file mode 100644
index 000000000000..f3aef1d7b0e2
--- /dev/null
+++ b/dlls/dsrole/dsrole.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2001 Mike McCormack
+ * Copyright 2002 Andriy Palamarchuk
+ * Copyright 2003 Juan Lang
+ * Copyright 2005,2006 Paul Vriens
+ * Copyright 2006 Robert Reif
+ * Copyright 2013 Hans Leidekker for CodeWeavers
+ * Copyright 2020 Dmitry Timoshkov
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+
+#include "ntstatus.h"
+#include "windef.h"
+#include "winbase.h"
+#include "ntsecapi.h"
+
+#include "dsrole.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dsrole);
+
+/************************************************************
+ *  DsRoleFreeMemory (dsrole.@)
+ */
+void WINAPI DsRoleFreeMemory(void *buffer)
+{
+    TRACE("(%p)\n", buffer);
+    HeapFree(GetProcessHeap(), 0, buffer);
+}
+
+/************************************************************
+ *  DsRoleGetPrimaryDomainInformation (dsrole.@)
+ */
+DWORD WINAPI DsRoleGetPrimaryDomainInformation(
+    LPCWSTR lpServer, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
+    PBYTE* Buffer)
+{
+    DWORD ret;
+
+    FIXME("(%p, %d, %p) stub\n", lpServer, InfoLevel, Buffer);
+
+    /* Check some input parameters */
+
+    if (!Buffer) return ERROR_INVALID_PARAMETER;
+    if ((InfoLevel < DsRolePrimaryDomainInfoBasic) || (InfoLevel > DsRoleOperationState)) return ERROR_INVALID_PARAMETER;
+
+    *Buffer = NULL;
+    switch (InfoLevel)
+    {
+        case DsRolePrimaryDomainInfoBasic:
+        {
+            LSA_OBJECT_ATTRIBUTES ObjectAttributes;
+            LSA_HANDLE PolicyHandle;
+            PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
+            NTSTATUS NtStatus;
+            int logon_domain_sz;
+            DWORD size;
+            PDSROLE_PRIMARY_DOMAIN_INFO_BASIC basic;
+
+            ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
+            NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes,
+             POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
+            if (NtStatus != STATUS_SUCCESS)
+            {
+                TRACE("LsaOpenPolicyFailed with NT status %lx\n",
+                    LsaNtStatusToWinError(NtStatus));
+                return ERROR_OUTOFMEMORY;
+            }
+            LsaQueryInformationPolicy(PolicyHandle,
+             PolicyAccountDomainInformation, (PVOID*)&DomainInfo);
+            logon_domain_sz = lstrlenW(DomainInfo->DomainName.Buffer) + 1;
+            LsaClose(PolicyHandle);
+
+            size = sizeof(DSROLE_PRIMARY_DOMAIN_INFO_BASIC) +
+             logon_domain_sz * sizeof(WCHAR);
+            basic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
+            if (basic)
+            {
+                basic->MachineRole = DsRole_RoleStandaloneWorkstation;
+                basic->DomainNameFlat = (LPWSTR)((LPBYTE)basic +
+                 sizeof(DSROLE_PRIMARY_DOMAIN_INFO_BASIC));
+                lstrcpyW(basic->DomainNameFlat, DomainInfo->DomainName.Buffer);
+                ret = ERROR_SUCCESS;
+            }
+            else
+                ret = ERROR_OUTOFMEMORY;
+            *Buffer = (PBYTE)basic;
+            LsaFreeMemory(DomainInfo);
+        }
+        break;
+    default:
+        ret = ERROR_CALL_NOT_IMPLEMENTED;
+    }
+    return ret;
+}
diff --git a/dlls/dsrole/dsrole.spec b/dlls/dsrole/dsrole.spec
new file mode 100644
index 000000000000..fae35b0b4119
--- /dev/null
+++ b/dlls/dsrole/dsrole.spec
@@ -0,0 +1,2 @@
+@ stdcall DsRoleFreeMemory(ptr)
+@ stdcall DsRoleGetPrimaryDomainInformation(wstr long ptr)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c
index dc434949c42c..c991b8d0d4be 100644
--- a/dlls/dwrite/analyzer.c
+++ b/dlls/dwrite/analyzer.c
@@ -308,12 +308,19 @@ system_fallback_config[] =
     { "1C00-1C4F",              L"Noto Sans Lepcha" },
     { "1C50-1C7F",              L"Noto Sans Ol Chiki" },
 
+    /* Arrows - 2190-21FF */
+    { "2190-21FF",              L"Noto Sans Symbols" },
+
     /* Miscellaneous Symbols - 2600-26FF */
-    { "2600-26FF",              L"Noto Sans Symbols2, Noto Sans Symbols" },
+    { "2600-26FF",              L"Noto Sans Symbols2, Noto Sans Symbols 2, Noto Sans Symbols" },
 
     /* Dingbats - 2700-27BF */
     { "2700-27BF",              L"Noto Sans Symbols2, Noto Sans Symbols 2" },
 
+    /* Misc Symbols and Arrows - 2B00-2BFF
+       Supplemental Arrows-C   - 1F800-1F8FF */
+    { "2B00-2BFF, 1F800-1F8FF", L"Noto Sans Symbols2, Noto Sans Symbols 2" },
+
     { "2C80-2CFF",              L"Noto Sans Coptic" },
     { "2D30-2D7F",              L"Noto Sans Tifinagh" },
 
diff --git a/dlls/dxgi/tests/dxgi.c b/dlls/dxgi/tests/dxgi.c
index ecd0661ab257..0886adf76bd8 100644
--- a/dlls/dxgi/tests/dxgi.c
+++ b/dlls/dxgi/tests/dxgi.c
@@ -878,6 +878,20 @@ static void get_factory_(unsigned int line, IUnknown *device, BOOL is_d3d12, IDX
     }
 }
 
+static BOOL dxgi_1_4_supported(IUnknown *device, BOOL is_d3d12)
+{
+    IDXGIFactory4 *factory4;
+    IDXGIFactory *factory;
+    HRESULT hr;
+
+    get_factory(device, is_d3d12, &factory);
+    if (SUCCEEDED(hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory4, (void**)&factory4)))
+        IDXGIFactory4_Release(factory4);
+    IDXGIFactory_Release(factory);
+
+    return SUCCEEDED(hr);
+}
+
 #define get_adapter(a, b) get_adapter_(__LINE__, a, b)
 static IDXGIAdapter *get_adapter_(unsigned int line, IUnknown *device, BOOL is_d3d12)
 {
@@ -7107,7 +7121,10 @@ static void test_cursor_clipping(IUnknown *device, BOOL is_d3d12)
             }
             ok(mode_idx < mode_count, "Failed to find a different mode than %ux%u.\n", width, height);
             if (mode_idx >= mode_count)
+            {
+                winetest_pop_context();
                 continue;
+            }
 
             ret = ClipCursor(NULL);
             ok(ret, "ClipCursor failed, error %#lx.\n", GetLastError());
@@ -7251,15 +7268,18 @@ static void test_frame_latency_event(IUnknown *device, BOOL is_d3d12)
     HRESULT hr;
     BOOL ret;
 
+    /* DXGI_SWAP_EFFECT_FLIP_DISCARD requires DXGI 1.4. */
+    if (!dxgi_1_4_supported(device, is_d3d12))
+    {
+        win_skip("DXGI 1.4 is not supported, skipping tests.\n");
+        return;
+    }
+
     get_factory(device, is_d3d12, &factory);
 
     hr = IDXGIFactory_QueryInterface(factory, &IID_IDXGIFactory2, (void**)&factory2);
+    ok(hr == S_OK, "Got hr %#lx.\n", hr);
     IDXGIFactory_Release(factory);
-    if (FAILED(hr))
-    {
-        win_skip("IDXGIFactory2 not available.\n");
-        return;
-    }
 
     window = create_window();
 
@@ -7984,11 +8004,16 @@ static void test_swapchain_present_count(IUnknown *device, BOOL is_d3d12)
     IDXGISwapChain *swapchain;
     ID3D12Fence *fence;
     unsigned int i;
+    BOOL dxgi_1_4;
     HWND window;
     HRESULT hr;
 
     window = create_window();
 
+    /* DXGI_SWAP_EFFECT_FLIP_DISCARD requires DXGI 1.4. */
+    if (!(dxgi_1_4 = dxgi_1_4_supported(device, is_d3d12)))
+        win_skip("DXGI 1.4 is not supported, skipping DXGI_SWAP_EFFECT_FLIP_DISCARD tests.\n");
+
     for (i = 0; i < ARRAY_SIZE(tests); ++i)
     {
         DXGI_SWAP_EFFECT swap_effect = tests[i].swap_effect;
@@ -7997,6 +8022,8 @@ static void test_swapchain_present_count(IUnknown *device, BOOL is_d3d12)
         /* D3D12 only supports flip swap effects. */
         if (is_d3d12 && (swap_effect == DXGI_SWAP_EFFECT_DISCARD))
             continue;
+        if (!dxgi_1_4 && swap_effect == DXGI_SWAP_EFFECT_FLIP_DISCARD)
+            continue;
 
         winetest_push_context("test %u", i);
 
@@ -8248,6 +8275,7 @@ static void run_on_d3d12(void (*test_func)(IUnknown *device, BOOL is_d3d12))
     if (!(device = create_d3d12_device()))
     {
         skip("Failed to create Direct3D 12 device.\n");
+        winetest_pop_context();
         return;
     }
 
diff --git a/dlls/gdi.exe16/gdi.c b/dlls/gdi.exe16/gdi.c
index 564b0484857f..38b0b12ea899 100644
--- a/dlls/gdi.exe16/gdi.c
+++ b/dlls/gdi.exe16/gdi.c
@@ -1190,12 +1190,13 @@ HDC16 WINAPI CreateDC16( LPCSTR driver, LPCSTR device, LPCSTR output,
         {
             .Width = info->bmiHeader.biWidth,
             .Height = abs( info->bmiHeader.biHeight ),
-            .Pitch = info->bmiHeader.biSizeImage / abs( info->bmiHeader.biHeight ),
         };
         struct saved_bitmap *bitmap;
         UINT status;
         int color;
 
+        desc.Pitch = ((info->bmiHeader.biWidth * info->bmiHeader.biBitCount + 31) >> 3) & ~3;
+
         if (info->bmiHeader.biBitCount <= 8)
         {
             if (info->bmiHeader.biClrUsed)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h
index cc5f823214b5..a1ed2cf7dbf1 100644
--- a/dlls/gdiplus/gdiplus_private.h
+++ b/dlls/gdiplus/gdiplus_private.h
@@ -479,7 +479,9 @@ struct GpMetafile{
     GpUnit unit;
     MetafileType metafile_type;
     HENHMETAFILE hemf;
+    HMETAFILE hwmf;
     int preserve_hemf; /* if true, hemf belongs to the app and should not be deleted */
+    int preserve_hwmf; /* if true, hwmf belongs to the app and should not be deleted */
 
     /* recording */
     HDC record_dc;
diff --git a/dlls/gdiplus/image.c b/dlls/gdiplus/image.c
index 17e1437eb5fc..4d537fd4f961 100644
--- a/dlls/gdiplus/image.c
+++ b/dlls/gdiplus/image.c
@@ -4348,7 +4348,14 @@ static GpStatus load_wmf(IStream *stream, GpMetafile **metafile)
         return GenericError;
 
     status = GdipCreateMetafileFromWmf(hmf, TRUE, is_placeable ? &pfh : NULL, metafile);
-    if (status != Ok)
+    if (status == Ok)
+    {
+        /* Windows reports raw WMF streams loaded through GdipLoadImageFromStream
+         * as EMF images.  The decoder's format choice is preserved above. */
+        if (!is_placeable)
+            (*metafile)->image.format = ImageFormatEMF;
+    }
+    else
         DeleteMetaFile(hmf);
     return status;
 }
@@ -4609,7 +4616,10 @@ GpStatus WINGDIPAPI GdipLoadImageFromStream(IStream *stream, GpImage **image)
     /* take note of the original data format */
     if (stat == Ok)
     {
-        memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
+        /* Metafile decoders may choose a more specific format (e.g. raw WMF
+         * streams are reported as EMF on Windows).  Respect that choice. */
+        if ((*image)->type != ImageTypeMetafile || IsEqualGUID(&(*image)->format, &GUID_NULL))
+            memcpy(&(*image)->format, &codec->info.FormatID, sizeof(GUID));
         return Ok;
     }
 
@@ -4880,27 +4890,85 @@ static BOOL has_encoder_param_long(GDIPCONST EncoderParameters *params, GUID par
     return FALSE;
 }
 
+static GpStatus rasterize_metafile(GpMetafile *metafile, GpBitmap **bitmap)
+{
+    GpStatus status;
+    GpBitmap *bmp;
+    GpGraphics *graphics;
+    REAL width, height;
+    INT pix_width, pix_height;
+
+    width = metafile->bounds.Width;
+    height = metafile->bounds.Height;
+
+    if (width <= 0.0f) width = 1.0f;
+    if (height <= 0.0f) height = 1.0f;
+
+    /* Cap rasterization size to avoid excessive memory use. */
+    if (width > 4096.0f || height > 4096.0f)
+    {
+        REAL scale = 4096.0f / (width > height ? width : height);
+        width *= scale;
+        height *= scale;
+    }
+
+    pix_width = (INT)width;
+    if (pix_width <= 0) pix_width = 1;
+    pix_height = (INT)height;
+    if (pix_height <= 0) pix_height = 1;
+
+    status = GdipCreateBitmapFromScan0(pix_width, pix_height, 0, PixelFormat32bppARGB, NULL, &bmp);
+    if (status != Ok) return status;
+
+    status = GdipGetImageGraphicsContext((GpImage*)bmp, &graphics);
+    if (status == Ok)
+    {
+        /* Leave the background transparent (the bitmap is already zero-
+         * initialized to 0x00000000); this matches native gdiplus behavior. */
+        status = GdipDrawImageRect(graphics, (GpImage*)metafile, 0.0f, 0.0f,
+            (REAL)pix_width, (REAL)pix_height);
+        GdipDeleteGraphics(graphics);
+    }
+
+    if (status == Ok)
+        *bitmap = bmp;
+    else
+        GdipDisposeImage((GpImage*)bmp);
+
+    return status;
+}
+
 static GpStatus encode_image_wic(GpImage *image, IStream *stream,
     REFGUID container, GDIPCONST EncoderParameters *params)
 {
     GpStatus status, terminate_status;
+    GpBitmap *rasterized = NULL;
+    GpImage *encode_image = image;
 
-    if (image->type != ImageTypeBitmap)
+    if (image->type == ImageTypeMetafile)
+    {
+        status = rasterize_metafile((GpMetafile*)image, &rasterized);
+        if (status != Ok) return status;
+        encode_image = (GpImage*)rasterized;
+    }
+    else if (image->type != ImageTypeBitmap)
         return GenericError;
 
-    status = initialize_encoder_wic(stream, container, image);
+    status = initialize_encoder_wic(stream, container, encode_image);
 
     if (status == Ok)
-        status = encode_frame_wic(image->encoder, image);
+        status = encode_frame_wic(encode_image->encoder, encode_image);
 
     if (!has_encoder_param_long(params, EncoderSaveFlag, EncoderValueMultiFrame))
     {
         /* always try to terminate, but if something already failed earlier, keep the old status. */
-        terminate_status = terminate_encoder_wic(image);
+        terminate_status = terminate_encoder_wic(encode_image);
         if (status == Ok)
             status = terminate_status;
     }
 
+    GdipDisposeImage((GpImage*)rasterized);
+
     return status;
 }
 
@@ -5108,8 +5176,16 @@ static const WCHAR wmf_codecname[] = L"Built-in WMF";
 static const WCHAR wmf_extension[] = L"*.WMF";
 static const WCHAR wmf_mimetype[] = L"image/x-wmf";
 static const WCHAR wmf_format[] = L"WMF";
-static const BYTE wmf_sig_pattern[] = { 0xd7, 0xcd };
-static const BYTE wmf_sig_mask[] = { 0xFF, 0xFF };
+static const BYTE wmf_sig_pattern[] = {
+    0xd7, 0xcd, 0xc6, 0x9a,   /* placeable WMF */
+    0x01, 0x00, 0x09, 0x00,   /* raw memory metafile */
+    0x02, 0x00, 0x09, 0x00,   /* raw disk metafile */
+};
+static const BYTE wmf_sig_mask[] = {
+    0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF,
+};
 
 static const WCHAR png_codecname[] = L"Built-in PNG";
 static const WCHAR png_extension[] = L"*.PNG";
@@ -5237,8 +5313,8 @@ static const struct image_codec codecs[NUM_CODECS] = {
             /* MimeType */           wmf_mimetype,
             /* Flags */              ImageCodecFlagsDecoder | ImageCodecFlagsSupportVector | ImageCodecFlagsBuiltin,
             /* Version */            1,
-            /* SigCount */           1,
-            /* SigSize */            2,
+            /* SigCount */           3,
+            /* SigSize */            4,
             /* SigPattern */         wmf_sig_pattern,
             /* SigMask */            wmf_sig_mask,
         },
diff --git a/dlls/gdiplus/metafile.c b/dlls/gdiplus/metafile.c
index 20adc83b95f6..83484b9a00e2 100644
--- a/dlls/gdiplus/metafile.c
+++ b/dlls/gdiplus/metafile.c
@@ -692,6 +692,8 @@ void METAFILE_Free(GpMetafile *metafile)
     DeleteEnhMetaFile(CloseEnhMetaFile(metafile->record_dc));
     if (!metafile->preserve_hemf)
         DeleteEnhMetaFile(metafile->hemf);
+    if (!metafile->preserve_hwmf)
+        DeleteMetaFile(metafile->hwmf);
     if (metafile->record_graphics)
     {
         WARN("metafile closed while recording\n");
@@ -4315,6 +4317,9 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
 
     if (retval == Ok)
     {
+        (*metafile)->hwmf = hwmf;
+        (*metafile)->preserve_hwmf = !delete;
+
         if (placeable)
         {
             (*metafile)->image.xres = (REAL)placeable->Inch;
@@ -4330,11 +4335,12 @@ GpStatus WINGDIPAPI GdipCreateMetafileFromWmf(HMETAFILE hwmf, BOOL delete,
         else
             (*metafile)->metafile_type = MetafileTypeWmf;
         (*metafile)->image.format = ImageFormatWMF;
-
-        if (delete) DeleteMetaFile(hwmf);
     }
     else
+    {
         DeleteEnhMetaFile(hemf);
+    }
+
     return retval;
 }
 
diff --git a/dlls/gdiplus/tests/image.c b/dlls/gdiplus/tests/image.c
index a1b81c8eda7e..7548ed9e725b 100644
--- a/dlls/gdiplus/tests/image.c
+++ b/dlls/gdiplus/tests/image.c
@@ -2028,6 +2028,25 @@ static const unsigned char wmfimage[180] = {
 0x00,0x00,0xf0,0x01,0x00,0x00,0x04,0x00,0x00,0x00,0xf0,0x01,0x01,0x00,0x03,0x00,
 0x00,0x00,0x00,0x00
 };
+/* 16x16 raw WMF with no drawing records, only used to verify background color. */
+static const unsigned char empty_wmf[44] = {
+0x01,0x00,0x09,0x00,0x00,0x03,0x16,0x00,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
+0x00,0x00,0x05,0x00,0x00,0x00,0x0b,0x02,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
+0x0c,0x02,0x10,0x00,0x10,0x00,0x03,0x00,0x00,0x00,0x00,0x00
+};
+/* 158-byte raw WMF (same content as wmfimage, but without the placeable header) */
+static const unsigned char raw_wmfimage[158] = {
+0x01,0x00,0x09,0x00,0x00,0x03,0x4f,0x00,0x00,0x00,0x0f,0x00,0x08,0x00,0x00,0x00,
+0x00,0x00,0x05,0x00,0x00,0x00,0x0b,0x02,0x00,0x00,0x00,0x00,0x05,0x00,0x00,0x00,
+0x0c,0x02,0x40,0x01,0x40,0x01,0x04,0x00,0x00,0x00,0x02,0x01,0x01,0x00,0x04,0x00,
+0x00,0x00,0x04,0x01,0x0d,0x00,0x08,0x00,0x00,0x00,0xfa,0x02,0x05,0x00,0x00,0x00,
+0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x2d,0x01,0x00,0x00,0x07,0x00,
+0x00,0x00,0xfc,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,
+0x2d,0x01,0x01,0x00,0x07,0x00,0x00,0x00,0xfc,0x02,0x00,0x00,0x00,0x00,0x00,0x00,
+0x00,0x00,0x04,0x00,0x00,0x00,0x2d,0x01,0x02,0x00,0x07,0x00,0x00,0x00,0x1b,0x04,
+0x40,0x01,0x40,0x01,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xf0,0x01,0x00,0x00,
+0x04,0x00,0x00,0x00,0xf0,0x01,0x01,0x00,0x03,0x00,0x00,0x00,0x00,0x00
+};
 static void test_getrawformat(void)
 {
     test_bufferrawformat((void*)pngimage, sizeof(pngimage), &ImageFormatPNG,  __LINE__, FALSE);
@@ -2183,6 +2202,358 @@ static void test_createfromwmf_noplaceable(void)
     GdipDisposeImage(img);
 }
 
+static void test_loadwmf_noplaceable(void)
+{
+    LPSTREAM stream;
+    HGLOBAL hglob;
+    LPBYTE data;
+    HRESULT hres;
+    GpStatus stat;
+    GpImage *img;
+    GUID format;
+
+    hglob = GlobalAlloc(0, sizeof(raw_wmfimage));
+    data = GlobalLock(hglob);
+    memcpy(data, raw_wmfimage, sizeof(raw_wmfimage));
+    GlobalUnlock(hglob);
+    data = NULL;
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+    if (hres != S_OK) return;
+
+    stat = GdipLoadImageFromStream(stream, &img);
+    ok(stat == Ok, "GdipLoadImageFromStream failed, status %d\n", stat);
+    IStream_Release(stream);
+    if (stat != Ok) return;
+
+    stat = GdipGetImageRawFormat(img, &format);
+    expect(Ok, stat);
+    if (stat == Ok)
+    {
+        /* Windows reports raw (non-placeable) WMF streams as EMF. */
+        ok(IsEqualGUID(&format, &ImageFormatEMF), "Expected EMF format\n");
+    }
+
+    GdipDisposeImage(img);
+}
+
+static void test_drawwmf(void)
+{
+    LPSTREAM stream;
+    HGLOBAL hglob;
+    LPBYTE data;
+    HRESULT hres;
+    GpStatus stat;
+    GpImage *img;
+    GpBitmap *bitmap;
+    GpGraphics *graphics;
+
+    hglob = GlobalAlloc(0, sizeof(raw_wmfimage));
+    data = GlobalLock(hglob);
+    memcpy(data, raw_wmfimage, sizeof(raw_wmfimage));
+    GlobalUnlock(hglob);
+    data = NULL;
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+    if (hres != S_OK) return;
+
+    stat = GdipLoadImageFromStream(stream, &img);
+    IStream_Release(stream);
+    ok(stat == Ok, "GdipLoadImageFromStream failed, status %d\n", stat);
+    if (stat != Ok) return;
+
+    stat = GdipCreateBitmapFromScan0(64, 64, 0, PixelFormat32bppARGB, NULL, &bitmap);
+    expect(Ok, stat);
+    if (stat == Ok)
+    {
+        stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+        expect(Ok, stat);
+        if (stat == Ok)
+        {
+            stat = GdipDrawImageRect(graphics, img, 0.0, 0.0, 64.0, 64.0);
+            expect(Ok, stat);
+            GdipDeleteGraphics(graphics);
+        }
+        GdipDisposeImage((GpImage*)bitmap);
+    }
+
+    GdipDisposeImage(img);
+}
+
+struct enumwmf_state
+{
+    GpMetafile *metafile;
+    unsigned int count;
+    unsigned int wmf_records;
+};
+
+static BOOL CALLBACK enumwmf_callback(EmfPlusRecordType record_type, unsigned int flags,
+    unsigned int dataSize, const unsigned char *pStr, void *userdata)
+{
+    struct enumwmf_state *state = (struct enumwmf_state*)userdata;
+    GpStatus stat;
+
+    state->count++;
+
+    if (record_type & GDIP_WMF_RECORD_BASE)
+        state->wmf_records++;
+
+    stat = GdipPlayMetafileRecord(state->metafile, record_type, flags, dataSize, pStr);
+    ok(stat == Ok, "record %u: GdipPlayMetafileRecord failed with stat %d (type 0x%x)\n",
+        state->count, stat, record_type);
+
+    return TRUE;
+}
+
+static void test_enumwmf(void)
+{
+    LPSTREAM stream;
+    HGLOBAL hglob;
+    LPBYTE data;
+    HRESULT hres;
+    GpStatus stat;
+    GpImage *img;
+    GpBitmap *bitmap;
+    GpGraphics *graphics;
+    GpPointF dst_points[3] = {{0.0, 0.0}, {64.0, 0.0}, {0.0, 64.0}};
+    GpRectF src_rect = {0.0, 0.0, 64.0, 64.0};
+    struct enumwmf_state state = {0};
+
+    hglob = GlobalAlloc(0, sizeof(raw_wmfimage));
+    data = GlobalLock(hglob);
+    memcpy(data, raw_wmfimage, sizeof(raw_wmfimage));
+    GlobalUnlock(hglob);
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+    if (hres != S_OK) return;
+
+    stat = GdipLoadImageFromStream(stream, &img);
+    IStream_Release(stream);
+    ok(stat == Ok, "GdipLoadImageFromStream failed, status %d\n", stat);
+    if (stat != Ok) return;
+
+    stat = GdipCreateBitmapFromScan0(64, 64, 0, PixelFormat32bppARGB, NULL, &bitmap);
+    expect(Ok, stat);
+    if (stat == Ok)
+    {
+        stat = GdipGetImageGraphicsContext((GpImage*)bitmap, &graphics);
+        expect(Ok, stat);
+        if (stat == Ok)
+        {
+            state.metafile = (GpMetafile*)img;
+
+            stat = GdipEnumerateMetafileSrcRectDestPoints(graphics, (GpMetafile*)img,
+                dst_points, 3, &src_rect, UnitPixel, enumwmf_callback, &state, NULL);
+            expect(Ok, stat);
+
+            /* Although the EmfPlusRecordType enum reserves a range of values
+             * for WMF record types (the GDIP_WMF_RECORD_BASE bit), Windows
+             * internally converts WMF metafiles to EMF before enumeration and
+             * reports every record using plain EMF record types. */
+            ok(state.count > 0, "Expected callback to be invoked at least once\n");
+            ok(state.wmf_records == 0,
+                "Expected no WMF-typed records, got %u of %u\n",
+                state.wmf_records, state.count);
+
+            GdipDeleteGraphics(graphics);
+        }
+        GdipDisposeImage((GpImage*)bitmap);
+    }
+
+    GdipDisposeImage(img);
+}
+
+static void test_savemetafile(void)
+{
+    static const CLSID CLSID_PngEncoder =
+        { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e } };
+    LPSTREAM stream, out_stream;
+    HGLOBAL hglob;
+    LPBYTE data;
+    HRESULT hres;
+    GpStatus stat;
+    GpImage *img;
+    STATSTG statstg;
+
+    hglob = GlobalAlloc(0, sizeof(raw_wmfimage));
+    data = GlobalLock(hglob);
+    memcpy(data, raw_wmfimage, sizeof(raw_wmfimage));
+    GlobalUnlock(hglob);
+    data = NULL;
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+    if (hres != S_OK) return;
+
+    stat = GdipLoadImageFromStream(stream, &img);
+    IStream_Release(stream);
+    ok(stat == Ok, "GdipLoadImageFromStream failed, status %d\n", stat);
+    if (stat != Ok) return;
+
+    hres = CreateStreamOnHGlobal(NULL, TRUE, &out_stream);
+    ok(hres == S_OK, "Failed to create output stream\n");
+    if (hres != S_OK)
+    {
+        GdipDisposeImage(img);
+        return;
+    }
+
+    stat = GdipSaveImageToStream(img, out_stream, &CLSID_PngEncoder, NULL);
+    ok(stat == Ok, "GdipSaveImageToStream failed, status %d\n", stat);
+
+    if (stat == Ok)
+    {
+        GpImage *loaded;
+        LARGE_INTEGER zero = {{0}};
+
+        memset(&statstg, 0, sizeof(statstg));
+        hres = IStream_Stat(out_stream, &statstg, STATFLAG_NONAME);
+        ok(hres == S_OK, "IStream_Stat failed\n");
+        ok(statstg.cbSize.QuadPart > 0, "saved PNG is empty\n");
+
+        /* Load the saved PNG back and inspect the result. */
+        IStream_Seek(out_stream, zero, STREAM_SEEK_SET, NULL);
+        stat = GdipLoadImageFromStream(out_stream, &loaded);
+        ok(stat == Ok, "Failed to load saved PNG, status %d\n", stat);
+
+        if (stat == Ok)
+        {
+            GUID format_guid;
+            PixelFormat pixel_format;
+            UINT width = 0, height = 0;
+            ARGB pixel = 0;
+
+            stat = GdipGetImageRawFormat(loaded, &format_guid);
+            expect(Ok, stat);
+            ok(IsEqualGUID(&format_guid, &ImageFormatPNG),
+                "Expected PNG format for the saved image\n");
+
+            stat = GdipGetImagePixelFormat(loaded, &pixel_format);
+            expect(Ok, stat);
+            ok(pixel_format == PixelFormat32bppARGB,
+                "Expected PixelFormat32bppARGB for the saved PNG, got %#x\n", pixel_format);
+
+            stat = GdipGetImageWidth(loaded, &width);
+            expect(Ok, stat);
+            stat = GdipGetImageHeight(loaded, &height);
+            expect(Ok, stat);
+            ok(width > 0 && height > 0,
+                "Saved PNG has invalid dimensions %ux%u\n", width, height);
+
+            /* The raw_wmfimage WMF draws a single solid black rectangle covering
+             * its entire window, so every pixel of the rasterized image should be
+             * opaque black. This both verifies that the metafile actually played
+             * back during the save (a pure-white pixel would indicate the WMF
+             * was never drawn over the rasterizer's implicit white background)
+             * and that the rasterizer doesn't lose opacity along the way. */
+            if (width > 0 && height > 0)
+            {
+                stat = GdipBitmapGetPixel((GpBitmap*)loaded, width / 2, height / 2, &pixel);
+                expect(Ok, stat);
+                ok(pixel == 0xff000000,
+                    "Expected opaque black at center, got %.8lx\n", pixel);
+            }
+
+            GdipDisposeImage(loaded);
+        }
+    }
+
+    IStream_Release(out_stream);
+    GdipDisposeImage(img);
+}
+
+static void test_savemetafile_background(void)
+{
+    static const CLSID CLSID_PngEncoder =
+        { 0x557cf406, 0x1a04, 0x11d3, { 0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e } };
+    LPSTREAM stream, out_stream;
+    HGLOBAL hglob;
+    LPBYTE data;
+    HRESULT hres;
+    GpStatus stat;
+    GpImage *img, *loaded;
+    LARGE_INTEGER zero = {{0}};
+    PixelFormat pixel_format;
+    UINT width = 0, height = 0, x, y;
+    ARGB pixel;
+
+    hglob = GlobalAlloc(0, sizeof(empty_wmf));
+    data = GlobalLock(hglob);
+    memcpy(data, empty_wmf, sizeof(empty_wmf));
+    GlobalUnlock(hglob);
+
+    hres = CreateStreamOnHGlobal(hglob, TRUE, &stream);
+    ok(hres == S_OK, "Failed to create a stream\n");
+    if (hres != S_OK) return;
+
+    stat = GdipLoadImageFromStream(stream, &img);
+    IStream_Release(stream);
+    ok(stat == Ok, "GdipLoadImageFromStream failed, status %d\n", stat);
+    if (stat != Ok) return;
+
+    hres = CreateStreamOnHGlobal(NULL, TRUE, &out_stream);
+    ok(hres == S_OK, "Failed to create output stream\n");
+    if (hres != S_OK)
+    {
+        GdipDisposeImage(img);
+        return;
+    }
+
+    stat = GdipSaveImageToStream(img, out_stream, &CLSID_PngEncoder, NULL);
+    ok(stat == Ok, "GdipSaveImageToStream failed, status %d\n", stat);
+    if (stat != Ok)
+    {
+        IStream_Release(out_stream);
+        GdipDisposeImage(img);
+        return;
+    }
+
+    /* Load the saved PNG back. */
+    IStream_Seek(out_stream, zero, STREAM_SEEK_SET, NULL);
+    stat = GdipLoadImageFromStream(out_stream, &loaded);
+    ok(stat == Ok, "Failed to load saved PNG, status %d\n", stat);
+
+    if (stat == Ok)
+    {
+        stat = GdipGetImagePixelFormat(loaded, &pixel_format);
+        expect(Ok, stat);
+        ok(pixel_format == PixelFormat32bppARGB,
+            "Expected PixelFormat32bppARGB for the saved PNG, got %#x\n", pixel_format);
+
+        stat = GdipGetImageWidth(loaded, &width);
+        expect(Ok, stat);
+        stat = GdipGetImageHeight(loaded, &height);
+        expect(Ok, stat);
+        ok(width > 0 && height > 0,
+            "Saved PNG has invalid dimensions %ux%u\n", width, height);
+
+        /* The empty WMF performs no drawing, so every pixel of the rasterized
+         * output should be the rasterizer's implicit background color, which
+         * native gdiplus leaves as the zero-initialized transparent black. */
+        for (y = 0; y < height; y++)
+        {
+            for (x = 0; x < width; x++)
+            {
+                pixel = 0xdeadbeef;
+                stat = GdipBitmapGetPixel((GpBitmap*)loaded, x, y, &pixel);
+                expect(Ok, stat);
+                ok(pixel == 0x00000000,
+                    "Expected transparent background at (%u,%u), got %.8lx\n",
+                    x, y, pixel);
+                if (pixel != 0x00000000) goto done;
+            }
+        }
+done:
+        GdipDisposeImage(loaded);
+    }
+
+    IStream_Release(out_stream);
+    GdipDisposeImage(img);
+}
+
 static void test_resolution(void)
 {
     GpStatus stat;
@@ -6893,6 +7264,11 @@ START_TEST(image)
     test_loadwmf();
     test_createfromwmf();
     test_createfromwmf_noplaceable();
+    test_loadwmf_noplaceable();
+    test_drawwmf();
+    test_enumwmf();
+    test_savemetafile();
+    test_savemetafile_background();
     test_resolution();
     test_createhbitmap();
     test_getthumbnail();
diff --git a/dlls/imm32/ime.c b/dlls/imm32/ime.c
index 3cf7c1ed00a3..b407de2c33d0 100644
--- a/dlls/imm32/ime.c
+++ b/dlls/imm32/ime.c
@@ -534,7 +534,19 @@ BOOL WINAPI ImeSelect( HIMC himc, BOOL select )
 
 BOOL WINAPI ImeSetActiveContext( HIMC himc, BOOL flag )
 {
+    INPUTCONTEXT *ctx;
+    UINT msg;
+
     TRACE( "himc %p, flag %#x stub!\n", himc, flag );
+    if (!flag && (msg = ime_set_composition_status( himc, FALSE )))
+    {
+        if ((ctx = ImmLockIMC( himc )))
+        {
+            input_context_set_comp_str( ctx, NULL, 0 );
+            ImmUnlockIMC( himc );
+        }
+        ime_send_message( himc, msg, 0, 0 );
+    }
     return TRUE;
 }
 
@@ -683,8 +695,11 @@ BOOL WINAPI ImeSetCompositionString( HIMC himc, DWORD index, const void *comp, D
     {
         UINT msg, flags = GCS_COMPSTR | GCS_COMPCLAUSE | GCS_COMPATTR | GCS_DELTASTART | GCS_CURSORPOS;
         WCHAR wparam = comp && comp_len >= sizeof(WCHAR) ? *(WCHAR *)comp : 0;
-        input_context_set_comp_str( ctx, comp, comp_len / sizeof(WCHAR) );
-        if ((msg = ime_set_composition_status( himc, TRUE ))) ime_send_message( himc, msg, 0, 0 );
+        DWORD len = comp_len / sizeof(WCHAR);
+
+        while (len && comp && !((WCHAR *)comp)[len - 1]) --len;
+        input_context_set_comp_str( ctx, comp, len );
+        if ((msg = ime_set_composition_status( himc, !!len ))) ime_send_message( himc, msg, 0, 0 );
         ime_send_message( himc, WM_IME_COMPOSITION, wparam, flags );
     }
 
diff --git a/dlls/imm32/tests/imm32.c b/dlls/imm32/tests/imm32.c
index c4d1404f3ea5..90960609069b 100644
--- a/dlls/imm32/tests/imm32.c
+++ b/dlls/imm32/tests/imm32.c
@@ -1083,26 +1083,107 @@ static void test_SCS_SETSTR(void)
     LONG alen,wlen;
     BOOL ret;
     DWORD prop;
+    imm_msgs *msg;
+    BOOL ends_comp_in_set, empty_string_fails;
 
     imc = ImmGetContext(hwnd);
+    flush_events();
+    msg_spy_flush_msgs();
     ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
     if (!ret) {
         win_skip("Composition isn't supported\n");
         ImmReleaseContext(hwnd, imc);
         return;
     }
+    msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+    ok(!!msg, "did not find  WM_IME_STARTCOMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+    ok(!!msg, "did not find WM_IME_COMPOSITION.\n");
+    /* Before Win10 1909 WM_IME_ENDCOMPOSITION arrives after ImmSetCompositionStringW with non-empty string. On the
+     * newer Windows version WM_IME_ENDCOMPOSITION is only sent when the composition string is cleared or context
+     * is deactivated. */
+    ends_comp_in_set = !!msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
 
+    msg_spy_flush_msgs();
     ret = ImmSetCompositionStringW(imc, SCS_SETSTR, NULL, 128, NULL, 128);
     ok(ret, "got error %lu.\n", GetLastError());
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!!msg || broken(ends_comp_in_set && !msg), "did not find WM_IME_ENDCOMPOSITION.\n");
 
     alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
     ok(!alen, "got %ld.\n", alen);
     wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
     ok(!wlen, "got %ld.\n", alen);
 
+    msg_spy_flush_msgs();
+    ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 0);
+    ok(ret, "got error %lu.\n", GetLastError());
+    msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+    ok(!!msg, "did not find  WM_IME_STARTCOMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+    ok(!!msg, "did not find WM_IME_COMPOSITION.\n");
+
+    msg_spy_flush_msgs();
+    ret = ImmSetCompositionStringW(imc, SCS_SETSTR, L"12", 6, NULL, 0);
+    ok(ret, "got error %lu.\n", GetLastError());
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!msg || broken(ends_comp_in_set && msg), "found WM_IME_ENDCOMPOSITION.\n");
+
+    alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
+    ok(alen == 2 || broken(ends_comp_in_set && !alen), "got %ld.\n", alen);
+    wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
+    ok(wlen == 4 || broken(ends_comp_in_set && !wlen), "got %ld.\n", wlen);
+
+    msg_spy_flush_msgs();
+    ret = ImmSetCompositionStringW(imc, SCS_SETSTR, L"", 2, NULL, 0);
+    /* Such SCS_SETSTR on Windows with Korean MS IME. */
+    empty_string_fails = !ret;
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!!msg || broken((ends_comp_in_set || empty_string_fails) && !msg), "did not find WM_IME_ENDCOMPOSITION.\n");
+
+    alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
+    ok(!alen || broken(empty_string_fails && alen == 2), "got %ld.\n", alen);
+    wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
+    ok(!wlen || broken(empty_string_fails && wlen == 4), "got %ld.\n", wlen);
+
+    msg_spy_flush_msgs();
+    ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 2);
+    ok(ret, "got error %lu.\n", GetLastError());
+    msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+    ok(!!msg || broken(empty_string_fails && !msg), "did not find WM_IME_STARTCOMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+    ok(!!msg, "did not find WM_IME_COMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!msg || broken(ends_comp_in_set && msg), "found WM_IME_ENDCOMPOSITION.\n");
+
+    msg_spy_flush_msgs();
+    ImmSetActiveContext( hwnd, imc, FALSE );
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!!msg || broken(ends_comp_in_set && !msg), "did not find WM_IME_ENDCOMPOSITION.\n");
+    alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
+    ok(!alen, "got %ld.\n", alen);
+    wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR, wstring, 20);
+    ok(!wlen, "got %ld.\n", alen);
+
+    msg_spy_flush_msgs();
+    ImmSetActiveContext( hwnd, imc, TRUE );
+    msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+    ok(!msg, "found WM_IME_STARTCOMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+    ok(!msg, "did not find WM_IME_COMPOSITION.\n");
+
+    msg_spy_flush_msgs();
+
     ret = ImmSetCompositionStringW(imc, SCS_SETSTR, string, sizeof(string), NULL, 2);
     ok(ret, "got error %lu.\n", GetLastError());
+    msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+    ok(!!msg, "did not find WM_IME_STARTCOMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+    ok(!!msg, "did not find WM_IME_COMPOSITION.\n");
+    msg = msg_spy_find_msg(WM_IME_ENDCOMPOSITION);
+    ok(!msg || broken(ends_comp_in_set && msg), "found WM_IME_ENDCOMPOSITION.\n");
 
+    process_messages();
     msg_spy_flush_msgs();
 
     alen = ImmGetCompositionStringA(imc, GCS_COMPSTR, cstring, 20);
@@ -1170,9 +1251,19 @@ static void test_SCS_SETSTR(void)
         imc = ImmGetContext(hwnd);
         msg_spy_flush_msgs();
 
+        msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+        ok(!msg, "found WM_IME_COMPOSITION.\n");
+        msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+        ok(!msg, "found WM_IME_STARTCOMPOSITION.\n");
         ret = ImmSetCompositionStringW(imc, SCS_SETSTR,
                                        string, sizeof(string), NULL,0);
         ok(ret, "ImmSetCompositionStringW failed\n");
+
+        msg = msg_spy_find_msg(WM_IME_STARTCOMPOSITION);
+        ok(!msg, "found WM_IME_STARTCOMPOSITION.\n");
+        msg = msg_spy_find_msg(WM_IME_COMPOSITION);
+        ok(!!msg, "did not find WM_IME_COMPOSITION.\n");
+
         wlen = ImmGetCompositionStringW(imc, GCS_COMPSTR,
                                         wstring, sizeof(wstring));
         if (wlen > 0) {
@@ -6491,6 +6582,7 @@ static void test_ImmSetCompositionWindow(void)
     hwnd = CreateWindowW( test_class.lpszClassName, NULL, WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                           100, 100, 100, 100, NULL, NULL, NULL, NULL );
     ok( !!hwnd, "CreateWindowW failed, error %lu\n", GetLastError() );
+    flush_events();
 
     ok_ret( 1, ImmActivateLayout( hkl ) );
     ok_ret( 1, ImmLoadIME( hkl ) );
diff --git a/dlls/iyuv_32/Makefile.in b/dlls/iyuv_32/Makefile.in
index e5a261b973ff..427c1e8e3985 100644
--- a/dlls/iyuv_32/Makefile.in
+++ b/dlls/iyuv_32/Makefile.in
@@ -1,6 +1,9 @@
 MODULE       = iyuv_32.dll
-IMPORTS      = user32 mfplat ole32 winegstreamer
+IMPORTS      = $(FFMPEG_PE_LIBS) user32 combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid
+EXTRAINCL    = $(FFMPEG_PE_CFLAGS)
+PARENTSRC    = ../colorcnv
 
 SOURCES = \
+	color_converter.c \
 	iyuv.c \
 	iyuv_32.rc
diff --git a/dlls/iyuv_32/iyuv.c b/dlls/iyuv_32/iyuv.c
index f990a5bd6a1a..6c9a8b43a51f 100644
--- a/dlls/iyuv_32/iyuv.c
+++ b/dlls/iyuv_32/iyuv.c
@@ -26,9 +26,10 @@
 #include "wingdi.h"
 #include "winuser.h"
 
+#define COBJMACROS
 #include "commdlg.h"
-#include "initguid.h"
 #include "vfw.h"
+#include "unknwn.h"
 #include "wmcodecdsp.h"
 
 #include "iyuv_private.h"
@@ -45,6 +46,9 @@ static HINSTANCE IYUV_32_module;
 
 #define compare_fourcc(fcc1, fcc2) (((fcc1) ^ (fcc2)) & ~0x20202020)
 
+/* in dlls/colorcnv/color_converter.c */
+extern IClassFactory color_converter_factory;
+
 static inline UINT64 make_uint64(UINT32 high, UINT32 low)
 {
     return ((UINT64)high << 32) | low;
@@ -59,7 +63,7 @@ static LRESULT IYUV_Open(const ICINFO *icinfo)
     if (icinfo && compare_fourcc(icinfo->fccType, ICTYPE_VIDEO))
         return 0;
 
-    if (FAILED(winegstreamer_create_color_converter(&transform)))
+    if (FAILED(IClassFactory_CreateInstance(&color_converter_factory, NULL, &IID_IMFTransform, (void **)&transform)))
         transform = NULL;
 
     return (LRESULT)transform;
diff --git a/dlls/iyuv_32/iyuv_private.h b/dlls/iyuv_32/iyuv_private.h
index 694f89799d59..a58482f7a0d0 100644
--- a/dlls/iyuv_32/iyuv_private.h
+++ b/dlls/iyuv_32/iyuv_private.h
@@ -25,8 +25,6 @@
 #include "mfapi.h"
 #include "mftransform.h"
 
-HRESULT WINAPI winegstreamer_create_color_converter(IMFTransform **out);
-
 #define IDS_NAME        100
 #define IDS_DESCRIPTION 101
 
diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c
index d667ae6b5b06..42fa7bbcf220 100644
--- a/dlls/joy.cpl/main.c
+++ b/dlls/joy.cpl/main.c
@@ -60,7 +60,6 @@ static CRITICAL_SECTION_DEBUG joy_cs_debug =
 static CRITICAL_SECTION joy_cs = { &joy_cs_debug, -1, 0, 0, 0, 0 };
 
 static struct list devices = LIST_INIT( devices );
-static HDEVNOTIFY devnotify;
 
 /*********************************************************************
  *  DllMain
@@ -305,7 +304,7 @@ static INT_PTR CALLBACK list_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
         disable_hidraw = get_advanced_option( L"DisableHidraw", FALSE );
         SendMessageW( GetDlgItem( hwnd, IDC_DISABLE_HIDRAW ), BM_SETCHECK, disable_hidraw, 0 );
 
-        devnotify = RegisterDeviceNotificationW( hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE );
+        RegisterDeviceNotificationW( hwnd, &filter, DEVICE_NOTIFY_WINDOW_HANDLE );
         return TRUE;
     }
 
diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c
index 939c9b62772a..ceaf14154f75 100644
--- a/dlls/kernel32/tests/actctx.c
+++ b/dlls/kernel32/tests/actctx.c
@@ -72,7 +72,7 @@ static NTSTATUS(NTAPI *pRtlQueryInformationActiveActivationContext)(ULONG,PVOID,
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c
index 9d730b3e65ea..b08c3173eced 100644
--- a/dlls/kernel32/tests/fiber.c
+++ b/dlls/kernel32/tests/fiber.c
@@ -133,8 +133,14 @@ static void test_ConvertThreadToFiber(void)
 
     if (pConvertThreadToFiber)
     {
+        ok( !NtCurrentTeb()->HasFiberData, "already a fiber\n" );
+        ok( !NtCurrentTeb()->Tib.FiberData || NtCurrentTeb()->Tib.FiberData == (void *)0x1e00,
+            "wrong data %p\n", NtCurrentTeb()->Tib.FiberData );
         fibers[0] = pConvertThreadToFiber(&testparam);
         ok(fibers[0] != NULL, "ConvertThreadToFiber failed with error %lu\n", GetLastError());
+        ok( NtCurrentTeb()->HasFiberData, "not a fiber\n" );
+        ok( NtCurrentTeb()->Tib.FiberData && NtCurrentTeb()->Tib.FiberData != (void *)0x1e00,
+            "wrong data %p\n", NtCurrentTeb()->Tib.FiberData );
 
         SetLastError(0xdeadbeef);
         ret = pConvertThreadToFiber(&testparam);
@@ -153,8 +159,12 @@ static void test_ConvertThreadToFiberEx(void)
 
     if (pConvertThreadToFiberEx)
     {
+        ok( !NtCurrentTeb()->HasFiberData, "already a fiber\n" );
         fibers[0] = pConvertThreadToFiberEx(&testparam, 0);
         ok(fibers[0] != NULL, "ConvertThreadToFiberEx failed with error %lu\n", GetLastError());
+        ok( NtCurrentTeb()->HasFiberData, "not a fiber\n" );
+        ok( NtCurrentTeb()->Tib.FiberData && NtCurrentTeb()->Tib.FiberData != (void *)0x1e00,
+            "wrong data %p\n", NtCurrentTeb()->Tib.FiberData );
 
         SetLastError(0xdeadbeef);
         ret = pConvertThreadToFiberEx(&testparam, 0);
@@ -171,8 +181,15 @@ static void test_ConvertFiberToThread(void)
 {
     if (pConvertFiberToThread)
     {
-        BOOL ret = pConvertFiberToThread();
+        BOOL ret;
+        ok( NtCurrentTeb()->HasFiberData, "not a fiber\n" );
+        ret = pConvertFiberToThread();
         ok(ret, "ConvertFiberToThread failed with error %lu\n", GetLastError());
+        ok( !NtCurrentTeb()->HasFiberData, "still a fiber\n" );
+        ok( !NtCurrentTeb()->Tib.FiberData, "wrong data %p\n", NtCurrentTeb()->Tib.FiberData );
+        ret = pConvertFiberToThread();
+        ok(!ret, "Got non NULL ret.\n");
+        ok(GetLastError() == ERROR_ALREADY_THREAD, "Got unexpected error %lu.\n", GetLastError());
     }
     else
     {
@@ -182,6 +199,9 @@ static void test_ConvertFiberToThread(void)
 
 static void test_FiberHandling(void)
 {
+    ok( !NtCurrentTeb()->HasFiberData, "already a fiber\n" );
+    ok( NtCurrentTeb()->Tib.FiberData == (void *)0x1e00, "wrong data %p\n", NtCurrentTeb()->Tib.FiberData );
+
     fiberCount = 0;
     fibers[0] = pCreateFiber(0,FiberMainProc,&testparam);
     ok(fibers[0] != NULL, "CreateFiber failed with error %lu\n", GetLastError());
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index ed6e0606f1e5..8dac53384bb2 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -2316,7 +2316,7 @@ static void test_LockFile(void)
     ok( status == STATUS_ACCESS_VIOLATION, "got %#lx.\n", status );
     memset( &iosb, 0xcc, sizeof(iosb) );
     status = NtUnlockFile( handle, &iosb, &count, &offset, NULL );
-    todo_wine_if(NT_ERROR(status)) ok( status == STATUS_RANGE_NOT_LOCKED, "got %#lx.\n", status );
+    ok( status == STATUS_RANGE_NOT_LOCKED, "got %#lx.\n", status );
     ok( iosb.Status == status, "got %lu.\n", iosb.Status);
     ok( !iosb.Information, "got %Iu.\n", iosb.Information);
 
@@ -2346,6 +2346,14 @@ static void test_LockFile(void)
     ret = LockFile( handle, 5, 0, 5, 0 );
     ok( ret, "got error %lu.\n", GetLastError() );
     count.QuadPart = 5;
+    offset.QuadPart = 4;
+    status = NtUnlockFile( handle, &iosb, &count, &offset, NULL );
+    ok( status == STATUS_RANGE_NOT_LOCKED, "got %#lx.\n", status );
+    count.QuadPart = 4;
+    offset.QuadPart = 5;
+    status = NtUnlockFile( handle, &iosb, &count, &offset, NULL );
+    ok( status == STATUS_RANGE_NOT_LOCKED, "got %#lx.\n", status );
+    count.QuadPart = 5;
     offset.QuadPart = 5;
     memset( &iosb, 0xcc, sizeof(iosb) );
     status = NtUnlockFile( handle, &iosb, &count, &offset, NULL );
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c
index aa1833504d83..4629786ddb53 100644
--- a/dlls/kernel32/tests/path.c
+++ b/dlls/kernel32/tests/path.c
@@ -47,7 +47,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c
index 130409158177..9a8ce88411f8 100644
--- a/dlls/kernelbase/thread.c
+++ b/dlls/kernelbase/thread.c
@@ -1151,12 +1151,15 @@ BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void)
 {
     struct fiber_data *fiber = NtCurrentTeb()->Tib.FiberData;
 
-    if (fiber)
+    if (!NtCurrentTeb()->HasFiberData)
     {
-        relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack );
-        NtCurrentTeb()->Tib.FiberData = NULL;
-        HeapFree( GetProcessHeap(), 0, fiber );
+        SetLastError( ERROR_ALREADY_THREAD );
+        return FALSE;
     }
+    relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack );
+    NtCurrentTeb()->Tib.FiberData = NULL;
+    NtCurrentTeb()->HasFiberData = FALSE;
+    HeapFree( GetProcessHeap(), 0, fiber );
     return TRUE;
 }
 
@@ -1177,7 +1180,7 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag
 {
     struct fiber_data *fiber;
 
-    if (NtCurrentTeb()->Tib.FiberData)
+    if (NtCurrentTeb()->HasFiberData)
     {
         SetLastError( ERROR_ALREADY_FIBER );
         return NULL;
@@ -1198,6 +1201,7 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag
     fiber->fls_slots        = NtCurrentTeb()->FlsSlots;
     relocate_thread_actctx_stack( &fiber->actctx.stack_space );
     NtCurrentTeb()->Tib.FiberData = fiber;
+    NtCurrentTeb()->HasFiberData = TRUE;
     return fiber;
 }
 
@@ -1228,7 +1232,7 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr )
  */
 BOOL WINAPI DECLSPEC_HOTPATCH IsThreadAFiber(void)
 {
-    return NtCurrentTeb()->Tib.FiberData != NULL;
+    return NtCurrentTeb()->HasFiberData;
 }
 
 
diff --git a/dlls/ksecdd.sys/ksecdd.sys.spec b/dlls/ksecdd.sys/ksecdd.sys.spec
index 31b1b35d71a1..a4654d6b14a0 100644
--- a/dlls/ksecdd.sys/ksecdd.sys.spec
+++ b/dlls/ksecdd.sys/ksecdd.sys.spec
@@ -3,41 +3,41 @@
 @ stub AcquireCredentialsHandleW
 @ stub AddCredentialsW
 @ stub ApplyControlToken
-@ stub BCryptCloseAlgorithmProvider
-@ stub BCryptCreateHash
-@ stub BCryptDecrypt
-@ stub BCryptDeriveKey
-@ stub BCryptDeriveKeyCapi
-@ stub BCryptDeriveKeyPBKDF2
-@ stub BCryptDestroyHash
-@ stub BCryptDestroyKey
-@ stub BCryptDestroySecret
-@ stub BCryptDuplicateHash
-@ stub BCryptDuplicateKey
-@ stub BCryptEncrypt
-@ stub BCryptEnumAlgorithms
+@ stdcall BCryptCloseAlgorithmProvider(ptr long) bcrypt.BCryptCloseAlgorithmProvider
+@ stdcall BCryptCreateHash(ptr ptr ptr long ptr long long) bcrypt.BCryptCreateHash
+@ stdcall BCryptDecrypt(ptr ptr long ptr ptr long ptr long ptr long) bcrypt.BCryptDecrypt
+@ stdcall BCryptDeriveKey(ptr wstr ptr ptr long ptr long) bcrypt.BCryptDeriveKey
+@ stdcall BCryptDeriveKeyCapi(ptr ptr ptr long long) bcrypt.BCryptDeriveKeyCapi
+@ stdcall BCryptDeriveKeyPBKDF2(ptr ptr long ptr long int64 ptr long long) bcrypt.BCryptDeriveKeyPBKDF2
+@ stdcall BCryptDestroyHash(ptr) bcrypt.BCryptDestroyHash
+@ stdcall BCryptDestroyKey(ptr) bcrypt.BCryptDestroyKey
+@ stdcall BCryptDestroySecret(ptr) bcrypt.BCryptDestroySecret
+@ stdcall BCryptDuplicateHash(ptr ptr ptr long long) bcrypt.BCryptDuplicateHash
+@ stdcall BCryptDuplicateKey(ptr ptr ptr long long) bcrypt.BCryptDuplicateKey
+@ stdcall BCryptEncrypt(ptr ptr long ptr ptr long ptr long ptr long) bcrypt.BCryptEncrypt
+@ stdcall BCryptEnumAlgorithms(long ptr ptr long) bcrypt.BCryptEnumAlgorithms
 @ stub BCryptEnumProviders
-@ stub BCryptExportKey
-@ stub BCryptFinalizeKeyPair
-@ stub BCryptFinishHash
-@ stub BCryptFreeBuffer
-@ stub BCryptGenRandom
-@ stub BCryptGenerateKeyPair
-@ stub BCryptGenerateSymmetricKey
-@ stub BCryptGetFipsAlgorithmMode
-@ stub BCryptGetProperty
-@ stub BCryptHashData
-@ stub BCryptImportKey
-@ stub BCryptImportKeyPair
-@ stub BCryptKeyDerivation
-@ stub BCryptOpenAlgorithmProvider
+@ stdcall BCryptExportKey(ptr ptr wstr ptr long ptr long) bcrypt.BCryptExportKey
+@ stdcall BCryptFinalizeKeyPair(ptr long) bcrypt.BCryptFinalizeKeyPair
+@ stdcall BCryptFinishHash(ptr ptr long long) bcrypt.BCryptFinishHash
+@ stdcall BCryptFreeBuffer(ptr) bcrypt.BCryptFreeBuffer
+@ stdcall BCryptGenRandom(ptr ptr long long) bcrypt.BCryptGenRandom
+@ stdcall BCryptGenerateKeyPair(ptr ptr long long) bcrypt.BCryptGenerateKeyPair
+@ stdcall BCryptGenerateSymmetricKey(ptr ptr ptr long ptr long long) bcrypt.BCryptGenerateSymmetricKey
+@ stdcall BCryptGetFipsAlgorithmMode(ptr) bcrypt.BCryptGetFipsAlgorithmMode
+@ stdcall BCryptGetProperty(ptr wstr ptr long ptr long) bcrypt.BCryptGetProperty
+@ stdcall BCryptHashData(ptr ptr long long) bcrypt.BCryptHashData
+@ stdcall BCryptImportKey(ptr ptr wstr ptr ptr long ptr long long) bcrypt.BCryptImportKey
+@ stdcall BCryptImportKeyPair(ptr ptr wstr ptr ptr long long) bcrypt.BCryptImportKeyPair
+@ stdcall BCryptKeyDerivation(ptr ptr ptr long ptr long) bcrypt.BCryptKeyDerivation
+@ stdcall BCryptOpenAlgorithmProvider(ptr wstr wstr long) bcrypt.BCryptOpenAlgorithmProvider
 @ stub BCryptRegisterConfigChangeNotify
 @ stub BCryptResolveProviders
-@ stub BCryptSecretAgreement
-@ stub BCryptSetProperty
-@ stub BCryptSignHash
+@ stdcall BCryptSecretAgreement(ptr ptr ptr long) bcrypt.BCryptSecretAgreement
+@ stdcall BCryptSetProperty(ptr wstr ptr long long) bcrypt.BCryptSetProperty
+@ stdcall BCryptSignHash(ptr ptr ptr long ptr long ptr long) bcrypt.BCryptSignHash
 @ stub BCryptUnregisterConfigChangeNotify
-@ stub BCryptVerifySignature
+@ stdcall BCryptVerifySignature(ptr ptr ptr long ptr long long) bcrypt.BCryptVerifySignature
 @ stub CompleteAuthToken
 @ stub CredMarshalTargetInfo
 @ stub DeleteSecurityContext
diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c
index 5b9db4815468..a6a257b9cca6 100644
--- a/dlls/mf/tests/mf.c
+++ b/dlls/mf/tests/mf.c
@@ -5154,7 +5154,6 @@ static IMFTimerVtbl MFTimerVtbl =
 DEFINE_EXPECT(presentation_clock_AddClockStateSink);
 DEFINE_EXPECT(presentation_clock_RemoveClockStateSink);
 DEFINE_EXPECT(presentation_clock_GetTimeSource);
-DEFINE_EXPECT(presentation_clock_SetTimeSource);
 
 static struct presentation_clock* impl_from_IMFPresentationClock(IMFPresentationClock *iface)
 {
@@ -5242,7 +5241,7 @@ static WINAPI HRESULT presentation_clock_SetTimeSource(IMFPresentationClock *ifa
 {
     struct presentation_clock *pc = impl_from_IMFPresentationClock(iface);
 
-    CHECK_EXPECT(presentation_clock_SetTimeSource);
+    ok(0, "Unexpected call.\n");
     if (pc->time_source) IMFPresentationTimeSource_Release(pc->time_source);
     IMFPresentationTimeSource_AddRef(pc->time_source = time_source);
     return S_OK;
diff --git a/dlls/mf/tests/topology.c b/dlls/mf/tests/topology.c
index eeb9169c668e..6487cd9682b5 100644
--- a/dlls/mf/tests/topology.c
+++ b/dlls/mf/tests/topology.c
@@ -697,10 +697,6 @@ static HRESULT WINAPI test_transform_create(UINT input_count, IMFMediaType **inp
     return S_OK;
 }
 
-DEFINE_EXPECT(test_source_BeginGetEvent);
-DEFINE_EXPECT(test_source_QueueEvent);
-DEFINE_EXPECT(test_source_Start);
-
 struct test_source
 {
     IMFMediaSource IMFMediaSource_iface;
@@ -761,7 +757,7 @@ static HRESULT WINAPI test_source_GetEvent(IMFMediaSource *iface, DWORD flags, I
 static HRESULT WINAPI test_source_BeginGetEvent(IMFMediaSource *iface, IMFAsyncCallback *callback, IUnknown *state)
 {
     struct test_source *source = impl_from_IMFMediaSource(iface);
-    CHECK_EXPECT(test_source_BeginGetEvent);
+    ok(0, "Unexpected call.\n");
     return source->begin_get_event_res;
 }
 
@@ -774,7 +770,7 @@ static HRESULT WINAPI test_source_EndGetEvent(IMFMediaSource *iface, IMFAsyncRes
 static HRESULT WINAPI test_source_QueueEvent(IMFMediaSource *iface, MediaEventType event_type, REFGUID ext_type,
         HRESULT hr, const PROPVARIANT *value)
 {
-    CHECK_EXPECT(test_source_QueueEvent);
+    ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
 
@@ -793,7 +789,7 @@ static HRESULT WINAPI test_source_CreatePresentationDescriptor(IMFMediaSource *i
 static HRESULT WINAPI test_source_Start(IMFMediaSource *iface, IMFPresentationDescriptor *pd, const GUID *time_format,
         const PROPVARIANT *start_position)
 {
-    CHECK_EXPECT(test_source_Start);
+    ok(0, "Unexpected call.\n");
     return E_NOTIMPL;
 }
 
diff --git a/dlls/mf/tests/transform.c b/dlls/mf/tests/transform.c
index b92652dcfd3c..4dcff7ef8cc9 100644
--- a/dlls/mf/tests/transform.c
+++ b/dlls/mf/tests/transform.c
@@ -6207,7 +6207,7 @@ static void test_audio_convert(void)
         ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 22050),
         ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 8),
         ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 22050 * 8),
-        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
+        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
         ATTR_UINT32(MF_MT_AUDIO_CHANNEL_MASK, 3, .todo = TRUE),
         {0},
     };
@@ -6220,8 +6220,8 @@ static void test_audio_convert(void)
         ATTR_UINT32(MF_MT_AUDIO_SAMPLES_PER_SECOND, 44100),
         ATTR_UINT32(MF_MT_AUDIO_BLOCK_ALIGNMENT, 4),
         ATTR_UINT32(MF_MT_AUDIO_AVG_BYTES_PER_SECOND, 44100 * 4),
-        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
-        ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1, .todo = TRUE),
+        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
+        ATTR_UINT32(MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1),
         {0},
     };
     const MFT_OUTPUT_STREAM_INFO output_info =
@@ -6245,7 +6245,7 @@ static void test_audio_convert(void)
     const struct attribute_desc output_sample_attributes[] =
     {
         ATTR_UINT32(mft_output_sample_incomplete, 1),
-        ATTR_UINT32(MFSampleExtension_CleanPoint, has_video_processor /* 0 on Win7 */, .todo = TRUE),
+        ATTR_UINT32(MFSampleExtension_CleanPoint, has_video_processor /* 0 on Win7 */),
         {0},
     };
     const struct sample_desc output_sample_desc[] =
@@ -6346,21 +6346,18 @@ static void test_audio_convert(void)
 
     memset(&dmo_mt, 0, sizeof(dmo_mt));
     hr = IMediaObject_GetInputCurrentType(dmo, 0, &dmo_mt);
-    todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr);
-    todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_WaveFormatEx), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
-    todo_wine ok(dmo_mt.cbFormat >= sizeof(WAVEFORMATEX), "got cbFormat %#lx\n", dmo_mt.cbFormat);
+    ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr);
+    ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_WaveFormatEx), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
+    ok(dmo_mt.cbFormat >= sizeof(WAVEFORMATEX), "got cbFormat %#lx\n", dmo_mt.cbFormat);
 
     hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type);
-    todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
-    if (hr == S_OK)
-    {
+    ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
     check_media_type(media_type, expect_input_type_desc, -1);
     IMFMediaType_Release(media_type);
 
     hr = IMediaObject_SetInputType(dmo, 0, &dmo_mt, 0);
     ok(hr == S_OK, "SetInputType returned %#lx\n", hr);
     check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
-    }
 
     MoFreeMediaType(&dmo_mt);
     IMediaObject_Release(dmo);
@@ -6386,11 +6383,11 @@ static void test_audio_convert(void)
 
     check_mft_set_output_type_required(transform, output_type_desc);
     check_mft_set_output_type(transform, output_type_desc, S_OK);
-    check_mft_get_output_current_type_(__LINE__, transform, expect_output_type_desc, FALSE, TRUE);
+    check_mft_get_output_current_type(transform, expect_output_type_desc);
 
     check_mft_set_input_type(transform, input_type_desc, S_OK);
     /* setting the input type does not set the output type to null */
-    check_mft_get_output_current_type_(__LINE__, transform, expect_output_type_desc, FALSE, TRUE);
+    check_mft_get_output_current_type(transform, expect_output_type_desc);
 
 
     hr = IMFTransform_QueryInterface(transform, &IID_IMediaObject, (void **)&dmo);
@@ -6398,21 +6395,18 @@ static void test_audio_convert(void)
 
     memset(&dmo_mt, 0, sizeof(dmo_mt));
     hr = IMediaObject_GetOutputCurrentType(dmo, 0, &dmo_mt);
-    todo_wine ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr);
-    todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_WaveFormatEx), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
-    todo_wine ok(dmo_mt.cbFormat >= sizeof(WAVEFORMATEX), "got cbFormat %#lx\n", dmo_mt.cbFormat);
+    ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr);
+    ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_WaveFormatEx), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
+    ok(dmo_mt.cbFormat >= sizeof(WAVEFORMATEX), "got cbFormat %#lx\n", dmo_mt.cbFormat);
 
     hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type);
-    todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
-    if (hr == S_OK)
-    {
+    ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
     check_media_type(media_type, expect_output_type_desc, -1);
     IMFMediaType_Release(media_type);
 
     hr = IMediaObject_SetOutputType(dmo, 0, &dmo_mt, 0);
     ok(hr == S_OK, "SetOutputType returned %#lx\n", hr);
-    check_mft_get_output_current_type_(__LINE__, transform, expect_output_type_desc, FALSE, TRUE);
-    }
+    check_mft_get_output_current_type(transform, expect_output_type_desc);
 
     MoFreeMediaType(&dmo_mt);
     IMediaObject_Release(dmo);
@@ -8965,10 +8959,10 @@ static void test_color_convert(BOOL use_2d_buffer)
         ATTR_BLOB(MF_MT_MINIMUM_DISPLAY_APERTURE, &actual_aperture, 16),
         ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
         ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width),
-        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2, .todo = TRUE),
-        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
-        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE),
-        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE),
+        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 3 / 2),
+        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
+        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
+        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
         {0},
     };
     const struct attribute_desc expect_output_type_desc[] =
@@ -8977,10 +8971,10 @@ static void test_color_convert(BOOL use_2d_buffer)
         ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
         ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
         ATTR_UINT32(MF_MT_DEFAULT_STRIDE, actual_width * 4),
-        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE),
-        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
-        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE),
-        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE),
+        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4),
+        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
+        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
+        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
         {0},
     };
     const struct attribute_desc expect_output_type_desc_negative_stride[] =
@@ -8989,10 +8983,10 @@ static void test_color_convert(BOOL use_2d_buffer)
         ATTR_GUID(MF_MT_SUBTYPE, MFVideoFormat_RGB32),
         ATTR_RATIO(MF_MT_FRAME_SIZE, actual_width, actual_height),
         ATTR_UINT32(MF_MT_DEFAULT_STRIDE, -actual_width * 4),
-        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4, .todo = TRUE),
-        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1, .todo = TRUE),
-        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1, .todo = TRUE),
-        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1, .todo = TRUE),
+        ATTR_UINT32(MF_MT_SAMPLE_SIZE, actual_width * actual_height * 4),
+        ATTR_UINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, 1),
+        ATTR_UINT32(MF_MT_FIXED_SIZE_SAMPLES, 1),
+        ATTR_RATIO(MF_MT_PIXEL_ASPECT_RATIO, 1, 1),
         {0},
     };
     const MFT_OUTPUT_STREAM_INFO output_info =
@@ -9159,7 +9153,7 @@ static void test_color_convert(BOOL use_2d_buffer)
 
     check_mft_set_input_type_required(transform, input_type_desc);
     check_mft_set_input_type(transform, input_type_desc, S_OK);
-    check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
+    check_mft_get_input_current_type(transform, expect_input_type_desc);
 
 
     hr = IMFTransform_QueryInterface(transform, &IID_IMediaObject, (void **)&dmo);
@@ -9167,15 +9161,13 @@ static void test_color_convert(BOOL use_2d_buffer)
 
     memset(&dmo_mt, 0, sizeof(dmo_mt));
     hr = IMediaObject_GetInputCurrentType(dmo, 0, &dmo_mt);
-    todo_wine ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr);
-    todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
-    todo_wine ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat);
+    ok(hr == S_OK, "GetInputCurrentType returned %#lx\n", hr);
+    ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
+    ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat);
     ok(is_dmo_subtype(&dmo_mt.subtype), "got subtype %s\n", debugstr_guid(&dmo_mt.subtype));
 
     hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type);
-    todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
-    if (hr == S_OK)
-    {
+    ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
     /* MFCreateMediaTypeFromRepresentation automatically converts MF to DMO media types */
     hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, get_mf_subtype_for_am_subtype(&dmo_mt.subtype));
     ok(hr == S_OK, "SetGUID returned %#lx\n", hr);
@@ -9184,8 +9176,7 @@ static void test_color_convert(BOOL use_2d_buffer)
 
     hr = IMediaObject_SetInputType(dmo, 0, &dmo_mt, 0);
     ok(hr == S_OK, "SetInputType returned %#lx\n", hr);
-    check_mft_get_input_current_type_(__LINE__, transform, expect_input_type_desc, FALSE, TRUE);
-    }
+    check_mft_get_input_current_type(transform, expect_input_type_desc);
 
     MoFreeMediaType(&dmo_mt);
     IMediaObject_Release(dmo);
@@ -9200,7 +9191,7 @@ static void test_color_convert(BOOL use_2d_buffer)
         winetest_push_context("color conversion #%lu", i);
         check_mft_set_output_type_required(transform, color_conversion_tests[i].output_type_desc);
         check_mft_set_output_type(transform, color_conversion_tests[i].output_type_desc, S_OK);
-        check_mft_get_output_current_type_(__LINE__, transform, color_conversion_tests[i].expect_output_type_desc, FALSE, TRUE);
+        check_mft_get_output_current_type(transform, color_conversion_tests[i].expect_output_type_desc);
 
 
         hr = IMFTransform_QueryInterface(transform, &IID_IMediaObject, (void **)&dmo);
@@ -9208,15 +9199,14 @@ static void test_color_convert(BOOL use_2d_buffer)
 
         memset(&dmo_mt, 0, sizeof(dmo_mt));
         hr = IMediaObject_GetOutputCurrentType(dmo, 0, &dmo_mt);
-        todo_wine ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr);
-        todo_wine ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
-        todo_wine ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat);
+        ok(hr == S_OK, "GetOutputCurrentType returned %#lx\n", hr);
+        ok(IsEqualGUID(&dmo_mt.formattype, &FORMAT_MFVideoFormat), "got format %s\n", debugstr_guid(&dmo_mt.formattype));
+        ok(dmo_mt.cbFormat == sizeof(MFVIDEOFORMAT), "got cbFormat %#lx\n", dmo_mt.cbFormat);
         ok(is_dmo_subtype(&dmo_mt.subtype), "got subtype %s\n", debugstr_guid(&dmo_mt.subtype));
 
         hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &dmo_mt, &media_type);
-        todo_wine ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
-        if (hr == S_OK)
-        {
+        ok(hr == S_OK, "MFCreateMediaTypeFromRepresentation returned %#lx\n", hr);
+
         /* MFCreateMediaTypeFromRepresentation automatically converts MF to DMO media types */
         hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, get_mf_subtype_for_am_subtype(&dmo_mt.subtype));
         ok(hr == S_OK, "SetGUID returned %#lx\n", hr);
@@ -9225,8 +9215,7 @@ static void test_color_convert(BOOL use_2d_buffer)
 
         hr = IMediaObject_SetOutputType(dmo, 0, &dmo_mt, 0);
         ok(hr == S_OK, "SetOutputType returned %#lx\n", hr);
-        check_mft_get_output_current_type_(__LINE__, transform, color_conversion_tests[i].expect_output_type_desc, FALSE, TRUE);
-        }
+        check_mft_get_output_current_type(transform, color_conversion_tests[i].expect_output_type_desc);
 
         MoFreeMediaType(&dmo_mt);
         IMediaObject_Release(dmo);
@@ -9749,7 +9738,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb32_default_stride, .output_bitmap = L"rgb32frame-flip.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb32_negative_stride : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
-            .delta = 2, /* Windows returns 0, Wine needs 2 */
         },
         { /* Test 1 */
             .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp",
@@ -9757,7 +9745,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb32_negative_stride, .output_bitmap = L"rgb32frame-flip.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb32_negative_stride : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
-            .delta = 2, /* Windows returns 0, Wine needs 2 */
         },
         { /* Test 2 */
             .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp",
@@ -9773,7 +9760,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", .output_bitmap_2d = L"nv12frame-flip-2d.bmp",
             .output_buffer_desc = use_2d_buffer ? nv12_default_stride : NULL,
             .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc,
-            .delta = 2, /* Windows returns 0, Wine needs 2 */
         },
         { /* Test 4 */
             .input_type_desc = rgb32_negative_stride, .input_bitmap = L"rgb32frame.bmp",
@@ -9781,7 +9767,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = nv12_default_stride, .output_bitmap = L"nv12frame-flip.bmp", .output_bitmap_2d = L"nv12frame-flip-2d.bmp",
             .output_buffer_desc = use_2d_buffer ? nv12_default_stride : NULL,
             .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc,
-            .delta = 2, /* Windows returns 0, Wine needs 2 */
         },
         { /* Test 5 */
             .input_type_desc = rgb32_positive_stride, .input_bitmap = L"rgb32frame.bmp",
@@ -9828,6 +9813,7 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_buffer_desc = use_2d_buffer ? rgb32_with_aperture : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
             .broken = TRUE, /* old Windows version incorrectly rescale */
+            .delta = 3, /* Windows returns 0, Wine needs 3 */
         },
         { /* Test 11 */
             .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp",
@@ -9835,7 +9821,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb555_default_stride, .output_bitmap = L"rgb555frame.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb555_negative_stride : NULL,
             .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc,
-            .delta = 5, /* Windows returns 0, Wine needs 5 */
         },
         { /* Test 12 */
             .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp",
@@ -9843,7 +9828,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb555_negative_stride, .output_bitmap = L"rgb555frame.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb555_negative_stride : NULL,
             .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc,
-            .delta = 5, /* Windows returns 0, Wine needs 5 */
         },
         { /* Test 13 */
             .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame.bmp",
@@ -9851,7 +9835,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb555_positive_stride : NULL,
             .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc,
-            .delta = 3, /* Windows returns 0, Wine needs 3 */
         },
         { /* Test 14 */
             .input_type_desc = rgb555_default_stride, .input_bitmap = L"rgb555frame.bmp",
@@ -9859,7 +9842,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb555_positive_stride, .output_bitmap = L"rgb555frame-flip.bmp",
             .output_buffer_desc = use_2d_buffer ? rgb555_positive_stride : NULL,
             .output_sample_desc = &rgb555_sample_desc, .output_sample_2d_desc = &rgb555_sample_desc,
-            .delta = 4, /* Windows returns 0, Wine needs 4 */
         },
         { /* Test 15 */
             .input_type_desc = nv12_with_aperture, .input_bitmap = L"nv12frame.bmp",
@@ -9876,7 +9858,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_buffer_desc = use_2d_buffer ? rgb32_with_aperture : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
             .broken = TRUE, /* old Windows version incorrectly rescale */
-            .todo = use_2d_buffer,
         },
         { /* Test 17 */
             .input_type_desc = rgb32_with_aperture, .input_bitmap = L"rgb32frame-flip.bmp",
@@ -9901,7 +9882,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_buffer_desc = use_2d_buffer ? rgb32_default_stride : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
             .delta = 3, /* Windows returns 3 with 2D buffer */
-            .todo = use_2d_buffer,
         },
         { /* Test 20 */
             .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame.bmp",
@@ -9910,7 +9890,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_buffer_desc = use_2d_buffer ? rgb32_positive_stride : NULL,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
             .delta = 3, /* Windows returns 3 with 2D buffer */
-            .todo = use_2d_buffer,
         },
 
         { /* Test 21, 2D only */
@@ -9919,7 +9898,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb32_default_stride, .output_bitmap = L"rgb32frame-extra-width.bmp",
             .output_buffer_desc = rgb32_extra_width,
             .output_sample_desc = &rgb32_extra_width_sample_desc, .output_sample_2d_desc = &rgb32_extra_width_sample_desc,
-            .todo = TRUE,
         },
         { /* Test 22, 2D only */
             .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame-extra-width.bmp",
@@ -9927,7 +9905,7 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = nv12_default_stride, .output_bitmap_1d = L"nv12frame.bmp", .output_bitmap_2d = L"nv12frame-2d.bmp",
             .output_buffer_desc = nv12_default_stride,
             .output_sample_desc = &nv12_sample_desc, .output_sample_2d_desc = &nv12_sample_2d_desc,
-            .delta = 2, /* Windows returns 2 with 1D buffer */ .todo = TRUE,
+            .delta = 2, /* Windows returns 2 with 1D buffer */
         },
         { /* Test 23, 2D only */
             .input_type_desc = rgb32_default_stride, .input_bitmap = L"rgb32frame-extra-width.bmp",
@@ -9935,7 +9913,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = nv12_default_stride, .output_bitmap_1d = L"nv12frame-extra-width.bmp", .output_bitmap_2d = L"nv12frame-extra-width-2d.bmp",
             .output_buffer_desc = nv12_extra_width,
             .output_sample_desc = &nv12_extra_width_sample_desc, .output_sample_2d_desc = &nv12_extra_width_sample_2d_desc,
-            .todo = TRUE,
         },
         { /* Test 24, 2D only */
             .input_type_desc = nv12_default_stride, .input_bitmap = L"nv12frame-extra-width.bmp",
@@ -9943,7 +9920,6 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = rgb32_default_stride, .output_bitmap_1d = L"rgb32frame.bmp", .output_bitmap_2d = L"rgb32frame.bmp",
             .output_buffer_desc = rgb32_default_stride,
             .output_sample_desc = &rgb32_sample_desc, .output_sample_2d_desc = &rgb32_sample_desc,
-            .todo = TRUE,
         },
         { /* Test 25 */
             .input_type_desc = rgb32_crop, .input_bitmap = L"rgb32frame-crop.bmp",
@@ -9951,8 +9927,7 @@ static void test_video_processor(BOOL use_2d_buffer)
             .output_type_desc = nv12_crop, .output_bitmap = L"nv12frame-crop.bmp", .output_bitmap_1d = L"nv12frame-crop-1d.bmp", .output_bitmap_2d = L"nv12frame-crop-2d.bmp",
             .output_buffer_desc = use_2d_buffer ? nv12_crop : NULL,
             .output_sample_desc = &nv12_crop_sample_desc, .output_sample_2d_desc = &nv12_crop_sample_2d_desc,
-            .delta = 2, /* Windows returns 1, Wine needs 2 */
-            .todo = use_2d_buffer,
+            .delta = 1, /* Windows returns 1, Wine needs 2 */
         },
     };
 
@@ -10142,7 +10117,6 @@ static void test_video_processor(BOOL use_2d_buffer)
     ok(hr == S_OK, "Failed to create a sample, hr %#lx.\n", hr);
 
     hr = check_mft_process_output(transform, output_sample, &output_status);
-    todo_wine
     ok(hr == MF_E_TRANSFORM_NEED_MORE_INPUT, "Unexpected hr %#lx.\n", hr);
 
     hr = IMFTransform_ProcessInput(transform, 0, input_sample, 0);
diff --git a/dlls/mf/topology_loader.c b/dlls/mf/topology_loader.c
index 2dda6250231f..5d51550145c2 100644
--- a/dlls/mf/topology_loader.c
+++ b/dlls/mf/topology_loader.c
@@ -806,6 +806,7 @@ static HRESULT topology_branch_connect_optional_chain(IMFTopology *topology, str
     while (SUCCEEDED(hr) && node != branch->down.node)
     {
         IMFTopologyNode *tmp = node;
+        IMFMediaType *orig;
         UINT32 method;
 
         if (FAILED(IMFTopologyNode_GetUINT32(node, &MF_TOPONODE_CONNECT_METHOD, &method)))
@@ -816,18 +817,25 @@ static HRESULT topology_branch_connect_optional_chain(IMFTopology *topology, str
          * downstream of them. Support for upstream insertion is untested in native, but seems unlikely to work. */
         if (FAILED(hr = topology_branch_create_for_input(down_node, down_stream, &current)))
             break;
+        if (FAILED(hr = IMFMediaTypeHandler_GetCurrentMediaType(current->up.handler, &orig)))
+        {
+            topology_branch_destroy(current);
+            break;
+        }
+
         if (SUCCEEDED(hr = topology_branch_create_optional(topology, current, node, stream, &up_branch, &down_branch)))
         {
             if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, up_branch, NULL, !!method))
                     || FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, down_branch, NULL, FALSE)))
             {
-                if (FAILED(hr = topology_branch_connect(topology, CONNECT_DIRECT, current, NULL, FALSE)))
+                if (FAILED(hr = topology_branch_connect_with_type(topology, current, orig)))
                     WARN("Failed to restore previous branch %s\n", debugstr_topology_branch(current));
                 IMFTopology_RemoveNode(topology, down_branch->up.node);
             }
             topology_branch_destroy(down_branch);
             topology_branch_destroy(up_branch);
         }
+        IMFMediaType_Release(orig);
         topology_branch_destroy(current);
 
         hr = IMFTopologyNode_GetOutput(tmp, 0, &node, &stream);
diff --git a/dlls/mfplat/tests/Makefile.in b/dlls/mfplat/tests/Makefile.in
index 898420268e3e..6caf83ab9714 100644
--- a/dlls/mfplat/tests/Makefile.in
+++ b/dlls/mfplat/tests/Makefile.in
@@ -1,5 +1,5 @@
 TESTDLL   = mfplat.dll
-IMPORTS   = ole32 mfplat user32 d3d9 dxva2 mfuuid propsys uuid strmiids kernelbase
+IMPORTS   = ole32 mfplat user32 d3d9 dxva2 mfuuid propsys uuid strmiids kernel32 kernelbase
 
 SOURCES = \
 	mfplat.c \
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c
index 2a8af296c915..1e6fa0639c36 100644
--- a/dlls/mfplat/tests/mfplat.c
+++ b/dlls/mfplat/tests/mfplat.c
@@ -1430,8 +1430,11 @@ static void test_source_resolver(void)
     hr = IMFSourceResolver_CreateObjectFromByteStream(resolver, stream, pathW, MF_RESOLUTION_MEDIASOURCE, NULL,
             &obj_type, (IUnknown **)&mediasource);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    IMFMediaSource_Shutdown(mediasource);
-    IMFMediaSource_Release(mediasource);
+    if (SUCCEEDED(hr))
+    {
+        IMFMediaSource_Shutdown(mediasource);
+        IMFMediaSource_Release(mediasource);
+    }
     IMFByteStream_Release(stream);
 
     hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream);
@@ -1457,8 +1460,11 @@ static void test_source_resolver(void)
             MF_RESOLUTION_MEDIASOURCE | MF_RESOLUTION_CONTENT_DOES_NOT_HAVE_TO_MATCH_EXTENSION_OR_MIME_TYPE,
             NULL, &obj_type, (IUnknown **)&mediasource);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    IMFMediaSource_Shutdown(mediasource);
-    IMFMediaSource_Release(mediasource);
+    if (SUCCEEDED(hr))
+    {
+        IMFMediaSource_Shutdown(mediasource);
+        IMFMediaSource_Release(mediasource);
+    }
     IMFByteStream_Release(stream);
 
     hr = MFCreateFile(MF_ACCESSMODE_READ, MF_OPENMODE_FAIL_IF_NOT_EXIST, MF_FILEFLAGS_NONE, filename, &stream);
diff --git a/dlls/mfsrcsnk/media_source.c b/dlls/mfsrcsnk/media_source.c
index c288383b391d..28b0d34c46b6 100644
--- a/dlls/mfsrcsnk/media_source.c
+++ b/dlls/mfsrcsnk/media_source.c
@@ -1728,7 +1728,9 @@ static NTSTATUS CDECL media_source_seek_cb( struct winedmo_stream *stream, UINT6
     struct media_source *source = CONTAINING_RECORD(stream, struct media_source, winedmo_stream);
     TRACE("stream %p, pos %p\n", stream, pos);
 
-    if (FAILED(IMFByteStream_Seek(source->stream, msoBegin, *pos, 0, pos)))
+    if (FAILED(IMFByteStream_SetCurrentPosition(source->stream, *pos)))
+        return STATUS_UNSUCCESSFUL;
+    if (FAILED(IMFByteStream_GetCurrentPosition(source->stream, pos)))
         return STATUS_UNSUCCESSFUL;
     return STATUS_SUCCESS;
 }
diff --git a/dlls/mfsrcsnk/tests/mfsrcsnk.c b/dlls/mfsrcsnk/tests/mfsrcsnk.c
index af44a074ea75..ad0cf4d9ff0d 100644
--- a/dlls/mfsrcsnk/tests/mfsrcsnk.c
+++ b/dlls/mfsrcsnk/tests/mfsrcsnk.c
@@ -903,7 +903,7 @@ static void test_mp4_extra_metadata(void)
     hr = IMFMediaType_GetUINT64(media_type, &MF_MT_PIXEL_ASPECT_RATIO, &value64);
     todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     /* pasp takes precedence */
-    todo_wine ok(value64 == 0xf00000010, "Unexpected aspect ratio: %#I64x.\n", value64);
+    todo_wine ok(value64 == 0xf00000010 || broken(value64 == 0x300000004) /* <= Win10 1809 */, "Unexpected aspect ratio: %#I64x.\n", value64);
     IMFMediaType_Release(media_type);
     IMFMediaTypeHandler_Release(type_handler);
     IMFStreamDescriptor_Release(stream_descriptor);
diff --git a/dlls/mscoree/mscoree_private.h b/dlls/mscoree/mscoree_private.h
index c9fd0b781f0b..2b761c2b2dbc 100644
--- a/dlls/mscoree/mscoree_private.h
+++ b/dlls/mscoree/mscoree_private.h
@@ -45,7 +45,7 @@ extern HRESULT assembly_get_runtime_version(ASSEMBLY *assembly, LPSTR *version);
 extern HRESULT assembly_get_vtable_fixups(ASSEMBLY *assembly, VTableFixup **fixups, DWORD *count);
 extern HRESULT assembly_get_native_entrypoint(ASSEMBLY *assembly, NativeEntryPointFunc *func);
 
-#define WINE_MONO_VERSION "11.1.0"
+#define WINE_MONO_VERSION "11.2.0"
 
 /* Mono embedding */
 typedef struct _MonoDomain MonoDomain;
diff --git a/dlls/mshtml/htmltextarea.c b/dlls/mshtml/htmltextarea.c
index 58d8ff3627fa..f3d560e4da96 100644
--- a/dlls/mshtml/htmltextarea.c
+++ b/dlls/mshtml/htmltextarea.c
@@ -131,15 +131,35 @@ static HRESULT WINAPI HTMLTextAreaElement_get_status(IHTMLTextAreaElement *iface
 static HRESULT WINAPI HTMLTextAreaElement_put_disabled(IHTMLTextAreaElement *iface, VARIANT_BOOL v)
 {
     HTMLTextAreaElement *This = impl_from_IHTMLTextAreaElement(iface);
-    FIXME("(%p)->(%x)\n", This, v);
-    return E_NOTIMPL;
+    nsresult nsres;
+
+    TRACE("(%p)->(%x)\n", This, v);
+
+    nsres = nsIDOMHTMLTextAreaElement_SetDisabled(This->nstextarea, v != VARIANT_FALSE);
+    if(NS_FAILED(nsres)) {
+        ERR("SetDisabled failed: %08lx\n", nsres);
+        return E_FAIL;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI HTMLTextAreaElement_get_disabled(IHTMLTextAreaElement *iface, VARIANT_BOOL *p)
 {
     HTMLTextAreaElement *This = impl_from_IHTMLTextAreaElement(iface);
-    FIXME("(%p)->(%p)\n", This, p);
-    return E_NOTIMPL;
+    nsresult nsres;
+    cpp_bool b;
+
+    TRACE("(%p)->(%p)\n", This, p);
+
+    nsres = nsIDOMHTMLTextAreaElement_GetDisabled(This->nstextarea, &b);
+    if(NS_FAILED(nsres)) {
+        ERR("GetDisabled failed: %08lx\n", nsres);
+        return E_FAIL;
+    }
+
+    *p = variant_bool(b);
+    return S_OK;
 }
 
 static HRESULT WINAPI HTMLTextAreaElement_get_form(IHTMLTextAreaElement *iface, IHTMLFormElement **p)
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index 0a8398f935db..b3f49171a942 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -2096,6 +2096,32 @@ static void _test_textarea_type(unsigned line, IUnknown *unk)
     SysFreeString(type);
 }
 
+#define test_textarea_disabled(t,v) _test_textarea_disabled(__LINE__,t,v)
+static void _test_textarea_disabled(unsigned line, IUnknown *unk, VARIANT_BOOL ex)
+{
+    IHTMLTextAreaElement *textarea = _get_textarea_iface(line, unk);
+    VARIANT_BOOL b = 0x100;
+    HRESULT hres;
+
+    hres = IHTMLTextAreaElement_get_disabled(textarea, &b);
+    IHTMLTextAreaElement_Release(textarea);
+    ok_(__FILE__,line)(hres == S_OK, "get_disabled failed: %08lx\n", hres);
+    ok_(__FILE__,line)(b == ex, "disabled = %x, expected %x\n", b, ex);
+}
+
+#define test_textarea_put_disabled(t,v) _test_textarea_put_disabled(__LINE__,t,v)
+static void _test_textarea_put_disabled(unsigned line, IUnknown *unk, VARIANT_BOOL b)
+{
+    IHTMLTextAreaElement *textarea = _get_textarea_iface(line, unk);
+    HRESULT hres;
+
+    hres = IHTMLTextAreaElement_put_disabled(textarea, b);
+    IHTMLTextAreaElement_Release(textarea);
+    ok_(__FILE__,line)(hres == S_OK, "put_disabled failed: %08lx\n", hres);
+
+    _test_textarea_disabled(line, unk, b);
+}
+
 #define get_textarea_form(t) _get_textarea_form(__LINE__,t)
 static IHTMLFormElement *_get_textarea_form(unsigned line, IUnknown *unk)
 {
@@ -11379,6 +11405,9 @@ static void test_textarea_element(IHTMLDocument2 *doc, IHTMLElement *parent)
     test_textarea_put_readonly((IUnknown*)elem, VARIANT_TRUE);
     test_textarea_put_readonly((IUnknown*)elem, VARIANT_FALSE);
     test_textarea_type((IUnknown*)elem);
+    test_textarea_disabled((IUnknown*)elem, VARIANT_FALSE);
+    test_textarea_put_disabled((IUnknown*)elem, VARIANT_TRUE);
+    test_textarea_put_disabled((IUnknown*)elem, VARIANT_FALSE);
 
     form = get_textarea_form((IUnknown*)elem);
     ok(!form, "form = %p\n", form);
diff --git a/dlls/msv1_0/main.c b/dlls/msv1_0/main.c
index fc828e7574ac..985b83b327ba 100644
--- a/dlls/msv1_0/main.c
+++ b/dlls/msv1_0/main.c
@@ -39,6 +39,92 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntlm);
 
+enum negotiate_flags
+{
+    NTLMSSP_NEGOTIATE_UNICODE                   = 0x00000001,
+    NTLM_NEGOTIATE_OEM                          = 0x00000002,
+    NTLMSSP_REQUEST_TARGET                      = 0x00000004,
+    NTLMSSP_NEGOTIATE_SIGN                      = 0x00000010,
+    NTLMSSP_NEGOTIATE_SEAL                      = 0x00000020,
+    NTLMSSP_NEGOTIATE_DATAGRAM                  = 0x00000040,
+    NTLMSSP_NEGOTIATE_LM_KEY                    = 0x00000080,
+    NTLMSSP_NEGOTIATE_NETWARE                   = 0x00000100,
+    NTLMSSP_NEGOTIATE_NTLM                      = 0x00000200,
+    NTLMSSP_NEGOTIATE_ANONYMOUS                 = 0x00000800,
+    NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED       = 0x00001000,
+    NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED  = 0x00002000,
+    NTLMSSP_NEGOTIATE_LOCAL_CALL                = 0x00004000,
+    NTLMSSP_NEGOTIATE_ALWAYS_SIGN               = 0x00008000,
+    NTLMSSP_TARGET_TYPE_DOMAIN                  = 0x00010000,
+    NTLMSSP_TARGET_TYPE_SERVER                  = 0x00020000,
+    NTLMSSP_TARGET_TYPE_SHARE                   = 0x00040000,
+    NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY  = 0x00080000,
+    NTLMSSP_NEGOTIATE_IDENTIFY                  = 0x00100000,
+    NTLMSSP_REQUEST_NON_NT_SESSION_KEY          = 0x00400000,
+    NTLMSSP_NEGOTIATE_TARGET_INFO               = 0x00800000,
+    NTLMSSP_NEGOTIATE_VERSION                   = 0x02000000,
+    NTLMSSP_NEGOTIATE_128                       = 0x20000000,
+    NTLMSSP_NEGOTIATE_KEY_EXCH                  = 0x40000000,
+    NTLMSSP_NEGOTIATE_56                        = 0x80000000,
+};
+
+struct ntlm_negotiate
+{
+    char signature[8];
+    int message_type;
+    enum negotiate_flags negotiate_flags;
+    unsigned short target_name_len;
+    unsigned short target_name_max_len;
+    unsigned int target_name_off;
+    unsigned short workstation_name_len;
+    unsigned short workstation_name_max_len;
+    unsigned int workstation_name_off;
+    BYTE version[8];
+};
+
+struct ntlm_challenge
+{
+    char signature[8];
+    int message_type;
+    unsigned short target_name_len;
+    unsigned short target_name_max_len;
+    unsigned int target_name_off;
+    enum negotiate_flags negotiate_flags;
+    BYTE challenge[8];
+    BYTE reserved[8];
+    unsigned short target_info_len;
+    unsigned short target_info_max_len;
+    unsigned int target_info_off;
+    BYTE version[8];
+};
+
+struct ntlm_authenticate
+{
+    char signature[8];
+    int message_type;
+    unsigned short lm_response_len;
+    unsigned short lm_response_max_len;
+    unsigned int lm_response_off;
+    unsigned short nt_response_len;
+    unsigned short nt_response_max_len;
+    unsigned int nt_response_off;
+    unsigned short domain_len;
+    unsigned short domain_max_len;
+    unsigned int domain_off;
+    unsigned short username_len;
+    unsigned short username_max_len;
+    unsigned int username_off;
+    unsigned short workstation_len;
+    unsigned short workstation_max_len;
+    unsigned int workstation_off;
+    unsigned short random_session_key_len;
+    unsigned short random_session_key_max_len;
+    unsigned int random_session_key_off;
+    unsigned int negotiate_flags;
+    BYTE version[8];
+    BYTE mic[16];
+};
+
 static void ntlm_cleanup( struct ntlm_ctx *ctx )
 {
     WINE_UNIX_CALL( unix_cleanup, ctx );
@@ -720,15 +806,18 @@ static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA
          */
         if (!(want_flags = malloc( 73 ))) goto done;
         strcpy( want_flags, "SF" );
+        if (ctx_req & ISC_REQ_CONFIDENTIALITY) ctx_req |= ISC_REQ_INTEGRITY;
         if (ctx_req & ISC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
         if ((ctx_req & ISC_REQ_INTEGRITY) || (ctx_req & ISC_REQ_REPLAY_DETECT) ||
             (ctx_req & ISC_REQ_SEQUENCE_DETECT)) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
 
-        if (ctx_req & ISC_REQ_CONNECTION) ctx->attrs |= ISC_RET_CONNECTION;
-        if (ctx_req & ISC_REQ_EXTENDED_ERROR) ctx->attrs |= ISC_RET_EXTENDED_ERROR;
-        if (ctx_req & ISC_REQ_MUTUAL_AUTH) ctx->attrs |= ISC_RET_MUTUAL_AUTH;
-        if (ctx_req & ISC_REQ_USE_DCE_STYLE) ctx->attrs |= ISC_RET_USED_DCE_STYLE;
-        if (ctx_req & ISC_REQ_DELEGATE) ctx->attrs |= ISC_RET_DELEGATE;
+        ctx->req_attrs = ctx_req;
+        *ctx_attr = 0;
+        if (ctx_req & ISC_REQ_REPLAY_DETECT) *ctx_attr |= ISC_RET_REPLAY_DETECT;
+        if (ctx_req & ISC_REQ_SEQUENCE_DETECT) *ctx_attr |= ISC_RET_SEQUENCE_DETECT;
+        if (ctx_req & ISC_REQ_CONFIDENTIALITY) *ctx_attr |= ISC_RET_CONFIDENTIALITY;
+        if (ctx_req & ISC_REQ_CONNECTION) *ctx_attr |= ISC_RET_CONNECTION;
+        if (ctx_req & ISC_REQ_INTEGRITY) *ctx_attr |= ISC_RET_INTEGRITY;
         if (ctx_req & ISC_REQ_STREAM) FIXME( "ISC_REQ_STREAM\n" );
 
         /* use cached credentials if no password was given, fall back to an empty password on failure */
@@ -778,6 +867,8 @@ static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA
     }
     else /* !ctx_handle && !input */
     {
+        struct ntlm_challenge *challenge;
+
         if (!input || ((idx = get_buffer_index( input, SECBUFFER_TOKEN )) == -1))
         {
             status = SEC_E_INVALID_TOKEN;
@@ -791,11 +882,23 @@ static NTSTATUS NTAPI ntlm_SpInitLsaModeContext( LSA_SEC_HANDLE cred_handle, LSA
             goto done;
         }
 
-        if (!input->pBuffers[idx].pvBuffer || input->pBuffers[idx].cbBuffer > NTLM_MAX_BUF)
+        if (!input->pBuffers[idx].pvBuffer || input->pBuffers[idx].cbBuffer > NTLM_MAX_BUF ||
+                input->pBuffers[idx].cbBuffer < offsetof(struct ntlm_challenge, target_info_len))
         {
             status = SEC_E_INVALID_TOKEN;
             goto done;
         }
+
+        challenge = input->pBuffers[idx].pvBuffer;
+        ctx->req_attrs |= ctx_req;
+        *ctx_attr = 0;
+        if (ctx->req_attrs & ISC_REQ_MUTUAL_AUTH) FIXME( "ASC_REQ_MUTUAL_AUTH\n" );
+        if (ctx->req_attrs & (ISC_REQ_INTEGRITY | ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT) &&
+                challenge->negotiate_flags & NTLMSSP_NEGOTIATE_SIGN)
+            *ctx_attr |= ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT;
+        if (ctx->req_attrs & ISC_REQ_CONFIDENTIALITY && challenge->negotiate_flags & NTLMSSP_NEGOTIATE_SEAL)
+            *ctx_attr |= ISC_RET_CONFIDENTIALITY;
+
         bin_len = input->pBuffers[idx].cbBuffer;
         memcpy( bin, input->pBuffers[idx].pvBuffer, bin_len );
 
@@ -915,6 +1018,7 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
     if (!ctx_handle)
     {
         struct ntlm_cred *cred = (struct ntlm_cred *)cred_handle;
+        struct ntlm_negotiate *negotiate;
         char *argv[3];
 
         if (!cred || !(cred->mode & MODE_SERVER))
@@ -936,6 +1040,13 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
         }
         else bin_len = input->pBuffers[0].cbBuffer;
 
+        if (bin_len < offsetof(struct ntlm_negotiate, target_name_len))
+        {
+            status = SEC_E_INVALID_TOKEN;
+            goto done;
+        }
+        negotiate = input->pBuffers[0].pvBuffer;
+
         if (!(ctx = calloc( 1, sizeof(*ctx) ))) goto done;
 
         argv[0] = (char *)"ntlm_auth";
@@ -951,11 +1062,7 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
         }
         strcpy( want_flags, "SF" );
         if (ctx_req & ASC_REQ_CONFIDENTIALITY) strcat( want_flags, " NTLMSSP_FEATURE_SEAL" );
-        if (ctx_req & ASC_REQ_CONNECTION)
-        {
-            strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
-            ctx->attrs |= ASC_RET_CONNECTION;
-        }
+        if (ctx_req & ASC_REQ_CONNECTION) strcat( want_flags, " NTLMSSP_FEATURE_SESSION_KEY" );
         if (ctx_req & ASC_REQ_INTEGRITY) strcat( want_flags, " NTLMSSP_FEATURE_SIGN" );
         if (ctx_req & ASC_REQ_ALLOCATE_MEMORY) FIXME( "ASC_REQ_ALLOCATE_MEMORY\n" );
         if (ctx_req & ASC_REQ_EXTENDED_ERROR) FIXME( "ASC_REQ_EXTENDED_ERROR\n" );
@@ -964,6 +1071,17 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
         if (ctx_req & ASC_REQ_SEQUENCE_DETECT) FIXME( "ASC_REQ_SEQUENCE_DETECT\n" );
         if (ctx_req & ASC_REQ_STREAM) FIXME( "ASC_REQ_STREAM\n" );
 
+        ctx->req_attrs = ctx_req;
+        *ctx_attr = 0;
+        if (ctx_req & ASC_REQ_CONFIDENTIALITY || negotiate->negotiate_flags & NTLMSSP_NEGOTIATE_SEAL)
+            *ctx_attr |= ASC_RET_CONFIDENTIALITY;
+        if (ctx_req & ASC_REQ_CONNECTION) *ctx_attr |= ASC_RET_CONNECTION;
+        if (ctx_req & ASC_REQ_INTEGRITY) *ctx_attr |= ASC_RET_INTEGRITY;
+        if (ctx_req & ISC_REQ_REPLAY_DETECT || negotiate->negotiate_flags & NTLMSSP_NEGOTIATE_SIGN)
+            *ctx_attr |= ASC_RET_REPLAY_DETECT;
+        if (ctx_req & ISC_REQ_SEQUENCE_DETECT || negotiate->negotiate_flags & NTLMSSP_NEGOTIATE_SIGN)
+            *ctx_attr |= ASC_RET_SEQUENCE_DETECT;
+
         if (strlen( want_flags ) > 3)
         {
             TRACE( "want flags are %s\n", debugstr_a(want_flags) );
@@ -991,7 +1109,7 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
             goto done;
         }
         output->pBuffers[0].cbBuffer = bin_len;
-        output->pBuffers[0].BufferType = SECBUFFER_DATA;
+        output->pBuffers[0].BufferType = SECBUFFER_TOKEN;
         memcpy( output->pBuffers[0].pvBuffer, bin, bin_len );
 
         *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
@@ -999,6 +1117,8 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
     }
     else
     {
+        struct ntlm_authenticate *authenticate;
+
         if (!input || input->cBuffers < 1)
         {
             status = SEC_E_INCOMPLETE_MESSAGE;
@@ -1012,13 +1132,21 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
             goto done;
         }
 
-        if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF)
+        if (input->pBuffers[0].cbBuffer > NTLM_MAX_BUF ||
+                input->pBuffers[0].cbBuffer < offsetof(struct ntlm_authenticate, version))
         {
             status = SEC_E_INVALID_TOKEN;
             goto done;
         }
         else bin_len = input->pBuffers[0].cbBuffer;
         memcpy( bin, input->pBuffers[0].pvBuffer, bin_len );
+        authenticate = input->pBuffers[0].pvBuffer;
+
+        *ctx_attr = 0;
+        if (authenticate->negotiate_flags & NTLMSSP_NEGOTIATE_SEAL)
+            *ctx_attr |= ASC_RET_CONFIDENTIALITY;
+        if (authenticate->negotiate_flags & NTLMSSP_NEGOTIATE_SIGN)
+            *ctx_attr |= ASC_RET_INTEGRITY | ASC_RET_REPLAY_DETECT | ASC_RET_SEQUENCE_DETECT;
 
         strcpy( buf, "KK " );
         encode_base64( bin, bin_len, buf + 3 );
@@ -1052,7 +1180,8 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
                 goto done;
             }
         }
-        output->pBuffers[0].cbBuffer = 0;
+        if (output && output->cBuffers > 0)
+            output->pBuffers[0].cbBuffer = 0;
 
         strcpy( buf, "GF" );
         if ((status = ntlm_chat( ctx, buf, NTLM_MAX_BUF, &len )) != SEC_E_OK) goto done;
@@ -1088,6 +1217,11 @@ static NTSTATUS NTAPI ntlm_SpAcceptLsaModeContext( LSA_SEC_HANDLE cred_handle, L
         }
         arc4_init( &ctx->crypt.ntlm.arc4info, ctx->session_key, 16 );
         ctx->crypt.ntlm.seq_no = 0;
+        create_ntlm2_subkeys( ctx );
+        arc4_init( &ctx->crypt.ntlm2.send_arc4info, ctx->crypt.ntlm2.send_seal_key, 16 );
+        arc4_init( &ctx->crypt.ntlm2.recv_arc4info, ctx->crypt.ntlm2.recv_seal_key, 16 );
+        ctx->crypt.ntlm2.send_seq_no = 0;
+        ctx->crypt.ntlm2.recv_seq_no = 0;
 
         *new_ctx_handle = (LSA_SEC_HANDLE)ctx;
         status = SEC_E_OK;
diff --git a/dlls/msv1_0/unixlib.h b/dlls/msv1_0/unixlib.h
index bfa9497205e8..def5a2c896a3 100644
--- a/dlls/msv1_0/unixlib.h
+++ b/dlls/msv1_0/unixlib.h
@@ -64,7 +64,7 @@ struct ntlm_ctx
 {
     enum mode    mode;
     int          pid;
-    unsigned int attrs;
+    unsigned int req_attrs;
     int          pipe_in;
     int          pipe_out;
     char         session_key[16];
diff --git a/dlls/msvcp60/string.c b/dlls/msvcp60/string.c
index 253b13b7dbea..3abca440f578 100644
--- a/dlls/msvcp60/string.c
+++ b/dlls/msvcp60/string.c
@@ -3014,27 +3014,27 @@ basic_string_wchar* __thiscall basic_string_wchar_replace_cstr_len(basic_string_
     ptr = this->ptr;
 
     if(inside_pos == -1) {
-        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(char));
-        memcpy(ptr+off, str, str_len*sizeof(char));
+        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(wchar_t));
+        memcpy(ptr+off, str, str_len*sizeof(wchar_t));
     } else if(len >= str_len) {
-        memmove(ptr+off, ptr+inside_pos, str_len*sizeof(char));
-        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(char));
+        memmove(ptr+off, ptr+inside_pos, str_len*sizeof(wchar_t));
+        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(wchar_t));
     } else {
         size_t size;
 
-        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(char));
+        memmove(ptr+off+str_len, ptr+off+len, (this->size-off-len)*sizeof(wchar_t));
 
         if(inside_pos < off+len) {
             size = off+len-inside_pos;
             if(size > str_len)
                 size = str_len;
-            memmove(ptr+off, ptr+inside_pos, size*sizeof(char));
+            memmove(ptr+off, ptr+inside_pos, size*sizeof(wchar_t));
         } else {
             size = 0;
         }
 
         if(str_len > size)
-            memmove(ptr+off+size, ptr+off+str_len, (str_len-size)*sizeof(char));
+            memmove(ptr+off+size, ptr+off+str_len, (str_len-size)*sizeof(wchar_t));
     }
 
     if(this->ptr)
@@ -3091,7 +3091,7 @@ basic_string_wchar* __thiscall basic_string_wchar_replace_ch(basic_string_wchar
         basic_string_wchar__Grow(this, this->size-len+count, FALSE);
     ptr = this->ptr;
 
-    memmove(ptr+off+count, ptr+off+len, (this->size-off-len)*sizeof(char));
+    memmove(ptr+off+count, ptr+off+len, (this->size-off-len)*sizeof(wchar_t));
     MSVCP_char_traits_wchar_assignn(ptr+off, count, ch);
     basic_string_wchar__Eos(this, this->size-len+count);
 
diff --git a/dlls/msvcp70/msvcp70.spec b/dlls/msvcp70/msvcp70.spec
index 0ba16f5bd03b..518ed412d157 100644
--- a/dlls/msvcp70/msvcp70.spec
+++ b/dlls/msvcp70/msvcp70.spec
@@ -2820,9 +2820,9 @@
 @ stub -arch=win32 ?_Iput@?$num_put@GV?$ostreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@KA?AV?$ostreambuf_iterator@GU?$char_traits@G@std@@@2@V32@AAVios_base@2@GPADI@Z
 @ stub -arch=win64 ?_Iput@?$num_put@GV?$ostreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@KA?AV?$ostreambuf_iterator@GU?$char_traits@G@std@@@2@V32@AEAVios_base@2@GPEAD_K@Z
 @ stub -arch=win32 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@KA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AAVios_base@2@_WPADI@Z
-@ stub ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z
-@ stub ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z
-@ stub ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z
+@ cdecl ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isinf
 @ cdecl ?_Isnan@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isnan
diff --git a/dlls/msvcp71/msvcp71.spec b/dlls/msvcp71/msvcp71.spec
index 809ec0ea09b0..728e0e92d1d3 100644
--- a/dlls/msvcp71/msvcp71.spec
+++ b/dlls/msvcp71/msvcp71.spec
@@ -3065,9 +3065,9 @@
 @ cdecl -arch=win64 ?_Iput@?$num_put@GV?$ostreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@GU?$char_traits@G@std@@@2@V32@AEAVios_base@2@GPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_short__Iput
 @ cdecl -arch=win32 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@ABA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AAVios_base@2@_WPADI@Z(ptr ptr long ptr ptr long ptr long) num_put_wchar__Iput
 @ cdecl -arch=win64 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AEAVios_base@2@_WPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_wchar__Iput
-@ stub ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z
-@ stub ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z
-@ stub ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z
+@ cdecl ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isinf
 @ cdecl ?_Isnan@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isnan
diff --git a/dlls/msvcp80/msvcp80.spec b/dlls/msvcp80/msvcp80.spec
index f653bc066647..e0c1beb54864 100644
--- a/dlls/msvcp80/msvcp80.spec
+++ b/dlls/msvcp80/msvcp80.spec
@@ -3416,9 +3416,9 @@
 @ cdecl -arch=win64 ?_Iput@?$num_put@GV?$ostreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@GU?$char_traits@G@std@@@2@V32@AEAVios_base@2@GPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_short__Iput
 @ cdecl -arch=win32 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@ABA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AAVios_base@2@_WPADI@Z(ptr ptr long ptr ptr long ptr long) num_put_wchar__Iput
 @ cdecl -arch=win64 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AEAVios_base@2@_WPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_wchar__Iput
-@ stub ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z
-@ stub ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z
-@ stub ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z
+@ cdecl ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isinf
 @ cdecl ?_Isnan@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isnan
diff --git a/dlls/msvcp90/math.c b/dlls/msvcp90/math.c
index f413baf5b306..7a1dd6a7609a 100644
--- a/dlls/msvcp90/math.c
+++ b/dlls/msvcp90/math.c
@@ -861,6 +861,15 @@ std_Ctraits * __thiscall std_Ctraits_op_assign( std_Ctraits *this, std_Ctraits *
     return this;
 }
 
+/* ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z -> bool std::_Ctraits<float>::_Isinf(float) */
+BOOLEAN __cdecl std_Ctraits_float__Isinf( float x ) { return isinf(x); }
+
+/* ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z -> bool std::_Ctraits<double>::_Isinf(double) */
+BOOLEAN __cdecl std_Ctraits_double__Isinf( double x ) { return isinf(x); }
+
+/* ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z -> bool std::_Ctraits<long double>::_Isinf(long double) */
+BOOLEAN __cdecl std_Ctraits_long_double__Isinf( LDOUBLE x ) { return isinf(x); }
+
 /* ?_Isnan@?$_Ctraits@M@std@@SA_NM@Z -> public: static bool __cdecl std::_Ctraits<float>::_Isnan(float) */
 BOOLEAN __cdecl std_Ctraits_float__Isnan( float x ) { return _isnan(x); }
 
diff --git a/dlls/msvcp90/msvcp90.spec b/dlls/msvcp90/msvcp90.spec
index 9eae0f8f8c47..9a76733e7feb 100644
--- a/dlls/msvcp90/msvcp90.spec
+++ b/dlls/msvcp90/msvcp90.spec
@@ -3436,9 +3436,9 @@
 @ cdecl -arch=win64 ?_Iput@?$num_put@GV?$ostreambuf_iterator@GU?$char_traits@G@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@GU?$char_traits@G@std@@@2@V32@AEAVios_base@2@GPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_short__Iput
 @ cdecl -arch=win32 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@ABA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AAVios_base@2@_WPADI@Z(ptr ptr long ptr ptr long ptr long) num_put_wchar__Iput
 @ cdecl -arch=win64 ?_Iput@?$num_put@_WV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@std@@@std@@AEBA?AV?$ostreambuf_iterator@_WU?$char_traits@_W@std@@@2@V32@AEAVios_base@2@_WPEAD_K@Z(ptr ptr ptr ptr long ptr long) num_put_wchar__Iput
-@ stub ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z
-@ stub ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z
-@ stub ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z
+@ cdecl ?_Isinf@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isinf
+@ cdecl ?_Isinf@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isinf
 @ cdecl ?_Isnan@?$_Ctraits@M@std@@SA_NM@Z(float) std_Ctraits_float__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@N@std@@SA_NN@Z(double) std_Ctraits_double__Isnan
 @ cdecl ?_Isnan@?$_Ctraits@O@std@@SA_NO@Z(double) std_Ctraits_long_double__Isnan
diff --git a/dlls/msvproc/Makefile.in b/dlls/msvproc/Makefile.in
index f98b4d6d44b7..8bba759024f9 100644
--- a/dlls/msvproc/Makefile.in
+++ b/dlls/msvproc/Makefile.in
@@ -1,6 +1,8 @@
 MODULE    = msvproc.dll
-IMPORTS   = combase mfplat mfuuid dmoguids dxguid strmiids wmcodecdspuuid uuid
+IMPORTS   = $(FFMPEG_PE_LIBS) combase mfplat mfuuid dmoguids dxguid strmiids wmcodecdspuuid uuid
+EXTRAINCL = $(FFMPEG_PE_CFLAGS)
 
 SOURCES = \
 	msvproc.c \
-	msvproc.idl
+	msvproc.idl \
+	video_processor.c
diff --git a/dlls/msvproc/msvproc.c b/dlls/msvproc/msvproc.c
index fdf6a1cddb18..17c3b8def935 100644
--- a/dlls/msvproc/msvproc.c
+++ b/dlls/msvproc/msvproc.c
@@ -37,41 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(dmo);
 DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8);
 DEFINE_MEDIATYPE_GUID(MFVideoFormat_P208,MAKEFOURCC('P','2','0','8'));
 
-static HRESULT WINAPI video_processor_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
-        REFIID riid, void **out)
-{
-    static const GUID CLSID_wg_video_processor = {0xd527607f,0x89cb,0x4e94,{0x95,0x71,0xbc,0xfe,0x62,0x17,0x56,0x13}};
-    return CoCreateInstance(&CLSID_wg_video_processor, outer, CLSCTX_INPROC_SERVER, riid, out);
-}
-
-static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
-{
-    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
-    return *out ? S_OK : E_NOINTERFACE;
-}
-static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
-{
-    return 2;
-}
-static ULONG WINAPI class_factory_Release(IClassFactory *iface)
-{
-    return 1;
-}
-static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
-{
-    return S_OK;
-}
-
-static const IClassFactoryVtbl video_processor_factory_vtbl =
-{
-    class_factory_QueryInterface,
-    class_factory_AddRef,
-    class_factory_Release,
-    video_processor_factory_CreateInstance,
-    class_factory_LockServer,
-};
-
-static IClassFactory video_processor_factory = {&video_processor_factory_vtbl};
+extern IClassFactory video_processor_factory;
 
 /***********************************************************************
  *              DllGetClassObject (msvproc.@)
diff --git a/dlls/winegstreamer/video_processor.c b/dlls/msvproc/video_processor.c
similarity index 50%
rename from dlls/winegstreamer/video_processor.c
rename to dlls/msvproc/video_processor.c
index 301a76ca91ce..f2ad3e0fe780 100644
--- a/dlls/winegstreamer/video_processor.c
+++ b/dlls/msvproc/video_processor.c
@@ -15,23 +15,264 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
-#include "gst_private.h"
+#include <stddef.h>
+#include <stdarg.h>
 
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+
+#include "d3d9types.h"
+#include "dshow.h"
+#include "dvdmedia.h"
 #include "mfapi.h"
+#include "mfidl.h"
 #include "mferror.h"
 #include "mfobjects.h"
 #include "mftransform.h"
-#include "wmcodecdsp.h"
+
+#include <libavutil/avutil.h>
+#include <libavutil/imgutils.h>
+#include <libavutil/opt.h>
+#include <libswscale/swscale.h>
 
 #include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
+WINE_DEFAULT_DEBUG_CHANNEL(dmo);
 
-extern GUID MFVideoFormat_ABGR32;
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_ABGR32, D3DFMT_A8B8G8R8);
+DEFINE_MEDIATYPE_GUID(MFVideoFormat_P208,MAKEFOURCC('P','2','0','8'));
 
 static const GUID MF_XVP_PLAYBACK_MODE = { 0x3c5d293f, 0xad67, 0x4e29, { 0xaf, 0x12, 0xcf, 0x3e, 0x23, 0x8a, 0xcc, 0xe9 } };
 
+static const AVRational USER_TIME_BASE_Q = {1, 10000000};
+
+static const char *debugstr_avtime(INT64 time, AVRational time_base)
+{
+    time = av_rescale_q_rnd(time, time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX);
+    if (time == AV_NOPTS_VALUE)
+        return "(none)";
+    return wine_dbg_sprintf("%I64d", time);
+}
+
+static const char *debugstr_avframe(AVFrame *frame)
+{
+    return wine_dbg_sprintf("fmt %s %dx%d stride %d", av_get_pix_fmt_name(frame->format),
+            frame->width, frame->height, frame->linesize[0]);
+}
+
+static enum AVPixelFormat pixel_format_from_video_subtype(const GUID *subtype)
+{
+    switch (subtype->Data1)
+    {
+    /* MFVideoFormat_420O */   case MAKEFOURCC('4','2','0','O'): break;
+    /* MFVideoFormat_AYUV */   case MAKEFOURCC('A','Y','U','V'): return AV_PIX_FMT_AYUV;
+    /* MFVideoFormat_I420 */   case MAKEFOURCC('I','4','2','0'): return AV_PIX_FMT_YUV420P;
+    /* MFVideoFormat_IYUV */   case MAKEFOURCC('I','Y','U','V'): return AV_PIX_FMT_YUV420P;
+    /* MFVideoFormat_NV11 */   case MAKEFOURCC('N','V','1','1'): return AV_PIX_FMT_YUV411P;
+    /* MFVideoFormat_NV12 */   case MAKEFOURCC('N','V','1','2'): return AV_PIX_FMT_NV12;
+    /* MFVideoFormat_P208 */   case MAKEFOURCC('P','2','0','8'): break;
+    /* MFVideoFormat_UYVY */   case MAKEFOURCC('U','Y','V','Y'): return AV_PIX_FMT_UYVY422;
+    /* MFVideoFormat_v410 */   case MAKEFOURCC('v','4','1','0'): break;
+    /* MFVideoFormat_Y216 */   case MAKEFOURCC('Y','2','1','6'): return AV_PIX_FMT_Y216;
+    /* MFVideoFormat_Y41P */   case MAKEFOURCC('Y','4','1','P'): break;
+    /* MFVideoFormat_Y41T */   case MAKEFOURCC('Y','4','1','T'): break;
+    /* MFVideoFormat_Y42T */   case MAKEFOURCC('Y','4','2','T'): break;
+    /* MFVideoFormat_YUY2 */   case MAKEFOURCC('Y','U','Y','2'): return AV_PIX_FMT_YUYV422;
+    /* MFVideoFormat_YV12 */   case MAKEFOURCC('Y','V','1','2'): return AV_PIX_FMT_YUV420P;
+    /* MFVideoFormat_YVYU */   case MAKEFOURCC('Y','V','Y','U'): return AV_PIX_FMT_YVYU422;
+    /* MFVideoFormat_ABGR32 */ case D3DFMT_A8B8G8R8:             return AV_PIX_FMT_RGBA;
+    /* MFVideoFormat_ARGB32 */ case D3DFMT_A8R8G8B8:             return AV_PIX_FMT_BGRA;
+    /* MFVideoFormat_RGB24 */  case D3DFMT_R8G8B8:               return AV_PIX_FMT_BGR24;
+    /* MFVideoFormat_RGB32 */  case D3DFMT_X8R8G8B8:             return AV_PIX_FMT_BGR0;
+    /* MFVideoFormat_RGB555 */ case D3DFMT_X1R5G5B5:             return AV_PIX_FMT_RGB555;
+    /* MFVideoFormat_RGB565 */ case D3DFMT_R5G6B5:               return AV_PIX_FMT_RGB565;
+    /* MFVideoFormat_RGB8 */   case D3DFMT_P8:                   return AV_PIX_FMT_RGB8;
+    }
+
+    FIXME("Unsupported subtype %s (%s)\n", debugstr_guid(subtype), debugstr_fourcc(subtype->Data1));
+    return AV_PIX_FMT_NONE;
+}
+
+static void video_frame_init_aperture(AVFrame *frame, const MFVIDEOFORMAT *format)
+{
+    if (format->videoInfo.MinimumDisplayAperture.OffsetX.value
+            || format->videoInfo.MinimumDisplayAperture.OffsetY.value
+            || format->videoInfo.MinimumDisplayAperture.Area.cx
+            || format->videoInfo.MinimumDisplayAperture.Area.cy)
+    {
+        frame->width = format->videoInfo.MinimumDisplayAperture.OffsetX.value +
+                format->videoInfo.MinimumDisplayAperture.Area.cx;
+        frame->height = format->videoInfo.MinimumDisplayAperture.OffsetY.value +
+                format->videoInfo.MinimumDisplayAperture.Area.cy;
+    }
+    else
+    {
+        frame->width = format->videoInfo.dwWidth;
+        frame->height = format->videoInfo.dwHeight;
+    }
+}
+
+static void media_buffer_release(void *opaque, uint8_t *data)
+{
+    IMediaBuffer *media_buffer = opaque;
+    IMF2DBuffer2 *buffer2;
+
+    if (SUCCEEDED(IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2)))
+    {
+        IMF2DBuffer2_Unlock2D(buffer2);
+        IMF2DBuffer2_Release(buffer2);
+    }
+    IMediaBuffer_Release(media_buffer);
+}
+
+static AVBufferRef *buffer_from_media_buffer(IMediaBuffer *media_buffer, int flags, LONG *pitch)
+{
+    BYTE *data, *scanline0;
+    IMF2DBuffer2 *buffer2;
+    AVBufferRef *buffer;
+    HRESULT hr;
+    DWORD size;
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(media_buffer, &IID_IMF2DBuffer2, (void **)&buffer2)))
+    {
+        MF2DBuffer_LockFlags lock_flags = (flags & AV_BUFFER_FLAG_READONLY) ? MF2DBuffer_LockFlags_Read
+                : MF2DBuffer_LockFlags_Write;
+        hr = IMF2DBuffer2_Lock2DSize(buffer2, lock_flags, &scanline0, pitch, &data, &size);
+        IMF2DBuffer2_Release(buffer2);
+    }
+    if (FAILED(hr))
+    {
+        if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &data, &size)))
+            return NULL;
+        if (!flags && FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &size)))
+            return NULL;
+        *pitch = 0;
+    }
+
+    if (!(buffer = av_buffer_create(data, size, media_buffer_release, media_buffer, flags)))
+        return NULL;
+    IMediaBuffer_AddRef(media_buffer);
+    return buffer;
+}
+
+static void video_frame_init_from_format(AVFrame *frame, const MFVIDEOFORMAT *format)
+{
+    frame->format = pixel_format_from_video_subtype(&format->guidFormat);
+    frame->width = format->videoInfo.dwWidth;
+    frame->height = format->videoInfo.dwHeight;
+    frame->color_range = AVCOL_RANGE_UNSPECIFIED;
+    frame->color_primaries = AVCOL_PRI_UNSPECIFIED;
+    frame->color_trc = AVCOL_TRC_UNSPECIFIED;
+    frame->colorspace = AVCOL_SPC_UNSPECIFIED;
+    frame->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
+}
+
+static int fill_arrays_with_format(uint8_t *planes[4], int strides[4], AVBufferRef *buffer,
+        const MFVIDEOFORMAT *format, LONG pitch)
+{
+    enum AVPixelFormat pix_fmt = pixel_format_from_video_subtype(&format->guidFormat);
+    UINT width = format->videoInfo.dwWidth, height = format->videoInfo.dwHeight;
+    int size;
+
+    size = av_image_fill_arrays(planes, strides, buffer->data, pix_fmt, width, height, 1);
+    TRACE("buffer %p / %#Ix size %d pitch %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size,
+            size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]);
+    if (size > buffer->size)
+    {
+        ERR("stride %ld linesize %u,%u,%u,%u size %#x buffer %#Ix\n", pitch, strides[0], strides[1],
+                strides[2], strides[3], size, buffer->size);
+        return -1;
+    }
+
+    if (pitch && abs(pitch) != strides[0])
+    {
+        int new_strides[4] = {0};
+        for (int i = 0; i < 4; i++) new_strides[i] = (abs(pitch) * strides[i]) / strides[0];
+        for (int i = 1; i < 4 && planes[i]; i++)
+        {
+            size_t height = (planes[i] - planes[i - 1]) / strides[i - 1];
+            planes[i] = planes[i - 1] + height * new_strides[i - 1];
+        }
+        memcpy(strides, new_strides, sizeof(new_strides));
+    }
+
+    if ((format->videoInfo.VideoFlags & MFVideoFlag_BottomUpLinearRep) && pitch <= 0)
+    {
+        planes[0] = planes[0] + strides[0] * (format->videoInfo.dwHeight - 1);
+        strides[0] = -strides[0];
+    }
+
+    TRACE("buffer %p / %#Ix size %d stride %ld, planes %p,%p,%p strides %d,%d,%d\n", buffer->data, buffer->size,
+            size, pitch, planes[0], planes[1], planes[2], strides[0], strides[1], strides[2]);
+    return size;
+}
+
+static BOOL check_arrays_alignment(uint8_t *planes[4], int strides[4], int size, int align)
+{
+    if (size % align)
+        return FALSE;
+    for (int i = 0; i < 4; i++)
+        if ((UINT_PTR)planes[i] % align)
+            return FALSE;
+    for (int i = 0; i < 4; i++)
+        if (strides[i] % align)
+            return FALSE;
+    return TRUE;
+}
+
+static BOOL video_frame_wrap_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer, LONG pitch)
+{
+    int size;
+
+    TRACE("frame %p, info %p, buffer %p\n", frame, format, buffer);
+
+    video_frame_init_from_format(frame, format);
+    video_frame_init_aperture(frame, format);
+
+    if ((size = fill_arrays_with_format(frame->data, frame->linesize, buffer, format, pitch)) < 0)
+        return size;
+    /* swscale requires 16byte alignment for data pointers when SSE2 optimizations are used. */
+    if (!check_arrays_alignment(frame->data, frame->linesize, size, 16))
+    {
+        ERR("frame %s isn't aligned to 16 bytes\n", debugstr_avframe(frame));
+        return -1;
+    }
+
+    frame->opaque = (void *)-1;
+    frame->buf[0] = av_buffer_ref(buffer);
+    frame->extended_data = frame->data;
+    return size;
+}
+
+static int video_frame_copy_from_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer,
+        LONG pitch)
+{
+    int size, input_strides[4];
+    UINT8 *input_planes[4];
+
+    ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer);
+
+    size = fill_arrays_with_format(input_planes, input_strides, buffer, format, pitch);
+    av_image_copy(frame->data, frame->linesize, (const UINT8 **)input_planes, input_strides,
+            frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight);
+    return size;
+}
+
+static int video_frame_copy_to_buffer(AVFrame *frame, const MFVIDEOFORMAT *format, AVBufferRef *buffer,
+        LONG pitch)
+{
+    int size, output_strides[4];
+    UINT8 *output_planes[4];
+
+    ERR("frame %s, format %p, buffer %p\n", debugstr_avframe(frame), format, buffer);
+
+    size = fill_arrays_with_format(output_planes, output_strides, buffer, format, pitch);
+    av_image_copy(output_planes, output_strides, (const UINT8 **)frame->data, frame->linesize,
+            frame->format, format->videoInfo.dwWidth, format->videoInfo.dwHeight);
+    return size;
+}
+
 static const GUID *const input_types[] =
 {
     &MFVideoFormat_IYUV,
@@ -82,17 +323,176 @@ struct video_processor
     IMFAttributes *output_attributes;
 
     IMFMediaType *input_type;
+    MFVIDEOFORMAT *input_format;
     MFT_INPUT_STREAM_INFO input_info;
     IMFMediaType *output_type;
+    MFVIDEOFORMAT *output_format;
     MFT_OUTPUT_STREAM_INFO output_info;
 
-    wg_transform_t wg_transform;
-    struct wg_sample_queue *wg_sample_queue;
+    SwsContext *context;
+    AVFrame input_frame;
+    AVFrame output_frame;
+    AVFrame current_frame;
 
     IUnknown *device_manager;
     IMFVideoSampleAllocatorEx *allocator;
 };
 
+static HRESULT video_processor_process_frame(struct video_processor *impl, AVFrame *input_frame,
+        DMO_OUTPUT_DATA_BUFFER *output)
+{
+    AVFrame output_frame = {0};
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    int size, ret;
+    LONG pitch;
+    HRESULT hr;
+
+    if (!(buffer = buffer_from_media_buffer(output->pBuffer, 0, &pitch)))
+        return E_OUTOFMEMORY;
+    if ((size = video_frame_wrap_buffer(&output_frame, impl->output_format, buffer, pitch)) < 0)
+        av_frame_move_ref(&output_frame, &impl->output_frame);
+
+    TRACE("input %s output %s\n", debugstr_avframe(input_frame), debugstr_avframe(&output_frame));
+
+    if ((ret = sws_scale_frame(impl->context, &output_frame, input_frame)) < 0)
+        ERR("error ret %d (%s)\n", -ret, av_err2str(ret));
+    else if ((ret = size) < 0)
+        ret = video_frame_copy_to_buffer(&output_frame, impl->output_format, buffer, pitch);
+
+    av_buffer_unref(&buffer);
+
+    if (!output_frame.opaque)
+        av_frame_move_ref(&impl->output_frame, &output_frame);
+    else
+        av_frame_unref(&output_frame);
+
+    output->dwStatus = 0;
+    IMediaBuffer_SetLength(output->pBuffer, ret >= 0 ? ret : 0);
+    if (ret < 0)
+        return E_FAIL;
+    if (!ret)
+        return MF_E_TRANSFORM_NEED_MORE_INPUT;
+
+    if (input_frame->flags & AV_FRAME_FLAG_KEY)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
+    output->rtTimestamp = input_frame->pts;
+    if (output->rtTimestamp != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME;
+    output->rtTimelength = input_frame->duration;
+    if (output->rtTimelength != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(output->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (output->rtTimestamp != INT64_MIN)
+            IMFSample_SetSampleTime(sample, output->rtTimestamp);
+        if (output->rtTimelength != INT64_MIN)
+            IMFSample_SetSampleDuration(sample, output->rtTimelength);
+        if (output->dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT)
+            IMFSample_SetUINT32(sample, &MFSampleExtension_CleanPoint, 1);
+        IMFSample_Release(sample);
+    }
+
+    TRACE("returning output size %#x, pts %s, duration %s status %#lx\n", ret,
+            debugstr_avtime(output->rtTimestamp, USER_TIME_BASE_Q),
+            debugstr_avtime(output->rtTimelength, USER_TIME_BASE_Q), output->dwStatus);
+    return S_OK;
+}
+
+static HRESULT video_processor_process_input(struct video_processor *impl, const DMO_OUTPUT_DATA_BUFFER *input)
+{
+    LONGLONG pts = input->rtTimestamp, duration = input->rtTimelength;
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    HRESULT hr;
+    LONG pitch;
+    int ret;
+
+    if (!impl->context)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    if (impl->current_frame.width)
+        return MF_E_NOTACCEPTING;
+
+    if (!(buffer = buffer_from_media_buffer(input->pBuffer, AV_BUFFER_FLAG_READONLY, &pitch)))
+        return E_OUTOFMEMORY;
+    if ((ret = video_frame_wrap_buffer(&impl->current_frame, impl->input_format, buffer, pitch)) < 0)
+    {
+        ret = video_frame_copy_from_buffer(&impl->input_frame, impl->input_format, buffer, pitch);
+        av_frame_move_ref(&impl->current_frame, &impl->input_frame);
+    }
+    av_buffer_unref(&buffer);
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(input->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (FAILED(IMFSample_GetSampleTime(sample, &pts)))
+            pts = INT64_MIN;
+        if (FAILED(IMFSample_GetSampleDuration(sample, &duration)))
+            duration = INT64_MIN;
+        IMFSample_Release(sample);
+    }
+
+    impl->current_frame.pts = pts;
+    impl->current_frame.duration = duration;
+    TRACE("input frame %s, time %s, duration %s\n", debugstr_avframe(&impl->current_frame),
+            debugstr_avtime(impl->current_frame.pts, USER_TIME_BASE_Q),
+            debugstr_avtime(impl->current_frame.duration, USER_TIME_BASE_Q));
+    return S_OK;
+}
+
+static HRESULT video_processor_process_output(struct video_processor *impl, DMO_OUTPUT_DATA_BUFFER *output)
+{
+    HRESULT hr;
+
+    if (!impl->context)
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    if (!impl->current_frame.width)
+        return MF_E_TRANSFORM_NEED_MORE_INPUT;
+
+    hr = video_processor_process_frame(impl, &impl->current_frame, output);
+    if (!impl->current_frame.opaque)
+        av_frame_move_ref(&impl->input_frame, &impl->current_frame);
+    else
+        av_frame_unref(&impl->current_frame);
+
+    return hr;
+}
+
+static void video_processor_cleanup(struct video_processor *impl)
+{
+    CoTaskMemFree(impl->output_format);
+    impl->output_format = NULL;
+    CoTaskMemFree(impl->input_format);
+    impl->input_format = NULL;
+    av_frame_unref(&impl->current_frame);
+    av_frame_unref(&impl->output_frame);
+    av_frame_unref(&impl->input_frame);
+    sws_free_context(&impl->context);
+}
+
+static BOOL is_mf_video_area_empty(const MFVideoArea *area)
+{
+    return !area->OffsetX.value && !area->OffsetY.value && !area->Area.cx && !area->Area.cy;
+}
+
+static void get_mf_video_content_rect(const MFVideoInfo *info, RECT *rect)
+{
+    if (!is_mf_video_area_empty(&info->MinimumDisplayAperture))
+    {
+        rect->left = info->MinimumDisplayAperture.OffsetX.value;
+        rect->top = info->MinimumDisplayAperture.OffsetY.value;
+        rect->right = rect->left + info->MinimumDisplayAperture.Area.cx;
+        rect->bottom = rect->top + info->MinimumDisplayAperture.Area.cy;
+    }
+    else
+    {
+        rect->left = 0;
+        rect->top = 0;
+        rect->right = info->dwWidth;
+        rect->bottom = info->dwHeight;
+    }
+}
+
 static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info)
 {
     RECT input_rect, output_rect;
@@ -113,65 +513,68 @@ static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_i
     output_info->MinimumDisplayAperture = input_info->MinimumDisplayAperture;
 }
 
-static HRESULT normalize_media_types(BOOL bottom_up, IMFMediaType **input_type, IMFMediaType **output_type)
+static HRESULT create_video_format(BOOL bottom_up, IMFMediaType *media_type, MFVIDEOFORMAT **format)
 {
-    MFVIDEOFORMAT *input_format, *output_format;
-    BOOL normalize_input, normalize_output;
+    LONG stride;
     UINT32 size;
     HRESULT hr;
 
-    normalize_input = FAILED(IMFMediaType_GetItem(*input_type, &MF_MT_DEFAULT_STRIDE, NULL));
-    normalize_output = FAILED(IMFMediaType_GetItem(*output_type, &MF_MT_DEFAULT_STRIDE, NULL));
-
-    if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*input_type, &input_format, &size)))
-        return hr;
-    if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*output_type, &output_format, &size)))
-    {
-        CoTaskMemFree(input_format);
+    if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(media_type, format, &size)))
         return hr;
-    }
-
-    if (bottom_up && normalize_input)
-        input_format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
-    if (bottom_up && normalize_output)
-        output_format->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
-
-    update_video_aperture(&input_format->videoInfo, &output_format->videoInfo);
-
-    if (FAILED(hr = MFCreateVideoMediaType(input_format, (IMFVideoMediaType **)input_type)))
-        goto done;
-    if (FAILED(hr = MFCreateVideoMediaType(output_format, (IMFVideoMediaType **)output_type)))
-    {
-        IMFMediaType_Release(*input_type);
-        *input_type = NULL;
-    }
-
-done:
-    CoTaskMemFree(input_format);
-    CoTaskMemFree(output_format);
+    if (bottom_up && FAILED(IMFMediaType_GetItem(media_type, &MF_MT_DEFAULT_STRIDE, NULL))
+            && SUCCEEDED(MFGetStrideForBitmapInfoHeader((*format)->guidFormat.Data1, 1, &stride)) && stride < 0)
+        (*format)->videoInfo.VideoFlags |= MFVideoFlag_BottomUpLinearRep;
     return hr;
 }
 
-static HRESULT try_create_wg_transform(struct video_processor *impl)
+static HRESULT video_processor_init(struct video_processor *impl)
 {
     BOOL bottom_up = !impl->device_manager; /* when not D3D-enabled, the transform outputs bottom up RGB buffers */
-    IMFMediaType *input_type = impl->input_type, *output_type = impl->output_type;
-    struct wg_transform_attrs attrs = {0};
     HRESULT hr;
+    int ret;
 
-    if (impl->wg_transform)
+    video_processor_cleanup(impl);
+
+    if (!(impl->context = sws_alloc_context()))
+        return E_OUTOFMEMORY;
+    if (FAILED(hr = create_video_format(bottom_up, impl->input_type, &impl->input_format))
+            || FAILED(hr = create_video_format(bottom_up, impl->output_type, &impl->output_format)))
     {
-        wg_transform_destroy(impl->wg_transform);
-        impl->wg_transform = 0;
+        video_processor_cleanup(impl);
+        return hr;
     }
 
-    if (FAILED(hr = normalize_media_types(bottom_up, &input_type, &output_type)))
-        return hr;
-    hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform);
-    IMFMediaType_Release(output_type);
-    IMFMediaType_Release(input_type);
+    update_video_aperture(&impl->input_format->videoInfo, &impl->output_format->videoInfo);
 
-    return hr;
+    video_frame_init_from_format(&impl->input_frame, impl->input_format);
+    if ((ret = av_frame_get_buffer(&impl->input_frame, 0)) < 0)
+        goto failed;
+    video_frame_init_aperture(&impl->input_frame, impl->input_format);
+
+    video_frame_init_from_format(&impl->output_frame, impl->output_format);
+    if ((ret = av_frame_get_buffer(&impl->output_frame, 0)) < 0)
+        goto failed;
+    video_frame_init_aperture(&impl->output_frame, impl->input_format);
+
+    av_opt_set(impl->context, "sws_flags", "neighbor", 0);
+    av_opt_set_int(impl->context, "threads", 0, 0);
+    av_opt_set_int(impl->context, "srcw", impl->input_frame.width, 0);
+    av_opt_set_int(impl->context, "srch", impl->input_frame.height, 0);
+    av_opt_set_pixel_fmt(impl->context, "src_format", impl->input_frame.format, 0);
+    av_opt_set_int(impl->context, "dstw", impl->output_frame.width, 0);
+    av_opt_set_int(impl->context, "dsth", impl->output_frame.height, 0);
+    av_opt_set_pixel_fmt(impl->context, "dst_format", impl->output_frame.format, 0);
+
+    if ((ret = sws_init_context(impl->context, NULL, NULL)) < 0)
+        goto failed;
+
+    TRACE("input %s -> output %s\n", debugstr_avframe(&impl->input_frame), debugstr_avframe(&impl->output_frame));
+    return S_OK;
+
+failed:
+    ERR("ret %d\n", ret);
+    video_processor_cleanup(impl);
+    return E_FAIL;
 }
 
 static HRESULT video_processor_init_allocator(struct video_processor *processor)
@@ -260,8 +663,6 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface)
         video_processor_uninit_allocator(impl);
         if (impl->device_manager)
             IUnknown_Release(impl->device_manager);
-        if (impl->wg_transform)
-            wg_transform_destroy(impl->wg_transform);
         if (impl->input_type)
             IMFMediaType_Release(impl->input_type);
         if (impl->output_type)
@@ -270,8 +671,7 @@ static ULONG WINAPI video_processor_Release(IMFTransform *iface)
             IMFAttributes_Release(impl->attributes);
         if (impl->output_attributes)
             IMFAttributes_Release(impl->output_attributes);
-
-        wg_sample_queue_destroy(impl->wg_sample_queue);
+        video_processor_cleanup(impl);
         free(impl);
     }
 
@@ -461,12 +861,7 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id
             IMFMediaType_Release(impl->input_type);
             impl->input_type = NULL;
         }
-        if (impl->wg_transform)
-        {
-            wg_transform_destroy(impl->wg_transform);
-            impl->wg_transform = 0;
-        }
-
+        video_processor_cleanup(impl);
         return S_OK;
     }
 
@@ -490,7 +885,7 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id
         IMFMediaType_Release(impl->input_type);
     IMFMediaType_AddRef((impl->input_type = type));
 
-    if (impl->output_type && FAILED(hr = try_create_wg_transform(impl)))
+    if (impl->output_type && FAILED(hr = video_processor_init(impl)))
     {
         IMFMediaType_Release(impl->input_type);
         impl->input_type = NULL;
@@ -499,7 +894,6 @@ static HRESULT WINAPI video_processor_SetInputType(IMFTransform *iface, DWORD id
     if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size,
             (UINT32 *)&impl->input_info.cbSize)))
         impl->input_info.cbSize = 0;
-
     return hr;
 }
 
@@ -520,12 +914,7 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i
             IMFMediaType_Release(impl->output_type);
             impl->output_type = NULL;
         }
-        if (impl->wg_transform)
-        {
-            wg_transform_destroy(impl->wg_transform);
-            impl->wg_transform = 0;
-        }
-
+        video_processor_cleanup(impl);
         return S_OK;
     }
 
@@ -552,7 +941,7 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i
         IMFMediaType_Release(impl->output_type);
     IMFMediaType_AddRef((impl->output_type = type));
 
-    if (impl->input_type && FAILED(hr = try_create_wg_transform(impl)))
+    if (impl->input_type && FAILED(hr = video_processor_init(impl)))
     {
         IMFMediaType_Release(impl->output_type);
         impl->output_type = NULL;
@@ -561,7 +950,6 @@ static HRESULT WINAPI video_processor_SetOutputType(IMFTransform *iface, DWORD i
     if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size,
             (UINT32 *)&impl->output_info.cbSize)))
         impl->output_info.cbSize = 0;
-
     return hr;
 }
 
@@ -681,32 +1069,45 @@ static HRESULT WINAPI video_processor_ProcessMessage(IMFTransform *iface, MFT_ME
 static HRESULT WINAPI video_processor_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
 {
     struct video_processor *impl = impl_from_IMFTransform(iface);
+    DMO_OUTPUT_DATA_BUFFER input = {.dwStatus = flags};
+    IMFMediaBuffer *buffer;
+    HRESULT hr;
 
     TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
 
-    if (!impl->wg_transform)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+        return hr;
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &input.pBuffer)))
+    {
+        hr = video_processor_process_input(impl, &input);
+        IMediaBuffer_Release(input.pBuffer);
+    }
+    IMFMediaBuffer_Release(buffer);
 
-    return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue);
+    return hr;
 }
 
 static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
-        MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
+        MFT_OUTPUT_DATA_BUFFER *output, DWORD *output_status)
 {
     struct video_processor *impl = impl_from_IMFTransform(iface);
+    DMO_OUTPUT_DATA_BUFFER dmo_output = {0};
+    BOOL playback_mode, provide_samples;
     IMFSample *output_sample;
+    IMFMediaBuffer *buffer;
     HRESULT hr;
-    BOOL playback_mode, provide_samples;
 
-    TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
+    TRACE("iface %p, flags %#lx, count %lu, output %p, output_status %p.\n", iface, flags, count,
+            output, output_status);
 
     if (count != 1)
         return E_INVALIDARG;
-
-    if (!impl->wg_transform)
+    if (!impl->input_format || !impl->output_format)
         return MF_E_TRANSFORM_TYPE_NOT_SET;
+    if (!impl->current_frame.width)
+        return MF_E_TRANSFORM_NEED_MORE_INPUT;
 
-    samples->dwStatus = 0;
+    output->dwStatus = 0;
 
     if (FAILED(IMFAttributes_GetUINT32(impl->attributes, &MF_XVP_PLAYBACK_MODE, (UINT32 *) &playback_mode)))
         playback_mode = FALSE;
@@ -722,18 +1123,26 @@ static HRESULT WINAPI video_processor_ProcessOutput(IMFTransform *iface, DWORD f
     }
     else
     {
-        if (!(output_sample = samples->pSample))
+        if (!(output_sample = output->pSample))
             return E_INVALIDARG;
         IMFSample_AddRef(output_sample);
     }
 
-    if (FAILED(hr = wg_transform_read_mf(impl->wg_transform, output_sample, impl->output_info.cbSize, &samples->dwStatus, NULL)))
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(output_sample, &buffer)))
         goto done;
-    wg_sample_queue_flush(impl->wg_sample_queue, false);
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(output_sample, buffer, 0,
+                          &dmo_output.pBuffer)))
+    {
+        hr = video_processor_process_output(impl, &dmo_output);
+        IMediaBuffer_Release(dmo_output.pBuffer);
+    }
+    IMFMediaBuffer_Release(buffer);
+
+    output->dwStatus = *output_status = 0;
 
     if (provide_samples)
     {
-        samples->pSample = output_sample;
+        output->pSample = output_sample;
         IMFSample_AddRef(output_sample);
     }
 
@@ -772,30 +1181,27 @@ static const IMFTransformVtbl video_processor_vtbl =
     video_processor_ProcessOutput,
 };
 
-HRESULT video_processor_create(REFIID riid, void **ret)
+static const char *debugstr_version(UINT version)
+{
+    return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),
+            AV_VERSION_MICRO(version));
+}
+
+static HRESULT WINAPI video_processor_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
+        REFIID riid, void **out)
 {
-    const MFVIDEOFORMAT input_format =
-    {
-        .dwSize = sizeof(MFVIDEOFORMAT),
-        .videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
-        .guidFormat = MFVideoFormat_I420,
-    };
-    const MFVIDEOFORMAT output_format =
-    {
-        .dwSize = sizeof(MFVIDEOFORMAT),
-        .videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
-        .guidFormat = MFVideoFormat_NV12,
-    };
     struct video_processor *impl;
     HRESULT hr;
 
-    TRACE("riid %s, ret %p.\n", debugstr_guid(riid), ret);
+    TRACE("outer %p, riid %s, out %p.\n", outer, debugstr_guid(riid), out);
 
-    if (FAILED(hr = check_video_transform_support(&input_format, &output_format)))
-    {
-        ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n");
-        return hr;
-    }
+    *out = NULL;
+
+    if (outer)
+        return CLASS_E_NOAGGREGATION;
+
+    TRACE("avutil version %s\n", debugstr_version(avutil_version()));
+    TRACE("swscale version %s\n", debugstr_version(swscale_version()));
 
     if (!(impl = calloc(1, sizeof(*impl))))
         return E_OUTOFMEMORY;
@@ -809,14 +1215,12 @@ HRESULT video_processor_create(REFIID riid, void **ret)
         goto failed;
     if (FAILED(hr = MFCreateAttributes(&impl->output_attributes, 0)))
         goto failed;
-    if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue)))
-        goto failed;
 
     impl->IMFTransform_iface.lpVtbl = &video_processor_vtbl;
     impl->refcount = 1;
+    TRACE("Created video processor %p\n", impl);
 
-    *ret = &impl->IMFTransform_iface;
-    TRACE("Created %p\n", *ret);
+    *out = &impl->IMFTransform_iface;
     return S_OK;
 
 failed:
@@ -824,6 +1228,36 @@ failed:
         IMFAttributes_Release(impl->output_attributes);
     if (impl->attributes)
         IMFAttributes_Release(impl->attributes);
+    sws_free_context(&impl->context);
     free(impl);
     return hr;
 }
+
+static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
+{
+    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
+    return *out ? S_OK : E_NOINTERFACE;
+}
+static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+static ULONG WINAPI class_factory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    return S_OK;
+}
+
+static const IClassFactoryVtbl video_processor_factory_vtbl =
+{
+    class_factory_QueryInterface,
+    class_factory_AddRef,
+    class_factory_Release,
+    video_processor_factory_CreateInstance,
+    class_factory_LockServer,
+};
+
+IClassFactory video_processor_factory = {&video_processor_factory_vtbl};
diff --git a/dlls/msxml3/Makefile.in b/dlls/msxml3/Makefile.in
index 85cddced2b19..90d90ea4f12a 100644
--- a/dlls/msxml3/Makefile.in
+++ b/dlls/msxml3/Makefile.in
@@ -44,6 +44,4 @@ SOURCES = \
 	xmlparser.c \
 	xmlparser.idl \
 	xmlview.c \
-	xpath.c \
-	xslpattern.l \
-	xslpattern.y
+	xpath.c
diff --git a/dlls/msxml3/selection.c b/dlls/msxml3/selection.c
index 159bf86f4e47..9e745e0cce4f 100644
--- a/dlls/msxml3/selection.c
+++ b/dlls/msxml3/selection.c
@@ -52,8 +52,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
 
-xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str);
-
 typedef struct
 {
     IEnumVARIANT IEnumVARIANT_iface;
@@ -598,25 +596,6 @@ static dispex_static_data_t domselection_dispex =
     domselection_iface_tids
 };
 
-static void xmlRegisterNamespaces(struct domnode *node, xmlXPathContextPtr ctxt)
-{
-    struct domnode *doc = node->owner ? node->owner : node;
-    const struct xpath_namespace *ns;
-    xmlChar *p, *uri;
-
-    LIST_FOR_EACH_ENTRY(ns, &doc->properties->namespaces.entries, struct xpath_namespace, entry)
-    {
-        if (*ns->prefix)
-        {
-            p = xmlchar_from_wchar(ns->prefix);
-            uri = xmlchar_from_wchar(ns->uri);
-            xmlXPathRegisterNs(ctxt, p, uri);
-            free(uri);
-            free(p);
-        }
-    }
-}
-
 static HRESULT select_nodes(struct domnode *node, const WCHAR *query, bool xpath, struct selected_list *list)
 {
     struct xpath_object *result;
@@ -625,31 +604,7 @@ static HRESULT select_nodes(struct domnode *node, const WCHAR *query, bool xpath
 
     ctxt = xpath_create_context(xpath, node);
 
-    if (xpath)
-    {
-        result = xpath_eval(query, ctxt);
-    }
-    else
-    {
-        xmlChar *xmlquery, *pattern_query;
-        xmlXPathContextPtr _ctxt;
-        BSTR _query;
-
-        xmlquery = xmlchar_from_wchar(query);
-        _ctxt = xmlXPathNewContext(NULL);
-        xmlRegisterNamespaces(node, _ctxt);
-
-        pattern_query = XSLPattern_to_XPath(_ctxt, xmlquery);
-        _query = bstr_from_xmlChar(pattern_query);
-        xmlFree(pattern_query);
-
-        result = xpath_eval(_query, ctxt);
-
-        xmlXPathFreeContext(_ctxt);
-        SysFreeString(_query);
-        free(xmlquery);
-    }
-
+    result = xpath_eval(query, ctxt);
     if (result && result->type == _XPATH_NODESET)
     {
         list->count = result->nodesetval ? result->nodesetval->count : 0;
diff --git a/dlls/msxml3/tests/domdoc.c b/dlls/msxml3/tests/domdoc.c
index a33c4f5c6f26..5464a76aa383 100644
--- a/dlls/msxml3/tests/domdoc.c
+++ b/dlls/msxml3/tests/domdoc.c
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <assert.h>
+#include <stdbool.h>
 
 #include "windows.h"
 
@@ -68,8 +69,6 @@ static void check_interface_(unsigned int line, void *iface_ptr, REFIID iid, BOO
         IUnknown_Release(unk);
 }
 
-static int g_unexpectedcall, g_expectedcall;
-
 struct msxmlsupported_data_t
 {
     const GUID *clsid;
@@ -199,7 +198,7 @@ static ULONG WINAPI dispevent_Release(IDispatch *iface)
 
 static HRESULT WINAPI dispevent_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo)
 {
-    g_unexpectedcall++;
+    ok(0, "unexpected call\n");
     *pctinfo = 0;
     return S_OK;
 }
@@ -207,14 +206,14 @@ static HRESULT WINAPI dispevent_GetTypeInfoCount(IDispatch *iface, UINT *pctinfo
 static HRESULT WINAPI dispevent_GetTypeInfo(IDispatch *iface, UINT iTInfo,
         LCID lcid, ITypeInfo **ppTInfo)
 {
-    g_unexpectedcall++;
+    ok(0, "unexpected call\n");
     return S_OK;
 }
 
 static HRESULT WINAPI dispevent_GetIDsOfNames(IDispatch *iface, REFIID riid,
         LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
 {
-    g_unexpectedcall++;
+    ok(0, "unexpected call\n");
     return S_OK;
 }
 
@@ -222,20 +221,7 @@ static HRESULT WINAPI dispevent_Invoke(IDispatch *iface, DISPID member, REFIID r
         LCID lcid, WORD flags, DISPPARAMS *params, VARIANT *result,
         EXCEPINFO *excepInfo, UINT *argErr)
 {
-    ok(member == 0, "expected 0 member, got %ld\n", member);
-    ok(lcid == LOCALE_SYSTEM_DEFAULT, "expected LOCALE_SYSTEM_DEFAULT, got lcid %lx\n", lcid);
-    ok(flags == DISPATCH_METHOD, "expected DISPATCH_METHOD, got %d\n", flags);
-
-    ok(params->cArgs == 0, "got %d\n", params->cArgs);
-    ok(params->cNamedArgs == 0, "got %d\n", params->cNamedArgs);
-    ok(params->rgvarg == NULL, "got %p\n", params->rgvarg);
-    ok(params->rgdispidNamedArgs == NULL, "got %p\n", params->rgdispidNamedArgs);
-
-    ok(result == NULL, "got %p\n", result);
-    ok(excepInfo == NULL, "got %p\n", excepInfo);
-    ok(argErr == NULL, "got %p\n", argErr);
-
-    g_expectedcall++;
+    ok(0, "unexpected call\n");
     return E_FAIL;
 }
 
@@ -888,6 +874,7 @@ static const CHAR szNodeTypesXML[] =
 "       <b id='4' depth='2'/>"
 "       <c id='5' depth='2'/>"
 "   </x>"
+"   <![CDATA[cdata node 1]]>"
 "   <y id='2' depth='1'>"
 "       <?bar value='PI for y'?>"
 "       <!-- comment node 3 -->"
@@ -896,6 +883,7 @@ static const CHAR szNodeTypesXML[] =
 "       <b id='7' depth='2'/>"
 "       <c id='8' depth='2'/>"
 "   </y>"
+"   <![CDATA[cdata node 2]]>"
 "</root>";
 
 static const CHAR szTransformXML[] =
@@ -1292,6 +1280,9 @@ static void get_str_for_type(DOMNodeType type, char *buf)
         case NODE_PROCESSING_INSTRUCTION:
             strcpy(buf, "P");
             break;
+        case NODE_CDATA_SECTION:
+            strcpy(buf, "CD");
+            break;
         default:
             wsprintfA(buf, "[%d]", type);
     }
@@ -4816,7 +4807,7 @@ static inline void _check_ws_ignored(int line, const char *ver, IXMLDOMDocument2
 
     helper_ole_check_ver(IXMLDOMNode_get_childNodes(node1, &list));
     helper_expect_list_and_release(list,
-            "[4]1.E1.E5.E1.E2.D1 T2.E1.E5.E1.E2.D1 E3.E1.E5.E1.E2.D1 "
+            "CD1.E1.E5.E1.E2.D1 T2.E1.E5.E1.E2.D1 E3.E1.E5.E1.E2.D1 "
             "E4.E1.E5.E1.E2.D1 E5.E1.E5.E1.E2.D1 E6.E1.E5.E1.E2.D1");
     helper_ole_check_ver(IXMLDOMNode_get_text(node1, &bstr));
     if (str)
@@ -4854,7 +4845,7 @@ static inline void _check_ws_preserved(int line, const char *ver, IXMLDOMDocumen
 
     helper_ole_check_ver(IXMLDOMNode_get_childNodes(node1, &list));
     helper_expect_list_and_release(list,
-            "T1.E2.E10.E2.E2.D1 [4]2.E2.E10.E2.E2.D1 T3.E2.E10.E2.E2.D1 "
+            "T1.E2.E10.E2.E2.D1 CD2.E2.E10.E2.E2.D1 T3.E2.E10.E2.E2.D1 "
             "E4.E2.E10.E2.E2.D1 T5.E2.E10.E2.E2.D1 E6.E2.E10.E2.E2.D1 "
             "E7.E2.E10.E2.E2.D1 E8.E2.E10.E2.E2.D1 T9.E2.E10.E2.E2.D1");
     helper_ole_check_ver(IXMLDOMNode_get_text(node1, &bstr));
@@ -5015,6 +5006,7 @@ static void test_whitespace(void)
     hr = IXMLDOMNode_get_text(node, &text);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!wcscmp(text, L"  "), "Unexpected text %s.\n", debugstr_w(text));
+    SysFreeString(text);
     {
         IXMLDOMNodeList *list;
 
@@ -5032,7 +5024,6 @@ static void test_whitespace(void)
         IXMLDOMNodeList_Release(list);
     }
     IXMLDOMNode_Release(node);
-    SysFreeString(text);
 
     hr = IXMLDOMNodeList_nextNode(list, &node);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
@@ -5274,12 +5265,16 @@ static const selection_ns_t selection_ns_data[] = {
     { NULL }
 };
 
-typedef struct {
+struct query_test
+{
     const char *query;
     const char *list;
-} xpath_test_t;
+    bool todo_result;
+    bool todo_evaluates;
+};
 
-static const xpath_test_t xpath_test[] = {
+static const struct query_test xpath_test[] =
+{
     { "*/a", "E1.E1.E2.D1 E1.E2.E2.D1 E1.E4.E2.D1" },
     { "*/b", "E2.E1.E2.D1 E2.E2.E2.D1 E2.E4.E2.D1" },
     { "*/c", "E3.E1.E2.D1 E3.E2.E2.D1" },
@@ -5289,6 +5284,7 @@ static const xpath_test_t xpath_test[] = {
     { "//c", "E3.E1.E2.D1 E3.E2.E2.D1" },
     { "//d", "E4.E1.E2.D1 E4.E2.E2.D1 E4.E4.E2.D1" },
     { "//c[@type]", "E3.E2.E2.D1" },
+    { "(//c[@type] | //c)", "E3.E1.E2.D1 E3.E2.E2.D1" },
     { "//c[@type]/ancestor::node()[1]", "E2.E2.D1" },
     { "//c[@type]/ancestor-or-self::node()[1]", "E3.E2.E2.D1" },
     { "//c[@type]/attribute::node()[1]", "A'type'.E3.E2.E2.D1" },
@@ -5311,13 +5307,82 @@ static const xpath_test_t xpath_test[] = {
     { "ancestor-or-self::node()[1]", "E2.D1" },
     { "((//a)[1])[last()]", "E1.E1.E2.D1" },
     { "//elem[@*]", "E2.E2.D1" },
+    { "//elem[a > 'a3 field']", "" },
+    { "//elem", "E1.E2.D1 E2.E2.D1 E4.E2.D1" },
+    { "//elem[1]//text()", "T1.E1.E1.E2.D1 T1.E2.E1.E2.D1 T1.E3.E1.E2.D1 T1.E4.E1.E2.D1 "
+            "CD1.E1.E5.E1.E2.D1 T2.E1.E5.E1.E2.D1 T1.E3.E1.E5.E1.E2.D1 T1.E4.E1.E5.E1.E2.D1 "
+            "T1.E5.E1.E5.E1.E2.D1 T1.E2.E5.E1.E2.D1 T1.E2.E2.E5.E1.E2.D1 T3.E2.E5.E1.E2.D1 "
+            "T1.E4.E2.E5.E1.E2.D1 T5.E2.E5.E1.E2.D1 T7.E2.E5.E1.E2.D1" },
+    { "node()", "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1" },
     { NULL }
 };
 
+#define test_query_result(test, list, status) test_query_result_(test, list, status, __LINE__)
+static void test_query_result_(const struct query_test *test, IXMLDOMNodeList *list, HRESULT status, int line)
+{
+    HRESULT hr = test->list ? S_OK : E_FAIL;
+
+    todo_wine_if(test->todo_evaluates)
+    ok_(__FILE__, line)(hr == status, "Unexpected status %#lx, expected %#lx.\n", status, hr);
+
+    if (hr == status && status == S_OK)
+    {
+        char *str = list_to_string(list);
+        todo_wine_if(test->todo_result)
+        ok_(__FILE__, line)(!strcmp(str, test->list), "Unexpected node list %s, expected %s\n",
+                *str ? str : "(empty)", test->list);
+    }
+}
+
 static void test_XPath(void)
 {
+    static const char node_value_cmp[] =
+        "<?xml version='1.0' encoding='utf-8'?>"
+        "<root>"
+        "    <elem min=\"-1\" max=\"100\" a=\"a\" />"
+        "    <elem min=\"10\" max=\"20\" a=\"b\" />"
+        "    <elem min=\"0\" max=\"0\" a=\"c\" />"
+        "    <elem min=\"-10\" max=\"-10\" />"
+        "</root>";
+
+    static const char pi[] =
+        "<?xml version='1.0' encoding='utf-8'?>"
+        "<root>"
+        "    <elem>"
+        "      <?pi ?>"
+        "    </elem>"
+        "    <elem>"
+        "      <?pi2 ?>"
+        "    </elem>"
+        "</root>";
+
+    static const struct query_test node_value_cmp_test[] =
+    {
+        { "//elem[@min <= 0 and @max >= 0]", "E1.E2.D1 E3.E2.D1" },
+        { "//elem[0 >= @min and 10 <= @max]", "E1.E2.D1" },
+        { "//elem[@min <= 0.0 and @max >= 0.0]", "E1.E2.D1 E3.E2.D1" },
+        { "//elem[0.0 >= @min and 10.0 <= @max]", "E1.E2.D1" },
+        { "//elem[@min <= \"0\" and @max >= \"0\"]", "E1.E2.D1 E3.E2.D1" },
+        { "//elem[\"0\" >= @min and \"10\" <= @max]", "E1.E2.D1" },
+
+        /* String value could only be compared for equality */
+        { "//elem[@a <= \"c\"]", "" },
+        { "//elem[@a = \"c\"]", "E3.E2.D1" },
+        { "//elem[@a != 0]", "E1.E2.D1 E2.E2.D1 E3.E2.D1" },
+        { NULL },
+    };
+
+    static const struct query_test pi_test[] =
+    {
+        { "//elem/processing-instruction()", "P1.E1.E2.D1 P1.E2.E2.D1" },
+        { "//elem/processing-instruction('pi')", "P1.E1.E2.D1" },
+        { "//elem/processing-instruction(\"pi2\")", "P1.E2.E2.D1" },
+        { "//elem/processing-instruction(\'*\')", "" },
+        { NULL },
+    };
+
     const selection_ns_t *ptr = selection_ns_data;
-    const xpath_test_t *xptest = xpath_test;
+    const struct query_test *xptest;
     IXMLDOMNamedNodeMap *map;
     VARIANT var;
     VARIANT_BOOL b;
@@ -5337,14 +5402,44 @@ static void test_XPath(void)
     if (!is_clsid_supported(&CLSID_DOMDocument2, &IID_IXMLDOMDocument2)) return;
     doc = create_document(&IID_IXMLDOMDocument2);
 
-    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szExampleXML), &b);
-    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    ok(b == VARIANT_TRUE, "failed to load XML string\n");
-
     /* switch to XPath */
     hr = IXMLDOMDocument2_setProperty(doc, _bstr_("SelectionLanguage"), _variantbstr_("XPath"));
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(node_value_cmp), NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    for (xptest = node_value_cmp_test; xptest->query; xptest++)
+    {
+        winetest_push_context("Test %s", xptest->query);
+
+        hr = IXMLDOMDocument2_selectNodes(doc, _bstr_(xptest->query), &list);
+        test_query_result(xptest, list, hr);
+        if (list)
+            IXMLDOMNodeList_Release(list);
+
+        winetest_pop_context();
+    }
+
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(pi), NULL);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    for (xptest = pi_test; xptest->query; xptest++)
+    {
+        winetest_push_context("Test %s", xptest->query);
+
+        hr = IXMLDOMDocument2_selectNodes(doc, _bstr_(xptest->query), &list);
+        test_query_result(xptest, list, hr);
+        if (list)
+            IXMLDOMNodeList_Release(list);
+
+        winetest_pop_context();
+    }
+
+    hr = IXMLDOMDocument2_loadXML(doc, _bstr_(szExampleXML), &b);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(b == VARIANT_TRUE, "failed to load XML string\n");
+
     /* some simple queries*/
     EXPECT_REF(doc, 1);
     hr = IXMLDOMDocument2_selectNodes(doc, _bstr_("root"), &list);
@@ -5363,23 +5458,16 @@ static void test_XPath(void)
     expect_list_and_release(list, "E2.D1");
 
     /* perform xpath tests */
-    for ( ; xptest->query ; xptest++ )
+    for (xptest = xpath_test; xptest->query ; xptest++)
     {
-        char *str;
+        winetest_push_context("Test %s", xptest->query);
 
         hr = IXMLDOMNode_selectNodes(rootNode, _bstr_(xptest->query), &list);
-        ok(hr == S_OK, "query evaluation failed for query=%s\n", xptest->query);
-
-        if (hr != S_OK)
-            continue;
-
-        str = list_to_string(list);
-
-        ok(!strcmp(str, xptest->list), "query=%s, invalid node list: \"%s\", expected \"%s\"\n",
-            xptest->query, str, xptest->list);
-
+        test_query_result(xptest, list, hr);
         if (list)
             IXMLDOMNodeList_Release(list);
+
+        winetest_pop_context();
     }
 
     /* namespace:: axis test is disabled until namespace definitions
@@ -7323,28 +7411,37 @@ static void test_default_properties(void)
     }
 }
 
-typedef struct {
-    const char *query;
-    const char *list;
-    BOOL todo;
-} xslpattern_test_t;
-
-static const xslpattern_test_t xslpattern_test[] = {
+static const struct query_test xslpattern_test[] =
+{
+    { "root//elem[$not$ 0]", "E1.E2.D1 E2.E2.D1 E3.E2.D1 E4.E2.D1", false, true },
+    { "root//elem[$any$ 0]", "E1.E2.D1" },
+    { "root//elem[$all$ 0]", "E1.E2.D1" },
+    { "root//elem[$all$ 1]", "E2.E2.D1" },
+    { "root//(elem)[0]", "E1.E2.D1", false, true},
     { "root//elem[0]", "E1.E2.D1" },
+    { "root//elem[0.0]", "E1.E2.D1" },
     { "root//elem[index()=1]", "E2.E2.D1" },
     { "root//elem[index() $eq$ 1]", "E2.E2.D1" },
     { "root//elem[end()]", "E4.E2.D1" },
+    { "root//elem[$any$ end()]", "E4.E2.D1" },
+    { "root//elem[$not$ $any$ end()]", "E1.E2.D1 E2.E2.D1 E3.E2.D1" },
+    { "root//elem[not($any$ end())]", "E1.E2.D1 E2.E2.D1 E3.E2.D1" },
     { "root//elem[$not$ end()]", "E1.E2.D1 E2.E2.D1 E3.E2.D1" },
     { "root//elem[index() != 0]", "E2.E2.D1 E3.E2.D1 E4.E2.D1" },
+    { "root//elem[$any$ (index() != 0)]", "E2.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root//elem[index() $ne$ 0]", "E2.E2.D1 E3.E2.D1 E4.E2.D1" },
+    { "root//elem[index() $ine$ 0]", "E2.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root//elem[index() < 2]", "E1.E2.D1 E2.E2.D1" },
     { "root//elem[index() $lt$ 2]", "E1.E2.D1 E2.E2.D1" },
+    { "root//elem[index() $ilt$ 2]", "E1.E2.D1 E2.E2.D1" },
     { "root//elem[index() <= 1]", "E1.E2.D1 E2.E2.D1" },
     { "root//elem[index() $le$ 1]", "E1.E2.D1 E2.E2.D1" },
     { "root//elem[index() > 1]", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[index() $gt$ 1]", "E3.E2.D1 E4.E2.D1" },
+    { "root//elem[index() $igt$ 1]", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[index() >= 2]", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[index() $ge$ 2]", "E3.E2.D1 E4.E2.D1" },
+    { "root//elem[index() $ige$ 2]", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[a $ieq$ 'a2 field']", "E2.E2.D1" },
     { "root//elem[a $ine$ 'a2 field']", "E1.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root//elem[a $ilt$ 'a3 field']", "E1.E2.D1 E2.E2.D1" },
@@ -7352,6 +7449,7 @@ static const xslpattern_test_t xslpattern_test[] = {
     { "root//elem[a $igt$ 'a2 field']", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[a $ige$ 'a3 field']", "E3.E2.D1 E4.E2.D1" },
     { "root//elem[$any$ *='B2 field']", "E2.E2.D1" },
+    { "root//elem[$not$ $any$ *='B2 field']", "E1.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root//elem[$all$ *!='B2 field']", "E1.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root//elem[index()=0 or end()]", "E1.E2.D1 E4.E2.D1" },
     { "root//elem[index()=0 $or$ end()]", "E1.E2.D1 E4.E2.D1" },
@@ -7360,6 +7458,7 @@ static const xslpattern_test_t xslpattern_test[] = {
     { "root//elem[index()>0 $and$ $not$ end()]", "E2.E2.D1 E3.E2.D1" },
     { "root//elem[index()>0 && $not$ end()]", "E2.E2.D1 E3.E2.D1" },
     { "root/elem[0]", "E1.E2.D1" },
+    { "(root/elem[0] | root/elem[1])", "E1.E2.D1 E2.E2.D1" },
     { "root/elem[index()=1]", "E2.E2.D1" },
     { "root/elem[index() $eq$ 1]", "E2.E2.D1" },
     { "root/elem[end()]", "E4.E2.D1" },
@@ -7373,7 +7472,10 @@ static const xslpattern_test_t xslpattern_test[] = {
     { "root/elem[index() > 1]", "E3.E2.D1 E4.E2.D1" },
     { "root/elem[index() $gt$ 1]", "E3.E2.D1 E4.E2.D1" },
     { "root/elem[index() >= 2]", "E3.E2.D1 E4.E2.D1" },
+    { "root/elem[(index() >= 2) = 1]", "", true },
     { "root/elem[index() $ge$ 2]", "E3.E2.D1 E4.E2.D1" },
+    { "root/elem[a < 'a3 field']", "E1.E2.D1 E2.E2.D1", true },
+    { "root/elem[a > 'a3 field']", "E3.E2.D1 E4.E2.D1", true },
     { "root/elem[a $ieq$ 'a2 field']", "E2.E2.D1" },
     { "root/elem[a $ine$ 'a2 field']", "E1.E2.D1 E3.E2.D1 E4.E2.D1" },
     { "root/elem[a $ilt$ 'a3 field']", "E1.E2.D1 E2.E2.D1" },
@@ -7387,50 +7489,92 @@ static const xslpattern_test_t xslpattern_test[] = {
     { "root/elem[index()=0 || end()]", "E1.E2.D1 E4.E2.D1" },
     { "root/elem[index()>0 and $not$ end()]", "E2.E2.D1 E3.E2.D1" },
     { "root/elem[index()>0 $and$ $not$ end()]", "E2.E2.D1 E3.E2.D1" },
+    { "root/elem[index()>0 $and$ not (end())]", "E2.E2.D1 E3.E2.D1" },
     { "root/elem[index()>0 && $not$ end()]", "E2.E2.D1 E3.E2.D1" },
     { "root/elem[d]", "E1.E2.D1 E2.E2.D1 E4.E2.D1" },
-    { "root/elem[@*]", "E2.E2.D1 E3.E2.D1", TRUE },
+    { "root/elem[$any$ d]", "E1.E2.D1 E2.E2.D1 E4.E2.D1" },
+    { "root/elem/element('foo:c')", "E3.E4.E2.D1" },
+    { "root/elem[d!value() = 'D1 field']", "E1.E2.D1", false, true },
+    { "root/elem[d ! value ( ) = 'D1 field']", "E1.E2.D1", false, true },
+    { "root/elem[@*]", "E2.E2.D1 E3.E2.D1", true },
+    { "root/elem[(@*)]", "E2.E2.D1 E3.E2.D1", true },
+    { "root/elem[@ *]", "E2.E2.D1 E3.E2.D1", true },
+    { "root//c[@type]", "E3.E2.E2.D1" },
+    { "root//c[(@type)]", "E3.E2.E2.D1" },
+
+    { "//@foo:*", "A'foo:b'.E2.D1", true },
+    { "//@xmlns:*", "A'xmlns:foo'.E2.D1 A'xmlns:foo'.E5.E1.E2.D1 "
+            "A'xmlns:bar'.E5.E1.E2.D1 A'xmlns'.E1.E5.E1.E2.D1 "
+            "A'xmlns'.E2.E5.E1.E2.D1 A'xmlns'.E3.E2.D1", true },
+
+    /* No unary '-' in expression, but allowed for literals. */
+    { "root/elem[-nodeType()]", NULL },
+    { "root/elem[-1]", "", false, true },
+
+    { "root/(elem)[d]", "E1.E2.D1 E2.E2.D1 E4.E2.D1", false, true },
+
+    /* Predicate at different levels requiring index fixup vs XPath */
+    { "root//elem[0][0]", "E1.E2.D1" },
     { NULL }
 };
 
-static const xslpattern_test_t xslpattern_test_no_ns[] = {
+static const struct query_test xslpattern_test_no_ns[] =
+{
     /* prefixes don't need to be registered, you may use them as they are in the doc */
     { "//bar:x", "E6.E1.E5.E1.E2.D1 E6.E2.E5.E1.E2.D1" },
+    { "//bar:*", "E6.E1.E5.E1.E2.D1 E6.E2.E5.E1.E2.D1", true },
     /* prefixes must be explicitly specified in the name */
     { "//foo:elem", "" },
     { "//foo:c", "E3.E4.E2.D1" },
+    { "//node()[nodeName()='foo:c']", "E3.E4.E2.D1" },
+    { "//node()[nodeName()='c']", "E3.E1.E2.D1 E3.E2.E2.D1 E3.E3.E2.D1" },
     { NULL }
 };
 
-static const xslpattern_test_t xslpattern_test_func[] = {
+static const struct query_test xslpattern_test_func[] =
+{
     { "attribute()", "" },
     { "attribute('depth')", "" },
     { "root/attribute('depth')", "A'depth'.E3.D1" },
+    { "root/attribute('depth')", "A'depth'.E3.D1" },
     { "//x/attribute()", "A'id'.E3.E3.D1 A'depth'.E3.E3.D1" },
+    { "//x/attribute('*')", "A'id'.E3.E3.D1 A'depth'.E3.E3.D1" },
     { "//x//attribute(id)", NULL },
     { "//x//attribute('id')", "A'id'.E3.E3.D1 A'id'.E4.E3.E3.D1 A'id'.E5.E3.E3.D1 A'id'.E6.E3.E3.D1" },
     { "comment()", "C2.D1" },
-    { "//comment()", "C2.D1 C1.E3.D1 C2.E3.E3.D1 C2.E4.E3.D1" },
+    { "//comment()", "C2.D1 C1.E3.D1 C2.E3.E3.D1 C2.E5.E3.D1" },
     { "element()", "E3.D1" },
-    { "root/y/element()", "E4.E4.E3.D1 E5.E4.E3.D1 E6.E4.E3.D1" },
+    { "root/y/element()", "E4.E5.E3.D1 E5.E5.E3.D1 E6.E5.E3.D1" },
+    { "root/y/element('*')", "E4.E5.E3.D1 E5.E5.E3.D1 E6.E5.E3.D1" },
+    { "root/(y)/element()", "E4.E5.E3.D1 E5.E5.E3.D1 E6.E5.E3.D1", false, true },
     { "//element(a)", NULL },
-    { "//element('a')", "E4.E3.E3.D1 E4.E4.E3.D1" },
+    { "//element('a')", "E4.E3.E3.D1 E4.E5.E3.D1" },
+    { "//element('*')", "E3.D1 E3.E3.D1 E4.E3.E3.D1 E5.E3.E3.D1 E6.E3.E3.D1 E5.E3.D1 E4.E5.E3.D1 E5.E5.E3.D1 E6.E5.E3.D1" },
     { "node()", "P1.D1 C2.D1 E3.D1" },
     { "//x/node()", "P1.E3.E3.D1 C2.E3.E3.D1 T3.E3.E3.D1 E4.E3.E3.D1 E5.E3.E3.D1 E6.E3.E3.D1" },
     { "//x/node()[nodeType()=1]", "E4.E3.E3.D1 E5.E3.E3.D1 E6.E3.E3.D1" },
     { "//x/node()[nodeType()=3]", "T3.E3.E3.D1" },
     { "//x/node()[nodeType()=7]", "P1.E3.E3.D1" },
     { "//x/node()[nodeType()=8]", "C2.E3.E3.D1" },
+    { "//x/node()[nodeType()='8']", "C2.E3.E3.D1" },
+    { "//x/node()[nodeType()='8.0']", "C2.E3.E3.D1" },
+    { "//x/node()[nodeType()='8.1']", "" },
+    { "//x/node()[nodeName()='a']", "E4.E3.E3.D1" },
     { "pi()", "P1.D1" },
-    { "//y/pi()", "P1.E4.E3.D1" },
-    { "root/textnode()", "T2.E3.D1" },
-    { "root/element()/textnode()", "T3.E3.E3.D1 T3.E4.E3.D1" },
+    { "pi('*')", "P1.D1" },
+    { "pi('xml')", "P1.D1" },
+    { "pi( \"xml\" )", "P1.D1" },
+    { "//y/pi()", "P1.E5.E3.D1" },
+    { "root/textnode()", "T2.E3.D1 CD4.E3.D1 CD6.E3.D1" },
+    { "root/text()", "T2.E3.D1 CD4.E3.D1 CD6.E3.D1" },
+    { "root/cdata()", "CD4.E3.D1 CD6.E3.D1" },
+    { "root/element()/textnode()", "T3.E3.E3.D1 T3.E5.E3.D1" },
     { NULL }
 };
 
 static void test_XSLPattern(void)
 {
-    const xslpattern_test_t *ptr = xslpattern_test;
+    const struct query_test *ptr = xslpattern_test;
     IXMLDOMDocument2 *doc;
     IXMLDOMNodeList *list;
     VARIANT_BOOL b;
@@ -7459,27 +7603,17 @@ static void test_XSLPattern(void)
     ok(len == 3, "expected 3 entries in list, got %ld\n", len);
     IXMLDOMNodeList_Release(list);
 
-    while (ptr->query)
+    for (; ptr->query; ptr++)
     {
+        winetest_push_context("Test %s", ptr->query);
+
         list = NULL;
         hr = IXMLDOMDocument2_selectNodes(doc, _bstr_(ptr->query), &list);
-        ok(hr == S_OK, "query=%s, failed with %#lx\n", ptr->query, hr);
-        len = 0;
-        hr = IXMLDOMNodeList_get_length(list, &len);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-        ok(len != 0, "query=%s, empty list\n", ptr->query);
-        if (len) {
-            if (ptr->todo) {
-                char *str = list_to_string(list);
-                todo_wine
-                ok(!strcmp(str, ptr->list), "Invalid node list: %s, expected %s\n", str, ptr->list);
-                IXMLDOMNodeList_Release(list);
-            }
-            else
-                expect_list_and_release(list, ptr->list);
-        }
+        test_query_result(ptr, list, hr);
+        if (list)
+            IXMLDOMNodeList_Release(list);
 
-        ptr++;
+        winetest_pop_context();
     }
 
     /* namespace handling */
@@ -7488,30 +7622,17 @@ static void test_XSLPattern(void)
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     ptr = xslpattern_test_no_ns;
-    while (ptr->query)
+    for (; ptr->query; ptr++)
     {
+        winetest_push_context("Test %s", ptr->query);
+
         list = NULL;
         hr = IXMLDOMDocument2_selectNodes(doc, _bstr_(ptr->query), &list);
-        ok(hr == S_OK, "query=%s, failed with %#lx.\n", ptr->query, hr);
-
-        if (*ptr->list)
-        {
-            len = 0;
-            hr = IXMLDOMNodeList_get_length(list, &len);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-            ok(len != 0, "query=%s, empty list\n", ptr->query);
-        }
-        else
-        {
-            len = 1;
-            hr = IXMLDOMNodeList_get_length(list, &len);
-            ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-            ok(len == 0, "query=%s, empty list\n", ptr->query);
-        }
-        if (len)
-            expect_list_and_release(list, ptr->list);
+        test_query_result(ptr, list, hr);
+        if (list)
+            IXMLDOMNodeList_Release(list);
 
-        ptr++;
+        winetest_pop_context();
     }
 
     /* explicitly register prefix foo */
@@ -7553,27 +7674,17 @@ static void test_XSLPattern(void)
     ptr = xslpattern_test_func;
     while (ptr->query)
     {
+        winetest_push_context("Test %s", ptr->query);
+
         list = NULL;
         hr = IXMLDOMDocument2_selectNodes(doc, _bstr_(ptr->query), &list);
-        if (ptr->list)
-        {
-            ok(hr == S_OK, "query=%s, failed with %#lx.\n", ptr->query, hr);
-            len = 0;
-            hr = IXMLDOMNodeList_get_length(list, &len);
-            ok(hr == S_OK, "Failed to get list length, hr %#lx.\n", hr);
-            if (*ptr->list)
-            {
-                ok(len != 0, "query=%s, empty list\n", ptr->query);
-                if (len)
-                    expect_list_and_release(list, ptr->list);
-            }
-            else
-                ok(len == 0, "query=%s, filled list\n", ptr->query);
-        }
-        else
-            ok(hr == E_FAIL, "query=%s, failed with %#lx.\n", ptr->query, hr);
+        test_query_result(ptr, list, hr);
+        if (list)
+            IXMLDOMNodeList_Release(list);
 
         ptr++;
+
+        winetest_pop_context();
     }
 
     IXMLDOMDocument2_Release(doc);
diff --git a/dlls/msxml3/tests/httpreq.c b/dlls/msxml3/tests/httpreq.c
index bccfbaf582a1..903d9d69cc59 100644
--- a/dlls/msxml3/tests/httpreq.c
+++ b/dlls/msxml3/tests/httpreq.c
@@ -88,6 +88,9 @@ static BOOL g_enablecallchecks;
         expect_ ## func = called_ ## func = FALSE; \
     }while(0)
 
+#define CLEAR_CALLED(func) \
+    expect_ ## func = called_ ## func = 0
+
 /* object site */
 DEFINE_EXPECT(site_qi_IServiceProvider);
 DEFINE_EXPECT(site_qi_IXMLDOMDocument);
@@ -1403,8 +1406,8 @@ static void set_xhr_site(IXMLHttpRequest *xhr)
     CHECK_CALLED(sp_queryservice_SID_secmgr_htmldoc2);
     todo_wine
     CHECK_CALLED(sp_queryservice_SID_secmgr_xmldomdoc);
-    /* this one isn't very reliable
-    CHECK_CALLED(sp_queryservice_SID_secmgr_secmgr); */
+    /* this one isn't very reliable */
+    CLEAR_CALLED(sp_queryservice_SID_secmgr_secmgr);
 todo_wine {
     CHECK_CALLED(htmldoc2_get_all);
     CHECK_CALLED(collection_get_length);
diff --git a/dlls/msxml3/xmlview.c b/dlls/msxml3/xmlview.c
index f11545e0ccac..9505eead03f3 100644
--- a/dlls/msxml3/xmlview.c
+++ b/dlls/msxml3/xmlview.c
@@ -364,6 +364,19 @@ static inline HRESULT display_error_page(BindStatusCallback *This)
     return report_data(This);
 }
 
+static void dom_document_use_xpath(IXMLDOMDocument3 *doc)
+{
+    BSTR name;
+    VARIANT v;
+
+    V_VT(&v) = VT_BSTR;
+    V_BSTR(&v) = SysAllocString(L"XPath");
+    name = SysAllocString(L"SelectionLanguage");
+    IXMLDOMDocument3_setProperty(doc, name, v);
+    SysFreeString(name);
+    VariantClear(&v);
+}
+
 static inline HRESULT handle_xml_load(BindStatusCallback *This)
 {
     IXMLDOMDocument3 *xml = NULL, *xsl = NULL;
@@ -386,6 +399,7 @@ static inline HRESULT handle_xml_load(BindStatusCallback *This)
     hres = dom_document_create(MSXML_DEFAULT, (void **)&xml);
     if(FAILED(hres))
         return display_error_page(This);
+    dom_document_use_xpath(xml);
 
     V_VT(&var) = VT_UNKNOWN;
     V_UNKNOWN(&var) = (IUnknown*)This->stream;
@@ -465,6 +479,7 @@ static inline HRESULT handle_xml_load(BindStatusCallback *This)
         IXMLDOMDocument3_Release(xml);
         return display_error_page(This);
     }
+    dom_document_use_xpath(xsl);
 
     /* TODO: do the binding asynchronously */
     hres = IXMLDOMDocument3_load(xsl, var, &succ);
diff --git a/dlls/msxml3/xpath.c b/dlls/msxml3/xpath.c
index 3f4e2e44634b..2f5513d8a65b 100644
--- a/dlls/msxml3/xpath.c
+++ b/dlls/msxml3/xpath.c
@@ -1,4 +1,5 @@
 /*
+ * Copyright 2010 Adam Martinson for CodeWeavers
  * Copyright 2026 Nikolay Sivov for CodeWeavers
  *
  * This library is free software; you can redistribute it and/or
@@ -66,6 +67,23 @@ enum xpath_global_config
 static const double XPATH_UPPER_DOUBLE = 1e9;
 static const double XPATH_LOWER_DOUBLE = 1e-5;
 
+enum compop
+{
+    COMPOP_NONE = 0,
+    COMPOP_EQ = 0x1,
+    COMPOP_NE = 0x2,
+
+    COMPOP_LT = 0x4,
+    COMPOP_GT = 0x8,
+    COMPOP_NOTSTRICT = 0x1000,
+    COMPOP_LE = COMPOP_LT | COMPOP_NOTSTRICT,
+    COMPOP_GE = COMPOP_GT | COMPOP_NOTSTRICT,
+
+    COMPOP_I = 0x2000,
+
+    COMPOP_EQUALITY = COMPOP_EQ | COMPOP_NE,
+};
+
 enum xpath_axis
 {
     AXIS_UNDEFINED = 0,
@@ -99,6 +117,10 @@ enum xpath_type
     NODE_TYPE_COMMENT = NODE_COMMENT,
     NODE_TYPE_TEXT = NODE_TEXT,
     NODE_TYPE_PI = NODE_PROCESSING_INSTRUCTION,
+    /* Extension */
+    NODE_TYPE_ELEMENT = NODE_ELEMENT,
+    NODE_TYPE_ATTRIBUTE = NODE_ATTRIBUTE,
+    NODE_TYPE_CDATA = NODE_CDATA_SECTION,
 };
 
 struct xpath_parser_context;
@@ -160,6 +182,11 @@ enum xpath_op
     XPATH_OP_PREDICATE,
     XPATH_OP_FILTER,
     XPATH_OP_SORT,
+
+    XPATH_OP_NOT,
+    XPATH_OP_ALL,
+    XPATH_OP_ICMP,
+    XPATH_OP_IEQUAL,
 };
 
 struct xpath_parser_context;
@@ -220,6 +247,15 @@ struct xpath_parser_context
     } namespaces;
 };
 
+/* XSLPattern uses 0-based indexing */
+static int xpath_adjust_nodeset_index(struct xpath_parser_context *ctxt, int index)
+{
+    if (ctxt->context->xpath)
+        return index;
+
+    return index + 1;
+}
+
 /* In XPath data model attributes and namespace nodes have their containing
    element as a parent. One exception for that is implicit "xmlns:xml" namespace which
    is only exposed with namespace:: axis. For consistency we'll use XPath-specific
@@ -326,9 +362,12 @@ static void xpath_debug_dump_step_op(const struct xpath_comp_expr *comp, int idx
         case XPATH_OP_OR:
             MESSAGE("OR"); break;
         case XPATH_OP_EQUAL:
-            MESSAGE("EQUAL %s", op->value ? "=" : "!="); break;
+        case XPATH_OP_IEQUAL:
+            MESSAGE("%sEQUAL %s", op->op == XPATH_OP_IEQUAL ? "I" : "", op->value ? "=" : "!=");
+            break;
         case XPATH_OP_CMP:
-            MESSAGE("CMP %s", op->value ? "<" : ">");
+        case XPATH_OP_ICMP:
+            MESSAGE("%sCMP %s", op->op == XPATH_OP_ICMP ? "I" : "", op->value ? "<" : ">");
             if (!op->value2)
                 MESSAGE("=");
             break;
@@ -423,6 +462,12 @@ static void xpath_debug_dump_step_op(const struct xpath_comp_expr *comp, int idx
                     MESSAGE("'text' "); break;
                 case NODE_TYPE_PI:
                     MESSAGE("'PI' "); break;
+                case NODE_TYPE_ELEMENT:
+                    MESSAGE("'element' "); break;
+                case NODE_TYPE_ATTRIBUTE:
+                    MESSAGE("'attribute' "); break;
+                case NODE_TYPE_CDATA:
+                    MESSAGE("'cdata' "); break;
             }
             if (prefix)
                 MESSAGE("%s:", debugstr_w(prefix));
@@ -464,6 +509,8 @@ static void xpath_debug_dump_step_op(const struct xpath_comp_expr *comp, int idx
         case XPATH_OP_ARG: MESSAGE("ARG"); break;
         case XPATH_OP_PREDICATE: MESSAGE("PREDICATE"); break;
         case XPATH_OP_FILTER: MESSAGE("FILTER"); break;
+        case XPATH_OP_NOT: MESSAGE("NOT"); break;
+        case XPATH_OP_ALL: MESSAGE("ALL"); break;
         default:
         MESSAGE("UNKNOWN %d\n", op->op); return;
     }
@@ -771,6 +818,19 @@ static void xpath_parse_next(struct xpath_parser_context *ctxt)
     xpath_parse_skip(ctxt, 1);
 }
 
+static bool xpath_parse_cmp(struct xpath_parser_context *ctxt, const WCHAR *str)
+{
+    int count = wcslen(str);
+
+    if (!wcsncmp(ctxt->cur, str, count))
+    {
+        xpath_parse_skip(ctxt, count);
+        return true;
+    }
+
+    return false;
+}
+
 static WCHAR * xpath_parse_nc_name(struct xpath_parser_context *ctxt)
 {
     const WCHAR *start = ctxt->cur;
@@ -942,10 +1002,8 @@ static WCHAR * xpath_compile_nodetest(struct xpath_parser_context *ctxt, enum xp
 
     blanks = xml_is_space(*ctxt->cur);
     xpath_parse_skipspaces(ctxt);
-    if (*ctxt->cur == '(')
+    if (xpath_parse_cmp(ctxt, L"("))
     {
-        xpath_parse_next(ctxt);
-
         /*
          * NodeType or PI search
          */
@@ -1003,9 +1061,8 @@ static WCHAR * xpath_compile_nodetest(struct xpath_parser_context *ctxt, enum xp
 
         *prefix = name;
 
-        if (*ctxt->cur == '*')
+        if (xpath_parse_cmp(ctxt, L"*"))
         {
-            xpath_parse_next(ctxt);
             *test = NODE_TEST_ALL;
             return NULL;
         }
@@ -1041,15 +1098,13 @@ static void xpath_compile_step(struct xpath_parser_context *ctxt)
         return;
 
     xpath_parse_skipspaces(ctxt);
-    if (ctxt->cur[0] == '.' && ctxt->cur[1] == '.')
+    if (xpath_parse_cmp(ctxt, L".."))
     {
-        xpath_parse_skip(ctxt, 2);
         xpath_parse_skipspaces(ctxt);
         xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_PARENT, NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
     }
-    else if (ctxt->cur[0] == '.')
+    else if (xpath_parse_cmp(ctxt, L"."))
     {
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
     }
     else
@@ -1073,9 +1128,8 @@ static void xpath_compile_step(struct xpath_parser_context *ctxt)
                 if (axis)
                 {
                     xpath_parse_skipspaces(ctxt);
-                    if (ctxt->cur[0] == ':' && ctxt->cur[1] == ':')
+                    if (xpath_parse_cmp(ctxt, L"::"))
                     {
-                        xpath_parse_skip(ctxt, 2);
                         free(name);
                         name = NULL;
                     }
@@ -1089,9 +1143,8 @@ static void xpath_compile_step(struct xpath_parser_context *ctxt)
                     axis = AXIS_CHILD;
                 }
             }
-            else if (*ctxt->cur == '@')
+            else if (xpath_parse_cmp(ctxt, L"@"))
             {
-                xpath_parse_next(ctxt);
                 axis = AXIS_ATTRIBUTE;
             }
             else
@@ -1134,16 +1187,14 @@ static void xpath_compile_step(struct xpath_parser_context *ctxt)
 static void xpath_compile_relative_location_path(struct xpath_parser_context *ctxt)
 {
     xpath_parse_skipspaces(ctxt);
-    if (ctxt->cur[0] == '/' && ctxt->cur[1] == '/')
+    if (xpath_parse_cmp(ctxt, L"//"))
     {
-        xpath_parse_skip(ctxt, 2);
         xpath_parse_skipspaces(ctxt);
         xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
                 NODE_TYPE_NODE, NULL, NULL);
     }
-    else if (ctxt->cur[0] == '/')
+    else if (xpath_parse_cmp(ctxt, L"/"))
     {
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
     }
     xpath_compile_step(ctxt);
@@ -1153,17 +1204,15 @@ static void xpath_compile_relative_location_path(struct xpath_parser_context *ct
     xpath_parse_skipspaces(ctxt);
     while (ctxt->cur[0] == '/')
     {
-        if (ctxt->cur[0] == '/' && ctxt->cur[1] == '/')
+        if (xpath_parse_cmp(ctxt, L"//"))
         {
-            xpath_parse_skip(ctxt, 2);
             xpath_parse_skipspaces(ctxt);
             xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
                     NODE_TYPE_NODE, NULL, NULL);
             xpath_compile_step(ctxt);
         }
-        else if (ctxt->cur[0] == '/')
+        else if (xpath_parse_cmp(ctxt, L"/"))
         {
-            xpath_parse_next(ctxt);
             xpath_parse_skipspaces(ctxt);
             xpath_compile_step(ctxt);
         }
@@ -1190,17 +1239,15 @@ static void xpath_compile_location_path(struct xpath_parser_context *ctxt)
     {
         while (*ctxt->cur == '/')
         {
-            if (ctxt->cur[0] == '/' && ctxt->cur[1] == '/')
+            if (xpath_parse_cmp(ctxt, L"//"))
             {
-                xpath_parse_skip(ctxt, 2);
                 xpath_parse_skipspaces(ctxt);
                 xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
                         NODE_TYPE_NODE, NULL, NULL);
                 xpath_compile_relative_location_path(ctxt);
             }
-            else if (ctxt->cur[0] == '/')
+            else if (xpath_parse_cmp(ctxt, L"/"))
             {
-                xpath_parse_next(ctxt);
                 xpath_parse_skipspaces(ctxt);
                 if (*ctxt->cur &&
                         ((is_ascii_letter(*ctxt->cur)) || (*ctxt->cur >= 0x80) ||
@@ -1227,10 +1274,9 @@ static void xpath_compile_variable_reference(struct xpath_parser_context *ctxt)
         return;
 
     xpath_parse_skipspaces(ctxt);
-    if (*ctxt->cur != '$')
+    if (!xpath_parse_cmp(ctxt, L"$"))
         return xpath_parser_context_set_error(ctxt, XPATH_VARIABLE_REF_ERROR);
 
-    xpath_parse_next(ctxt);
     xpath_parse_qname(ctxt, &name);
     if (!name.name)
     {
@@ -1557,12 +1603,11 @@ static void xpath_compile_function_call(struct xpath_parser_context *ctxt)
     }
     xpath_parse_skipspaces(ctxt);
 
-    if (*ctxt->cur != '(')
+    if (!xpath_parse_cmp(ctxt, L"("))
     {
         xpath_free_qname(&name);
         return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
     }
-    xpath_parse_next(ctxt);
     xpath_parse_skipspaces(ctxt);
 
     /*
@@ -1588,12 +1633,11 @@ static void xpath_compile_function_call(struct xpath_parser_context *ctxt)
             xpath_push_binary_step(ctxt, XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
             nbargs++;
             if (*ctxt->cur == ')') break;
-            if (*ctxt->cur != ',')
+            if (!xpath_parse_cmp(ctxt, L","))
             {
                 xpath_free_qname(&name);
                 return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
             }
-            xpath_parse_next(ctxt);
             xpath_parse_skipspaces(ctxt);
         }
     }
@@ -1617,14 +1661,12 @@ static void xpath_compile_primary_expr(struct xpath_parser_context *ctxt)
     {
         xpath_compile_variable_reference(ctxt);
     }
-    else if (*ctxt->cur == '(')
+    else if (xpath_parse_cmp(ctxt, L"("))
     {
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
         xpath_compile_expr(ctxt, true);
-        if (*ctxt->cur != ')')
+        if (!xpath_parse_cmp(ctxt, L")"))
             return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
     }
     else if (is_ascii_digit(*ctxt->cur) || (*ctxt->cur == '.' && is_ascii_digit(ctxt->cur[1])))
@@ -1651,9 +1693,8 @@ static void xpath_compile_predicate(struct xpath_parser_context *ctxt, bool filt
     int op1 = ctxt->comp->last;
 
     xpath_parse_skipspaces(ctxt);
-    if (*ctxt->cur != '[')
+    if (!xpath_parse_cmp(ctxt, L"["))
         return xpath_parser_context_set_error(ctxt, XPATH_INVALID_PREDICATE_ERROR);
-    xpath_parse_next(ctxt);
     xpath_parse_skipspaces(ctxt);
 
     ctxt->comp->last = -1;
@@ -1661,7 +1702,7 @@ static void xpath_compile_predicate(struct xpath_parser_context *ctxt, bool filt
     if (ctxt->error != XPATH_EXPRESSION_OK)
         return;
 
-    if (*ctxt->cur != ']')
+    if (!xpath_parse_cmp(ctxt, L"]"))
         return xpath_parser_context_set_error(ctxt, XPATH_INVALID_PREDICATE_ERROR);
 
     if (filter)
@@ -1669,7 +1710,6 @@ static void xpath_compile_predicate(struct xpath_parser_context *ctxt, bool filt
     else
         xpath_push_binary_step(ctxt, XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
 
-    xpath_parse_next(ctxt);
     xpath_parse_skipspaces(ctxt);
 }
 
@@ -1789,7 +1829,7 @@ static void xpath_compile_path_expr(struct xpath_parser_context *ctxt)
             }
 
             location_path = true;
-            if (ctxt->cur[len++] == '(')
+            if (ctxt->cur[len] && ctxt->cur[len++] == '(')
                 location_path = xpath_is_nodetype(name);
 
             if (!ctxt->cur[len])
@@ -1810,9 +1850,8 @@ static void xpath_compile_path_expr(struct xpath_parser_context *ctxt)
     {
         xpath_compile_filter_expr(ctxt);
 
-        if (ctxt->cur[0] == '/' && ctxt->cur[1] == '/')
+        if (xpath_parse_cmp(ctxt, L"//"))
         {
-            xpath_parse_skip(ctxt, 2);
             xpath_parse_skipspaces(ctxt);
             xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
                     NODE_TYPE_NODE, NULL, NULL);
@@ -1835,13 +1874,12 @@ static void xpath_compile_union_expr(struct xpath_parser_context *ctxt)
 {
     xpath_compile_path_expr(ctxt);
     xpath_parse_skipspaces(ctxt);
-    while (*ctxt->cur == '|')
+    while (xpath_parse_cmp(ctxt, L"|"))
     {
         int op1 = ctxt->comp->last;
 
         xpath_push_leave_step(ctxt, XPATH_OP_NODE, 0, 0);
 
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
         xpath_compile_path_expr(ctxt);
 
@@ -1860,11 +1898,10 @@ static void xpath_compile_unary_expr(struct xpath_parser_context *ctxt)
     int minus = 0;
 
     xpath_parse_skipspaces(ctxt);
-    while (*ctxt->cur == '-')
+    while (xpath_parse_cmp(ctxt, L"-"))
     {
         minus = 1 - minus;
         found = true;
-        xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
     }
 
@@ -1949,7 +1986,7 @@ static void xpath_compile_additive_expr(struct xpath_parser_context *ctxt)
  *                 | RelationalExpr '<=' AdditiveExpr
  *                 | RelationalExpr '>=' AdditiveExpr
  */
-static void xpath_compiler_relational_expr(struct xpath_parser_context *ctxt)
+static void xpath_compile_relational_expr(struct xpath_parser_context *ctxt)
 {
     xpath_compile_additive_expr(ctxt);
     xpath_parse_skipspaces(ctxt);
@@ -1978,7 +2015,7 @@ static void xpath_compiler_relational_expr(struct xpath_parser_context *ctxt)
  */
 static void xpath_compile_equality_expr(struct xpath_parser_context *ctxt)
 {
-    xpath_compiler_relational_expr(ctxt);
+    xpath_compile_relational_expr(ctxt);
     xpath_parse_skipspaces(ctxt);
 
     while (ctxt->cur[0] == '=' || (ctxt->cur[0] == '!' && ctxt->cur[1] == '='))
@@ -1991,7 +2028,7 @@ static void xpath_compile_equality_expr(struct xpath_parser_context *ctxt)
         if (!eq)
             xpath_parse_next(ctxt);
         xpath_parse_skipspaces(ctxt);
-        xpath_compiler_relational_expr(ctxt);
+        xpath_compile_relational_expr(ctxt);
         xpath_push_binary_step(ctxt, XPATH_OP_EQUAL, op1, ctxt->comp->last, eq, 0);
         xpath_parse_skipspaces(ctxt);
     }
@@ -2005,11 +2042,10 @@ static void xpath_compile_and_expr(struct xpath_parser_context *ctxt)
 {
     xpath_compile_equality_expr(ctxt);
     xpath_parse_skipspaces(ctxt);
-    while (ctxt->cur[0] == 'a' && ctxt->cur[1] == 'n' && ctxt->cur[2] == 'd')
+    while (xpath_parse_cmp(ctxt, L"and"))
     {
         int op1 = ctxt->comp->last;
 
-        xpath_parse_skip(ctxt, 3);
         xpath_parse_skipspaces(ctxt);
         xpath_compile_equality_expr(ctxt);
         xpath_push_binary_step(ctxt, XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
@@ -2039,11 +2075,10 @@ static void xpath_compile_expr(struct xpath_parser_context *ctxt, bool sort)
 
     xpath_compile_and_expr(ctxt);
     xpath_parse_skipspaces(ctxt);
-    while (ctxt->cur[0] == 'o' && ctxt->cur[1] == 'r')
+    while (xpath_parse_cmp(ctxt, L"or"))
     {
         int op1 = ctxt->comp->last;
 
-        xpath_parse_skip(ctxt, 2);
         xpath_parse_skipspaces(ctxt);
         xpath_compile_and_expr(ctxt);
         xpath_push_binary_step(ctxt, XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
@@ -2843,11 +2878,37 @@ static bool xpath_equal_nodeset_float(struct xpath_parser_context *ctxt,
     return ret;
 }
 
+static bool xpath_equal_node_string(struct domnode *node, unsigned int hash, const WCHAR *str, bool neq)
+{
+    WCHAR *str2;
+    bool ret;
+
+    if (xpath_nodeval_hash(node) != hash)
+        return neq;
+
+    str2 = xpath_cast_node_to_string(node);
+    if (str2 && !wcscmp(str, str2))
+    {
+        ret = !neq;
+    }
+    else if (!str2 && !*str)
+    {
+        ret = !neq;
+    }
+    else
+    {
+        ret = neq;
+    }
+
+    free(str2);
+
+    return ret;
+}
+
 static bool xpath_equal_nodeset_string(struct xpath_object *arg, const WCHAR *str, bool neq)
 {
     struct xpath_nodeset *ns;
     unsigned int hash;
-    WCHAR *str2;
     int i;
 
     if (!str || !arg || arg->type != _XPATH_NODESET)
@@ -2857,38 +2918,27 @@ static bool xpath_equal_nodeset_string(struct xpath_object *arg, const WCHAR *st
     if (!ns || ns->count <= 0)
         return false;
     hash = xpath_string_hash(str);
-    for (i = 0; i < ns->count; ++i)
+
+    if (arg->all)
     {
-        if (xpath_nodeval_hash(ns->nodes[i]) == hash)
+        for (i = 0; i < ns->count; ++i)
         {
-            str2 = xpath_cast_node_to_string(ns->nodes[i]);
-            if (str2 && !wcscmp(str, str2))
-            {
-                free(str2);
-                if (neq)
-                    continue;
-                return true;
-            }
-            else if (!str2 && !*str)
-            {
-                if (neq)
-                    continue;
-                return true;
-            }
-            else if (neq)
-            {
-                free(str2);
-                return true;
-            }
-            free(str2);
+            if (!xpath_equal_node_string(ns->nodes[i], hash, str, neq))
+                return false;
         }
-        else if (neq)
+
+        return true;
+    }
+    else
+    {
+        for (i = 0; i < ns->count; ++i)
         {
-            return true;
+            if (xpath_equal_node_string(ns->nodes[i], hash, str, neq))
+                return true;
         }
-    }
 
-    return false;
+        return false;
+    }
 }
 
 static bool xpath_equal_values(struct xpath_parser_context *ctxt)
@@ -3709,7 +3759,8 @@ static int xpath_node_collect_and_test(struct xpath_parser_context *ctxt,
     if (prefix)
     {
         uri  = xpath_ns_lookup(xpctxt, prefix);
-        if (!uri)
+
+        if (!uri && ctxt->context->xpath)
         {
             xpath_object_release(xpctxt, obj);
             xpath_parser_context_set_error(ctxt, XPATH_UNDEF_PREFIX_ERROR);
@@ -3847,6 +3898,8 @@ static int xpath_node_collect_and_test(struct xpath_parser_context *ctxt,
                 predOp = NULL;
                 hasAxisRange = true;
             }
+
+            maxPos = xpath_adjust_nodeset_index(ctxt, maxPos);
         }
     }
     breakOnFirstHit = ((toBool) && (predOp == NULL)) ? 1 : 0;
@@ -4028,18 +4081,29 @@ static int xpath_node_collect_and_test(struct xpath_parser_context *ctxt,
                         case NODE_ELEMENT:
                             if (!wcscmp(name, cur->name))
                             {
-                                node_uri = xpath_get_node_uri(cur);
-
-                                if (prefix)
+                                /* If namespace is not registered, simply compare prefixes */
+                                if (!ctxt->context->xpath && prefix && !uri)
                                 {
-                                    if (node_uri && !wcscmp(uri, node_uri))
+                                    if (cur->prefix && !wcscmp(cur->prefix, prefix))
                                     {
                                         XP_TEST_HIT
                                     }
                                 }
-                                else if (!node_uri)
+                                else
                                 {
-                                    XP_TEST_HIT
+                                    node_uri = xpath_get_node_uri(cur);
+
+                                    if (prefix)
+                                    {
+                                        if (node_uri && !wcscmp(uri, node_uri))
+                                        {
+                                            XP_TEST_HIT
+                                        }
+                                    }
+                                    else if (!node_uri || (!ctxt->context->xpath && !cur->prefix))
+                                    {
+                                        XP_TEST_HIT
+                                    }
                                 }
                             }
                             break;
@@ -4398,7 +4462,7 @@ static bool xpath_compare_values(struct xpath_parser_context *ctxt, bool inf, bo
         else
         {
             if (arg1->type == _XPATH_NODESET)
-                ret = xpath_compare_nodeset_value(ctxt, !inf, strict, arg1, arg2);
+                ret = xpath_compare_nodeset_value(ctxt, inf, strict, arg1, arg2);
             else
                 ret = xpath_compare_nodeset_value(ctxt, !inf, strict, arg2, arg1);
         }
@@ -4715,7 +4779,7 @@ static int xpath_evaluate_predicate_result(struct xpath_parser_context *ctxt, st
         case _XPATH_BOOLEAN:
             return res->boolval;
         case _XPATH_NUMBER:
-            return res->floatval == ctxt->context->proximityPosition;
+            return xpath_adjust_nodeset_index(ctxt, res->floatval) == ctxt->context->proximityPosition;
         case _XPATH_NODESET:
             return res->nodesetval && res->nodesetval->count;
         case _XPATH_STRING:
@@ -4773,7 +4837,6 @@ start:
             break;
         default:
             xpath_comp_op_eval(ctxt, op);
-            if (ctxt->error != XPATH_EXPRESSION_OK)
             if (ctxt->error != XPATH_EXPRESSION_OK)
                 return -1;
 
@@ -4921,6 +4984,46 @@ static xpath_function_ptr xpath_lookup_function(struct xpath_context *ctxt, cons
     return NULL;
 }
 
+static void xpath_builtin_not(struct xpath_parser_context *ctxt, int nargs);
+static WCHAR * xpath_pop_string(struct xpath_parser_context *ctxt);
+
+static int xpath_icompare_values(struct xpath_parser_context *ctxt, bool inf, bool strict)
+{
+    WCHAR *arg1, *arg2;
+    int ret;
+
+    arg2 = xpath_pop_string(ctxt);
+    arg1 = xpath_pop_string(ctxt);
+
+    ret = wcsicmp(arg1, arg2);
+
+    if (inf)
+        ret = strict ? ret < 0 : ret <= 0;
+    else
+        ret = strict ? ret > 0 : ret >= 0;
+
+    free(arg1);
+    free(arg2);
+
+    return ret;
+}
+
+static bool xpath_iequal_values(struct xpath_parser_context *ctxt)
+{
+    WCHAR *arg1, *arg2;
+    bool ret;
+
+    arg2 = xpath_pop_string(ctxt);
+    arg1 = xpath_pop_string(ctxt);
+
+    ret = wcsicmp(arg1, arg2) == 0;
+
+    free(arg1);
+    free(arg2);
+
+    return ret;
+}
+
 static int xpath_comp_op_eval(struct xpath_parser_context *ctxt, struct xpath_step_op *op)
 {
     struct xpath_object *arg1, *arg2;
@@ -5311,6 +5414,37 @@ static int xpath_comp_op_eval(struct xpath_parser_context *ctxt, struct xpath_st
             if (ctxt->value && ctxt->value->type == _XPATH_NODESET)
                 xpath_nodeset_sort(ctxt->value->nodesetval);
             break;
+        case XPATH_OP_NOT:
+            if (op->ch1 != -1)
+                total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch1]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+
+            xpath_builtin_not(ctxt, 1);
+            break;
+        case XPATH_OP_ICMP:
+            total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch1]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+            total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch2]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+            ret = xpath_icompare_values(ctxt, op->value, op->value2);
+            xpath_push_value(ctxt, xpath_new_boolean(ctxt, ret));
+            break;
+        case XPATH_OP_IEQUAL:
+            total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch1]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+            total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch2]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+            equal = xpath_iequal_values(ctxt);
+            if (!op->value) equal = !equal;
+            xpath_push_value(ctxt, xpath_new_boolean(ctxt, equal));
+            break;
+        case XPATH_OP_ALL:
+            if (op->ch1 != -1)
+                total += xpath_comp_op_eval(ctxt, &comp->steps.values[op->ch1]);
+            if (ctxt->error != XPATH_EXPRESSION_OK) return 0;
+            if (ctxt->value)
+                ctxt->value->all = true;
+            break;
         default:
             WARN("Unknown precompiled operation %d.\n", op->op);
             ctxt->error = XPATH_INVALID_OPERAND;
@@ -5340,13 +5474,18 @@ static int xpath_run_eval(struct xpath_parser_context *ctxt)
     return 0;
 }
 
+static void xslpattern_compile_expr(struct xpath_parser_context *ctxt, bool sort);
+
 static void xpath_eval_expr(struct xpath_parser_context *ctxt)
 {
     int oldDepth = 0;
 
     if (ctxt->context)
         oldDepth = ctxt->context->depth;
-    xpath_compile_expr(ctxt, true);
+    if (ctxt->context->xpath)
+        xpath_compile_expr(ctxt, true);
+    else
+        xslpattern_compile_expr(ctxt, true);
     if (ctxt->context)
         ctxt->context->depth = oldDepth;
 
@@ -6599,139 +6738,919 @@ static WCHAR * xpath_pop_string(struct xpath_parser_context *ctxt)
     return ret;
 }
 
-/* XSLPattern translated functions */
+/* XSLPattern */
 
-/* Indexing is 0-based in XSLPattern */
-static void xpath_builtin_index(struct xpath_parser_context *ctxt, int nargs)
+/**
+ *  FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
+ *  Argument ::=   Expr
+ */
+static void xslpattern_compile_function_call(struct xpath_parser_context *ctxt)
 {
-    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
-        return;
+    struct xpath_qname name;
+    int nbargs = 0;
 
-    xpath_builtin_position(ctxt, 0);
-    xpath_push_value(ctxt, xpath_new_number(ctxt, xpath_pop_number(ctxt) - 1.0));
-}
+    xpath_parse_qname(ctxt, &name);
+    if (!name.name)
+    {
+        xpath_free_qname(&name);
+        return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+    }
+    xpath_parse_skipspaces(ctxt);
 
-/* Boolean end() = pos == last */
-static void xpath_builtin_end(struct xpath_parser_context *ctxt, int nargs)
-{
-    double pos, last;
+    if (!xpath_parse_cmp(ctxt, L"("))
+    {
+        xpath_free_qname(&name);
+        return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+    }
+    xpath_parse_skipspaces(ctxt);
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
-        return;
+    ctxt->comp->last = -1;
+    if (*ctxt->cur != ')')
+    {
+        while (*ctxt->cur)
+        {
+            int op1 = ctxt->comp->last;
+            ctxt->comp->last = -1;
+            xslpattern_compile_expr(ctxt, true);
+            if (ctxt->error != XPATH_EXPRESSION_OK)
+            {
+                xpath_free_qname(&name);
+                return;
+            }
+            xpath_push_binary_step(ctxt, XPATH_OP_ARG, op1, ctxt->comp->last, 0, 0);
+            nbargs++;
+            if (*ctxt->cur == ')') break;
+            if (!xpath_parse_cmp(ctxt, L","))
+            {
+                xpath_free_qname(&name);
+                return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+            }
+            xpath_parse_skipspaces(ctxt);
+        }
+    }
 
-    xpath_builtin_position(ctxt, 0);
-    pos = xpath_pop_number(ctxt);
-    xpath_builtin_last(ctxt, 0);
-    last = xpath_pop_number(ctxt);
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, pos == last));
+    xpath_push_long_step(ctxt, XPATH_OP_FUNCTION, nbargs, 0, 0, name.name, name.prefix);
+    xpath_parse_next(ctxt);
+    xpath_parse_skipspaces(ctxt);
 }
 
-/* Returns numeric value for context node type. */
-static void xpath_builtin_node_type(struct xpath_parser_context *ctxt, int nargs)
+/*
+ *  PrimaryExpr ::=
+ *         | '(' Expr ')'
+ *         | Literal
+ *         | Number
+ *         | FunctionCall
+ */
+static void xslpattern_compile_primary_expr(struct xpath_parser_context *ctxt)
 {
-    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
-        return;
-
-    xpath_push_value(ctxt, xpath_new_number(ctxt, ctxt->context->node->type));
+    xpath_parse_skipspaces(ctxt);
+    if (xpath_parse_cmp(ctxt, L"("))
+    {
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_expr(ctxt, true);
+        if (!xpath_parse_cmp(ctxt, L")"))
+            return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+        xpath_parse_skipspaces(ctxt);
+    }
+    else if (is_ascii_digit(*ctxt->cur) || (*ctxt->cur == '.' && is_ascii_digit(ctxt->cur[1])))
+    {
+        xpath_compile_number(ctxt);
+    }
+    else if (*ctxt->cur == '\'' || *ctxt->cur == '"')
+    {
+        xpath_compile_literal(ctxt);
+    }
+    else
+    {
+        xslpattern_compile_function_call(ctxt);
+    }
+    xpath_parse_skipspaces(ctxt);
 }
 
-static void xpath_builtin_ieq(struct xpath_parser_context *ctxt, int nargs)
+/**
+ *  FilterExpr ::=   PrimaryExpr
+ *        | FilterExpr Predicate
+ */
+static void xslpattern_compile_filter_expr(struct xpath_parser_context *ctxt)
 {
-    WCHAR *arg1, *arg2;
-
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
-        return;
-
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
-
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) == 0));
+    xslpattern_compile_primary_expr(ctxt);
+    xpath_parse_skipspaces(ctxt);
 
-    free(arg1);
-    free(arg2);
+    while (*ctxt->cur == '[')
+    {
+        xpath_compile_predicate(ctxt, true);
+        xpath_parse_skipspaces(ctxt);
+    }
 }
 
-static void xpath_builtin_ineq(struct xpath_parser_context *ctxt, int nargs)
-{
-    WCHAR *arg1, *arg2;
+/**
+ *  NodeType ::=   'comment'
+ *             | 'text'
+ *             | 'pi'
+ *             | 'node'
+ *             | 'textnode'
+ *             | 'cdata'
+ *             | 'attribute'
+ *             | 'element'
+ */
+static bool xslpattern_is_nodetype(const WCHAR *name, enum xpath_type *type)
+{
+    static const struct
+    {
+        const WCHAR *name;
+        enum xpath_type type;
+    }
+    types[] =
+    {
+        { L"node", NODE_TYPE_NODE },
+        { L"comment", NODE_TYPE_COMMENT },
+        { L"text", NODE_TYPE_TEXT },
+        { L"textnode", NODE_TYPE_TEXT },
+        { L"pi", NODE_TYPE_PI },
+        { L"element", NODE_TYPE_ELEMENT },
+        { L"attribute", NODE_TYPE_ATTRIBUTE },
+        { L"cdata", NODE_TYPE_CDATA },
+    };
+
+    for (int i = 0; i < ARRAYSIZE(types); ++i)
+    {
+        if (!wcscmp(types[i].name, name))
+        {
+            if (type) *type = types[i].type;
+            return true;
+        }
+    }
+
+    return false;
+}
+
+/*
+ *  Predicate ::= '[' Expr ']'
+ */
+static void xslpattern_compile_predicate(struct xpath_parser_context *ctxt, bool filter)
+{
+    int op1 = ctxt->comp->last;
+
+    xpath_parse_skipspaces(ctxt);
+    if (!xpath_parse_cmp(ctxt, L"["))
+        return xpath_parser_context_set_error(ctxt, XPATH_INVALID_PREDICATE_ERROR);
+    xpath_parse_skipspaces(ctxt);
+
+    ctxt->comp->last = -1;
+    xslpattern_compile_expr(ctxt, filter);
+    if (ctxt->error != XPATH_EXPRESSION_OK)
+        return;
+
+    if (!xpath_parse_cmp(ctxt, L"]"))
+        return xpath_parser_context_set_error(ctxt, XPATH_INVALID_PREDICATE_ERROR);
+
+    if (filter)
+        xpath_push_binary_step(ctxt, XPATH_OP_FILTER, op1, ctxt->comp->last, 0, 0);
+    else
+        xpath_push_binary_step(ctxt, XPATH_OP_PREDICATE, op1, ctxt->comp->last, 0, 0);
+
+    xpath_parse_skipspaces(ctxt);
+}
+
+/*
+ * NodeTest ::=   NameTest
+ *            | NodeType '(' ')'
+ *            | 'pi' '(' Literal ')'
+ *            | 'attribute' '(' Literal ')'
+ *            | 'element' '(' Literal ')'
+ *
+ * NameTest ::=  '*'
+ *            | NCName ':' '*'
+ *            | QName
+ * NodeType ::= 'comment'
+ *            | 'text'
+ *            | 'pi'
+ *            | 'node'
+ *            | 'textnode'
+ *            | 'cdata'
+ *            | 'element'
+ *            | 'attribute'
+ */
+static WCHAR * xslpattern_compile_nodetest(struct xpath_parser_context *ctxt, enum xpath_axis *axis,
+        enum xpath_test *test, enum xpath_type *type, WCHAR **prefix, WCHAR *name)
+{
+    bool blanks;
+
+    *type = 0;
+    *test = 0;
+    *prefix = NULL;
+    xpath_parse_skipspaces(ctxt);
+
+    if (!name && *ctxt->cur == '*')
+    {
+        xpath_parse_next(ctxt);
+        *test = NODE_TEST_ALL;
+        return NULL;
+    }
+
+    if (!name)
+        name = xpath_parse_nc_name(ctxt);
+    if (!name)
+    {
+        xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+        return NULL;
+    }
+
+    blanks = xml_is_space(*ctxt->cur);
+    xpath_parse_skipspaces(ctxt);
+    if (xpath_parse_cmp(ctxt, L"("))
+    {
+        if (!xslpattern_is_nodetype(name, type))
+        {
+            free(name);
+            xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+            return NULL;
+        }
+
+        if (*type == NODE_TYPE_ATTRIBUTE)
+        {
+            *axis = AXIS_ATTRIBUTE;
+        }
+
+        *test = NODE_TEST_TYPE;
+
+        xpath_parse_skipspaces(ctxt);
+
+        /* Optional node name */
+        if (*type == NODE_TYPE_PI
+                || *type == NODE_TYPE_ATTRIBUTE
+                || *type == NODE_TYPE_ELEMENT)
+        {
+            free(name);
+            name = NULL;
+            if (*ctxt->cur != ')')
+            {
+                const WCHAR *p = ctxt->cur;
+                bool star = false;
+
+                name = xpath_parse_literal(ctxt);
+                if (!name)
+                {
+                    xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+                    return NULL;
+                }
+
+                /* XPath does not support such notation, it's equivalent to empty braces. */
+                if (!wcscmp(name, L"*"))
+                {
+                    star = true;
+                    free(name);
+                    name = NULL;
+                }
+
+                if (*type == NODE_TYPE_PI)
+                {
+                    *test = NODE_TEST_PI;
+                }
+                else if (!star)
+                {
+                    struct xpath_qname qname;
+
+                    *test = NODE_TEST_NAME;
+
+                    free(name);
+                    name = NULL;
+
+                    ctxt->cur = p;
+                    xpath_parse_next(ctxt);
+                    xpath_parse_qname(ctxt, &qname);
+                    xpath_parse_next(ctxt);
+
+                    *prefix = qname.prefix;
+                    name = qname.name;
+                }
+
+                xpath_parse_skipspaces(ctxt);
+            }
+        }
+        if (*ctxt->cur != ')')
+        {
+            free(*prefix);
+            free(name);
+            xpath_parser_context_set_error(ctxt, XPATH_UNCLOSED_ERROR);
+            return NULL;
+        }
+        xpath_parse_next(ctxt);
+        return name;
+    }
+
+    *test = NODE_TEST_NAME;
+    if (!blanks && *ctxt->cur == ':')
+    {
+        xpath_parse_next(ctxt);
+
+        *prefix = name;
+
+        if (xpath_parse_cmp(ctxt, L"*"))
+        {
+            *test = NODE_TEST_ALL;
+            return NULL;
+        }
+
+        name = xpath_parse_nc_name(ctxt);
+        if (!name)
+        {
+            xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+            return NULL;
+        }
+    }
+
+    return name;
+}
+
+/*
+ * Step ::= '@'? NodeTest Predicate*
+ *              | '.'
+ *              | '..'
+ */
+static void xslpattern_compile_step(struct xpath_parser_context *ctxt)
+{
+    WCHAR *prefix = NULL, *name = NULL;
+    enum xpath_test test = 0;
+    enum xpath_axis axis = 0;
+    enum xpath_type type = 0;
+    int op1;
+
+    if (ctxt->error != XPATH_EXPRESSION_OK)
+        return;
+
+    xpath_parse_skipspaces(ctxt);
+
+    if (xpath_parse_cmp(ctxt, L".."))
+    {
+        xpath_parse_skipspaces(ctxt);
+        xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_PARENT, NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
+    }
+    else if (xpath_parse_cmp(ctxt, L"."))
+    {
+        xpath_parse_skipspaces(ctxt);
+    }
+    else
+    {
+        /* Peek ahead into NodeTest */
+        if (*ctxt->cur == '*')
+        {
+            axis = AXIS_CHILD;
+        }
+        else
+        {
+            axis = AXIS_CHILD;
+
+            name = xpath_parse_nc_name(ctxt);
+            if (!name && xpath_parse_cmp(ctxt, L"@"))
+            {
+                axis = AXIS_ATTRIBUTE;
+            }
+        }
+
+        if (ctxt->error != XPATH_EXPRESSION_OK)
+        {
+            free(name);
+            return;
+        }
+
+        name = xslpattern_compile_nodetest(ctxt, &axis, &test, &type, &prefix, name);
+        if (test == 0)
+            return;
+
+        op1 = ctxt->comp->last;
+        ctxt->comp->last = -1;
+
+        xpath_parse_skipspaces(ctxt);
+        while (*ctxt->cur == '[')
+        {
+            xslpattern_compile_predicate(ctxt, false);
+        }
+
+        if (!xpath_push_full_step(ctxt, XPATH_OP_COLLECT, op1, ctxt->comp->last, axis, test, type, prefix, name))
+        {
+            free(prefix);
+            free(name);
+        }
+    }
+}
+
+/*
+ *  RelativeLocationPath ::=   Step
+ *               | RelativeLocationPath '/' Step
+ *               | RelativeLocationPath '//' Step
+ *               | RelativeLocationPath '!' FunctionCall
+ */
+static void xslpattern_compile_relative_location_path(struct xpath_parser_context *ctxt)
+{
+    WCHAR *name;
+
+    xpath_parse_skipspaces(ctxt);
+    if (xpath_parse_cmp(ctxt, L"//"))
+    {
+        xpath_parse_skipspaces(ctxt);
+        xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
+                NODE_TYPE_NODE, NULL, NULL);
+    }
+    else if (xpath_parse_cmp(ctxt, L"/"))
+    {
+        xpath_parse_skipspaces(ctxt);
+    }
+    xslpattern_compile_step(ctxt);
+    if (ctxt->error != XPATH_EXPRESSION_OK)
+        return;
+
+    xpath_parse_skipspaces(ctxt);
+    while (ctxt->cur[0] == '/' || (ctxt->cur[0] == '!' && ctxt->cur[1] != '='))
+    {
+        if (xpath_parse_cmp(ctxt, L"//"))
+        {
+            xpath_parse_skipspaces(ctxt);
+            xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
+                    NODE_TYPE_NODE, NULL, NULL);
+            xslpattern_compile_step(ctxt);
+        }
+        else if (xpath_parse_cmp(ctxt, L"/"))
+        {
+            xpath_parse_skipspaces(ctxt);
+            xslpattern_compile_step(ctxt);
+        }
+        else if (ctxt->cur[0] == '!' && ctxt->cur[1] != '=')
+        {
+            xpath_parse_next(ctxt);
+            xpath_parse_skipspaces(ctxt);
+
+            /* For node type tests defer to Step, checking if looks like a functional notation. */
+            name = xpath_scan_name(ctxt);
+            if (xslpattern_is_nodetype(name, NULL))
+            {
+                const WCHAR *p = ctxt->cur + wcslen(name);
+
+                while (xml_is_space(*p))
+                    ++p;
+                if (*p == '(')
+                    xslpattern_compile_step(ctxt);
+                else
+                    xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+            }
+            else
+            {
+                xslpattern_compile_function_call(ctxt);
+            }
+            free(name);
+        }
+        xpath_parse_skipspaces(ctxt);
+    }
+}
+
+/*
+ *  LocationPath ::=   RelativeLocationPath
+ *               | AbsoluteLocationPath
+ *  AbsoluteLocationPath ::=   '/' RelativeLocationPath?
+ *               | '//' RelativeLocationPath
+ */
+static void xslpattern_compile_location_path(struct xpath_parser_context *ctxt)
+{
+    xpath_parse_skipspaces(ctxt);
+    if (*ctxt->cur != '/')
+    {
+        xslpattern_compile_relative_location_path(ctxt);
+    }
+    else
+    {
+        while (*ctxt->cur == '/')
+        {
+            if (xpath_parse_cmp(ctxt, L"//"))
+            {
+                xpath_parse_skipspaces(ctxt);
+                xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
+                        NODE_TYPE_NODE, NULL, NULL);
+                xslpattern_compile_relative_location_path(ctxt);
+            }
+            else if (xpath_parse_cmp(ctxt, L"/"))
+            {
+                xpath_parse_skipspaces(ctxt);
+                if (*ctxt->cur &&
+                        ((is_ascii_letter(*ctxt->cur)) || (*ctxt->cur >= 0x80) ||
+                        (*ctxt->cur == '_') || (*ctxt->cur == '.') ||
+                        (*ctxt->cur == '@') || (*ctxt->cur == '*')))
+                {
+                    xslpattern_compile_relative_location_path(ctxt);
+                }
+            }
+            if (ctxt->error != XPATH_EXPRESSION_OK)
+                return;
+        }
+    }
+}
+
+/*
+ *  PathExpr ::=   LocationPath
+ *        | FilterExpr
+ *        | FilterExpr '/' RelativeLocationPath
+ *        | FilterExpr '//' RelativeLocationPath
+ */
+static void xslpattern_compile_path_expr(struct xpath_parser_context *ctxt)
+{
+    bool location_path = true;
+    WCHAR *name = NULL;
+
+    xpath_parse_skipspaces(ctxt);
+    if (*ctxt->cur == '$' || *ctxt->cur == '(' ||
+        is_ascii_digit(*ctxt->cur) ||
+        (*ctxt->cur == '\'') || *ctxt->cur == '"' ||
+        (*ctxt->cur == '.' && is_ascii_digit(ctxt->cur[1])))
+    {
+        location_path = false;
+    }
+    else if ((*ctxt->cur == '*')
+            || (*ctxt->cur == '/')
+            || (*ctxt->cur == '@')
+            || (*ctxt->cur == '.'))
+    {
+        location_path = true;
+    }
+    else
+    {
+        xpath_parse_skipspaces(ctxt);
+        name = xpath_scan_name(ctxt);
+        if (name)
+        {
+            int len = wcslen(name);
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
-        return;
+            while (ctxt->cur[len])
+            {
+                if (!xml_is_space(ctxt->cur[len]))
+                    break;
+                ++len;
+            }
 
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
+            location_path = true;
+            if (ctxt->cur[len] && ctxt->cur[len++] == '(')
+                location_path = xslpattern_is_nodetype(name, NULL);
+
+            if (!ctxt->cur[len])
+                location_path = true;
+            free(name);
+        }
+    }
 
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) != 0));
+    if (location_path)
+    {
+        if (*ctxt->cur == '/')
+            xpath_push_leave_step(ctxt, XPATH_OP_ROOT, 0, 0);
+        else
+            xpath_push_leave_step(ctxt, XPATH_OP_NODE, 0, 0);
+        xslpattern_compile_location_path(ctxt);
+    }
+    else
+    {
+        xslpattern_compile_filter_expr(ctxt);
 
-    free(arg1);
-    free(arg2);
+        if (xpath_parse_cmp(ctxt, L"//"))
+        {
+            xpath_parse_skipspaces(ctxt);
+            xpath_push_long_step(ctxt, XPATH_OP_COLLECT, AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
+                    NODE_TYPE_NODE, NULL, NULL);
+
+            xslpattern_compile_relative_location_path(ctxt);
+        }
+        else if (ctxt->cur[0] == '/')
+        {
+            xslpattern_compile_relative_location_path(ctxt);
+        }
+    }
+    xpath_parse_skipspaces(ctxt);
 }
 
-static void xpath_builtin_ilt(struct xpath_parser_context *ctxt, int nargs)
+/*
+ *  UnionExpr ::=   PathExpr
+ *        | UnionExpr '|' PathExpr
+ */
+static void xslpattern_compile_union_expr(struct xpath_parser_context *ctxt)
 {
-    WCHAR *arg1, *arg2;
+    xslpattern_compile_path_expr(ctxt);
+    xpath_parse_skipspaces(ctxt);
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
-        return;
+    while (ctxt->cur[0] == '|' && ctxt->cur[1] != '|')
+    {
+        int op1 = ctxt->comp->last;
 
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
+        xpath_push_leave_step(ctxt, XPATH_OP_NODE, 0, 0);
 
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) < 0));
+        xpath_parse_next(ctxt);
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_path_expr(ctxt);
 
-    free(arg1);
-    free(arg2);
+        xpath_push_binary_step(ctxt, XPATH_OP_UNION, op1, ctxt->comp->last, 0, 0);
+        xpath_parse_skipspaces(ctxt);
+    }
 }
 
-static void xpath_builtin_ileq(struct xpath_parser_context *ctxt, int nargs)
+static unsigned int xslpattern_parse_relation_op(struct xpath_parser_context *ctxt)
 {
-    WCHAR *arg1, *arg2;
+    static const struct
+    {
+        const WCHAR *name;
+        int flags;
+    }
+    ops[] =
+    {
+        { L"<=", COMPOP_LE },
+        { L"<",  COMPOP_LT },
+        { L">=", COMPOP_GE },
+        { L">",  COMPOP_GT },
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
-        return;
+        { L"$le$", COMPOP_LE },
+        { L"$lt$", COMPOP_LT },
+        { L"$ge$", COMPOP_GE },
+        { L"$gt$", COMPOP_GT },
 
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
+        { L"$ile$", COMPOP_LE | COMPOP_I },
+        { L"$ilt$", COMPOP_LT | COMPOP_I },
+        { L"$ige$", COMPOP_GE | COMPOP_I },
+        { L"$igt$", COMPOP_GT | COMPOP_I },
+    };
 
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) <= 0));
+    for (int i = 0; i < ARRAYSIZE(ops); ++i)
+    {
+        if (xpath_parse_cmp(ctxt, ops[i].name))
+            return ops[i].flags;
+    }
 
-    free(arg1);
-    free(arg2);
+    return COMPOP_NONE;
 }
 
-static void xpath_builtin_igt(struct xpath_parser_context *ctxt, int nargs)
+static bool xslpattern_parse_compare_modifiers(struct xpath_parser_context *ctxt)
 {
-    WCHAR *arg1, *arg2;
+    if (xpath_parse_cmp(ctxt, L"$all$"))
+        return true;
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
+    /* Ignored */
+    xpath_parse_cmp(ctxt, L"$any$");
+
+    return false;
+}
+
+/*
+ *  RelationalExpr ::= ($any$ | $all$)?  UnionExpr
+ *          | RelationalExpr ('<' | '$lt$') UnionExpr
+ *          | RelationalExpr ('>' | '$gt$') UnionExpr
+ *          | RelationalExpr ('<=' | '$le$') UnionExpr
+ *          | RelationalExpr ('>=' | '$ge$') UnionExpr
+ *          | RelationalExpr '$ilt$' UnionExpr
+ *          | RelationalExpr '$igt$' UnionExpr
+ *          | RelationalExpr '$ile$' UnionExpr
+ *          | RelationalExpr '$ige$' UnionExpr
+ *
+ */
+static void xslpattern_compile_relational_expr(struct xpath_parser_context *ctxt)
+{
+    unsigned int op;
+    bool all;
+
+    all = xslpattern_parse_compare_modifiers(ctxt);
+    xslpattern_compile_union_expr(ctxt);
+    if (all)
+        xpath_push_unary_step(ctxt, XPATH_OP_ALL, ctxt->comp->last, 0, 0);
+    xpath_parse_skipspaces(ctxt);
+
+    if ((op = xslpattern_parse_relation_op(ctxt)) != COMPOP_NONE)
+    {
+        int op1 = ctxt->comp->last;
+
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_union_expr(ctxt);
+        if (op & COMPOP_I)
+            xpath_push_binary_step(ctxt, XPATH_OP_ICMP, op1, ctxt->comp->last, op & COMPOP_LT, !(op & COMPOP_NOTSTRICT));
+        else
+            xpath_push_binary_step(ctxt, XPATH_OP_CMP, op1, ctxt->comp->last, op & COMPOP_LT, !(op & COMPOP_NOTSTRICT));
+        xpath_parse_skipspaces(ctxt);
+    }
+}
+
+static unsigned int xslpattern_parse_eq_op(struct xpath_parser_context *ctxt)
+{
+    static const struct
+    {
+        const WCHAR *name;
+        int flags;
+    }
+    ops[] =
+    {
+        { L"=",  COMPOP_EQ },
+        { L"!=", COMPOP_NE },
+
+        { L"$eq$", COMPOP_EQ },
+        { L"$ne$", COMPOP_NE },
+
+        { L"$ieq$", COMPOP_EQ | COMPOP_I },
+        { L"$ine$", COMPOP_NE | COMPOP_I },
+    };
+
+    for (int i = 0; i < ARRAYSIZE(ops); ++i)
+    {
+        if (xpath_parse_cmp(ctxt, ops[i].name))
+            return ops[i].flags;
+    }
+
+    return COMPOP_NONE;
+}
+
+/*
+ *  EqualityExpr ::=   RelationalExpr
+ *          | EqualityExpr ('=' | '$eq') RelationalExpr
+ *          | EqualityExpr ('!=' | '$ne$') RelationalExpr
+ *          | EqualityExpr '$ine$' RelationalExpr
+ *          | EqualityExpr '$ieq$' RelationalExpr
+ */
+static void xslpattern_compile_equality_expr(struct xpath_parser_context *ctxt)
+{
+    unsigned int op;
+    bool all;
+
+    all = xslpattern_parse_compare_modifiers(ctxt);
+    xslpattern_compile_relational_expr(ctxt);
+    if (all)
+        xpath_push_unary_step(ctxt, XPATH_OP_ALL, ctxt->comp->last, 0, 0);
+    xpath_parse_skipspaces(ctxt);
+
+    if ((op = xslpattern_parse_eq_op(ctxt)) != COMPOP_NONE)
+    {
+        int op1 = ctxt->comp->last;
+
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_relational_expr(ctxt);
+        if (op & COMPOP_I)
+            xpath_push_binary_step(ctxt, XPATH_OP_IEQUAL, op1, ctxt->comp->last, op & COMPOP_EQ, 0);
+        else
+            xpath_push_binary_step(ctxt, XPATH_OP_EQUAL, op1, ctxt->comp->last, op & COMPOP_EQ, 0);
+        xpath_parse_skipspaces(ctxt);
+    }
+}
+
+/*
+ *  NegationExpr ::= EqualityExpr
+ *          | '$not$' NegationExpr
+ *          | not( NegationExpr )
+ */
+static void xslpattern_compile_negation_expr(struct xpath_parser_context *ctxt)
+{
+    bool neg = false, functional = false;
+
+    xpath_parse_skipspaces(ctxt);
+    if (xpath_parse_cmp(ctxt, L"$not$"))
+    {
+        xpath_parse_skipspaces(ctxt);
+        neg = true;
+    }
+    else if (xpath_parse_cmp(ctxt, L"not"))
+    {
+        xpath_parse_skipspaces(ctxt);
+        if (!xpath_parse_cmp(ctxt, L"("))
+            return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+        neg = functional = true;
+    }
+
+    xslpattern_compile_equality_expr(ctxt);
+
+    if (functional)
+    {
+        xpath_parse_skipspaces(ctxt);
+        if (!xpath_parse_cmp(ctxt, L")"))
+            return xpath_parser_context_set_error(ctxt, XPATH_EXPR_ERROR);
+    }
+
+    if (neg)
+        xpath_push_unary_step(ctxt, XPATH_OP_NOT, ctxt->comp->last, 0, 0);
+}
+
+/*
+ *  AndExpr ::= NegationExpr
+ *          | NegationExpr ('and' | '$and$' | '&&') AndExpr
+ */
+static void xslpattern_compile_and_expr(struct xpath_parser_context *ctxt)
+{
+    xslpattern_compile_negation_expr(ctxt);
+    xpath_parse_skipspaces(ctxt);
+    while (xpath_parse_cmp(ctxt, L"and")
+            || xpath_parse_cmp(ctxt, L"$and$")
+            || xpath_parse_cmp(ctxt, L"&&"))
+    {
+        int op1 = ctxt->comp->last;
+
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_negation_expr(ctxt);
+        xpath_push_binary_step(ctxt, XPATH_OP_AND, op1, ctxt->comp->last, 0, 0);
+        xpath_parse_skipspaces(ctxt);
+    }
+}
+
+/*
+ *  Expr ::=   OrExpr
+ *  OrExpr ::=   AndExpr
+ *            | OrExpr ('or' | '$or$' | '||')  AndExpr
+ */
+static void xslpattern_compile_expr(struct xpath_parser_context *ctxt, bool sort)
+{
+    struct xpath_context *xpctxt = ctxt->context;
+
+    if (ctxt->error != XPATH_EXPRESSION_OK)
         return;
 
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
+    if (xpctxt)
+    {
+        if (xpctxt->depth >= XPATH_MAX_RECURSION_DEPTH)
+            return xpath_parser_context_set_error(ctxt, XPATH_RECURSION_LIMIT_EXCEEDED);
+
+        xpctxt->depth += 10;
+    }
 
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) > 0));
+    xslpattern_compile_and_expr(ctxt);
 
-    free(arg1);
-    free(arg2);
+    xpath_parse_skipspaces(ctxt);
+    while (xpath_parse_cmp(ctxt, L"or")
+            || xpath_parse_cmp(ctxt, L"$or$")
+            || xpath_parse_cmp(ctxt, L"||"))
+    {
+        int op1 = ctxt->comp->last;
+
+        xpath_parse_skipspaces(ctxt);
+        xslpattern_compile_and_expr(ctxt);
+        xpath_push_binary_step(ctxt, XPATH_OP_OR, op1, ctxt->comp->last, 0, 0);
+        xpath_parse_skipspaces(ctxt);
+    }
+
+    if (sort && (ctxt->comp->steps.values[ctxt->comp->last].op != XPATH_OP_VALUE))
+    {
+        /* more ops could be optimized too */
+        /*
+        * This is the main place to eliminate sorting for
+        * operations which don't require a sorted node-set.
+        * E.g. count().
+        */
+        xpath_push_unary_step(ctxt, XPATH_OP_SORT, ctxt->comp->last, 0, 0);
+    }
+
+    if (xpctxt)
+        xpctxt->depth -= 10;
 }
 
-static void xpath_builtin_igeq(struct xpath_parser_context *ctxt, int nargs)
+/* Indexing is 0-based in XSLPattern */
+static void xslpattern_builtin_index(struct xpath_parser_context *ctxt, int nargs)
 {
-    WCHAR *arg1, *arg2;
+    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
+        return;
 
-    if (!xpath_builtin_check_stack(ctxt, nargs, 2))
+    xpath_builtin_position(ctxt, 0);
+    xpath_push_value(ctxt, xpath_new_number(ctxt, xpath_pop_number(ctxt) - 1.0));
+}
+
+/* Boolean end() = pos == last */
+static void xslpattern_builtin_end(struct xpath_parser_context *ctxt, int nargs)
+{
+    double pos, last;
+
+    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
         return;
 
-    arg2 = xpath_pop_string(ctxt);
-    arg1 = xpath_pop_string(ctxt);
+    xpath_builtin_position(ctxt, 0);
+    pos = xpath_pop_number(ctxt);
+    xpath_builtin_last(ctxt, 0);
+    last = xpath_pop_number(ctxt);
+    xpath_push_value(ctxt, xpath_new_boolean(ctxt, pos == last));
+}
 
-    xpath_push_value(ctxt, xpath_new_boolean(ctxt, wcsicmp(arg1, arg2) >= 0));
+/* Returns numeric value for context node type. */
+static void xslpattern_builtin_node_type(struct xpath_parser_context *ctxt, int nargs)
+{
+    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
+        return;
 
-    free(arg1);
-    free(arg2);
+    xpath_push_value(ctxt, xpath_new_number(ctxt, ctxt->context->node->type));
+}
+
+static void xslpattern_builtin_node_name(struct xpath_parser_context *ctxt, int nargs)
+{
+    struct domnode *node;
+
+    if (!xpath_builtin_check_stack(ctxt, nargs, 0))
+        return;
+
+    node = ctxt->context->node;
+    switch (node->type)
+    {
+        case NODE_ELEMENT:
+        case NODE_ATTRIBUTE:
+            xpath_push_value(ctxt, xpath_new_string(ctxt, node->qname));
+            break;
+        default:
+            xpath_push_value(ctxt, xpath_new_string(ctxt, node->name));
+            break;
+    }
 }
 
-static void xpath_register_all_functions(struct xpath_context *ctxt)
+static void xpath_register_xpath_functions(struct xpath_context *ctxt)
 {
     xpath_register_func(ctxt, L"boolean", xpath_builtin_boolean);
     xpath_register_func(ctxt, L"ceiling", xpath_builtin_ceiling);
@@ -6764,15 +7683,10 @@ static void xpath_register_all_functions(struct xpath_context *ctxt)
 
 static void xpath_register_xslpattern_functions(struct xpath_context *ctxt)
 {
-    xpath_register_func(ctxt, L"index", xpath_builtin_index);
-    xpath_register_func(ctxt, L"end", xpath_builtin_end);
-    xpath_register_func(ctxt, L"nodeType", xpath_builtin_node_type);
-    xpath_register_func(ctxt, L"OP_IEq", xpath_builtin_ieq);
-    xpath_register_func(ctxt, L"OP_INEq", xpath_builtin_ineq);
-    xpath_register_func(ctxt, L"OP_ILt", xpath_builtin_ilt);
-    xpath_register_func(ctxt, L"OP_ILEq", xpath_builtin_ileq);
-    xpath_register_func(ctxt, L"OP_IGt", xpath_builtin_igt);
-    xpath_register_func(ctxt, L"OP_IGEq", xpath_builtin_igeq);
+    xpath_register_func(ctxt, L"index", xslpattern_builtin_index);
+    xpath_register_func(ctxt, L"end", xslpattern_builtin_end);
+    xpath_register_func(ctxt, L"nodeType", xslpattern_builtin_node_type);
+    xpath_register_func(ctxt, L"nodeName", xslpattern_builtin_node_name);
 }
 
 struct xpath_context * xpath_create_context(bool xpath, struct domnode *node)
@@ -6793,8 +7707,9 @@ struct xpath_context * xpath_create_context(bool xpath, struct domnode *node)
     ret->contextSize = -1;
     ret->proximityPosition = -1;
 
-    xpath_register_all_functions(ret);
-    if (!xpath)
+    if (xpath)
+        xpath_register_xpath_functions(ret);
+    else
         xpath_register_xslpattern_functions(ret);
 
     return ret;
diff --git a/dlls/msxml3/xpath.h b/dlls/msxml3/xpath.h
index 15840fbdc659..4f39d22b53f7 100644
--- a/dlls/msxml3/xpath.h
+++ b/dlls/msxml3/xpath.h
@@ -42,10 +42,7 @@ struct xpath_object
     int boolval;
     double floatval;
     WCHAR *stringval;
-    void *user;
-    int index;
-    void *user2;
-    int index2;
+    bool all;
 };
 
 struct xpath_namespace
diff --git a/dlls/msxml3/xslpattern.h b/dlls/msxml3/xslpattern.h
deleted file mode 100644
index ddeb81801c05..000000000000
--- a/dlls/msxml3/xslpattern.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *    XSLPattern lexer/parser shared internals
- *
- * Copyright 2010 Adam Martinson for CodeWeavers
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#ifndef __XSLPATTERN__
-#define __XSLPATTERN__
-
-#include <stdlib.h>
-#include <libxml/tree.h>
-#include <libxml/xmlstring.h>
-#include <libxml/xpath.h>
-
-#include "windef.h"
-#include "winnt.h"
-
-typedef struct _parser_param {
-    void* yyscanner;
-    xmlXPathContextPtr ctx;
-    xmlChar const* in;
-    int pos;
-    int len;
-    xmlChar* out;
-    int err;
-} parser_param;
-
-#define XSLPATTERN_STYPE xmlChar*
-#define YY_EXTRA_TYPE parser_param*
-
-int  xslpattern_lex(xmlChar**, void*);
-int  xslpattern_lex_init(void**);
-int  xslpattern_lex_destroy(void*);
-void xslpattern_set_extra(parser_param*, void*);
-int  xslpattern_parse(parser_param*, void*);
-
-
-#endif /* __XSLPATTERN__ */
diff --git a/dlls/msxml3/xslpattern.l b/dlls/msxml3/xslpattern.l
deleted file mode 100644
index bfcfa1ac42af..000000000000
--- a/dlls/msxml3/xslpattern.l
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *    XSLPattern lexer
- *
- * Copyright 2010 Adam Martinson for CodeWeavers
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-%{
-#include "xslpattern.h"
-#include "xslpattern.tab.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msxml);
-
-#define SCAN    xslpattern_get_extra(yyscanner)
-#define YYSTYPE XSLPATTERN_STYPE
-
-#define YY_INPUT(tok_buf, tok_len, max) \
-        do { \
-            if (SCAN->pos <= SCAN->len) \
-            { \
-                tok_len = SCAN->len - SCAN->pos; \
-                if (tok_len > max) tok_len = max; \
-                memcpy(tok_buf, SCAN->in + SCAN->pos, tok_len); \
-                SCAN->pos += tok_len; \
-            } \
-            else \
-            { \
-                tok_len = YY_NULL; \
-            } \
-        } while (0);
-
-#define TOK(tok)    TRACE("token: %s : %s\n", #tok, yytext); return tok
-#define OP(tok)     *yylval=NULL; TOK(tok)
-#define SYM(tok)    *yylval=NULL; TOK(tok)
-#define STR(tok)    *yylval=xmlStrdup(BAD_CAST yytext); TOK(tok)
-
-
-%}
-
-%option reentrant bison-bridge
-%option noyywrap
-%option prefix="xslpattern_"
-%option noinput nounput never-interactive
-
-/* From the w3c XML standard
- * <http://www.w3.org/TR/REC-xml/> */
-
-    /* [2.3] Common Syntactic Constructs */
-WSpace          ([[:space:]])
-
-NCNameStartChar ([A-Za-z_]|[\xc0-\xd6\xd8-\xf6\xf8-\xff])
-
-NameCharEx      ([0-9]|[-._\xb7])
-
-NCNameChar      ({NCNameStartChar}|{NameCharEx})
-
-/* From the w3c XML Namespace standard
- * <http://www.w3.org/TR/REC-xml-names/> */
-
-    /* [3] Declaring Namespaces*/
-NCName          ({NCNameStartChar}{NCNameChar}*)
-
-/* Mostly verbatim from the w3c XPath standard.
- * <http://www.w3.org/TR/xpath/> */
-
-
-    /* [3.4] Booleans
-     * ||, &&, $foo$ are XSLPattern only */
-
-OP_Or           ("or"|"||"|"$or$")
-OP_And          ("and"|"&&"|"$and$")
-OP_Eq           ("="|"$eq$")
-OP_IEq          ("$ieq$")
-OP_NEq          ("!="|"$ne$")
-OP_INEq         ("$ine$")
-OP_Lt           ("<"|"$lt$")
-OP_ILt          ("$ilt$")
-OP_Gt           (">"|"$gt$")
-OP_IGt          ("$igt$")
-OP_LEq          ("<="|"$le$")
-OP_ILEq         ("$ile$")
-OP_GEq          (">="|"$ge$")
-OP_IGEq         ("$ige$")
-OP_Not          ("$not$")
-OP_All          ("$all$")
-OP_Any          ("$any$")
-
-    /* [3.7] Lexical Structure */
-Literal             (([\x22]([^\x22]*)[\x22])|([\x27]([^\x27]*)[\x27]))
-Number              ({Digits}("."{Digits}?)?|"."{Digits})
-Digits              ([0-9]+)
-
-ANY                 (.)
-
-%%
-
-{WSpace}+                   { /* ignored */ }
-{Literal}                   { STR(TOK_Literal); }
-"//"                        { SYM(TOK_DblFSlash); }
-"/"                         { SYM(TOK_FSlash); }
-".."                        { SYM(TOK_Parent); }
-"."                         { SYM(TOK_Self); }
-"::"                        { SYM(TOK_Axis); }
-":"                         { SYM(TOK_Colon); }
-"("                         { SYM('('); }
-")"                         { SYM(')'); }
-"["                         { SYM('['); }
-"]"                         { SYM(']'); }
-"@"                         { SYM('@'); }
-","                         { SYM(','); }
-"*"                         { SYM('*'); }
-{OP_And}                    { OP(TOK_OpAnd); }
-{OP_Or}                     { OP(TOK_OpOr); }
-{OP_Not}                    { OP(TOK_OpNot); }
-{OP_Eq}                     { OP(TOK_OpEq); }
-{OP_IEq}                    { OP(TOK_OpIEq); }
-{OP_NEq}                    { OP(TOK_OpNEq); }
-{OP_INEq}                   { OP(TOK_OpINEq); }
-{OP_Lt}                     { OP(TOK_OpLt); }
-{OP_ILt}                    { OP(TOK_OpILt); }
-{OP_Gt}                     { OP(TOK_OpGt); }
-{OP_IGt}                    { OP(TOK_OpIGt); }
-{OP_LEq}                    { OP(TOK_OpLEq); }
-{OP_ILEq}                   { OP(TOK_OpILEq); }
-{OP_GEq}                    { OP(TOK_OpGEq); }
-{OP_IGEq}                   { OP(TOK_OpIGEq); }
-{OP_All}                    { OP(TOK_OpAll); }
-{OP_Any}                    { OP(TOK_OpAny); }
-"|"                         { SYM('|'); }
-"!"                         { SYM('!'); }
-{NCName}                    { STR(TOK_NCName); }
-{Number}                    { STR(TOK_Number); }
-{ANY}                       { FIXME("Unexpected character '%s'.\n",yytext); }
-
-%%
-
-xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr, xmlChar const*);
-xmlChar* XSLPattern_to_XPath(xmlXPathContextPtr ctxt, xmlChar const* xslpat_str)
-{
-    parser_param p;
-    TRACE("(%s)\n", debugstr_a((char const*)xslpat_str));
-    memset(&p, 0, sizeof(parser_param));
-    p.ctx = ctxt;
-    p.in = xslpat_str;
-    p.len = xmlStrlen(xslpat_str);
-
-    xslpattern_lex_init(&p.yyscanner);
-    xslpattern_set_extra(&p, p.yyscanner);
-
-    xslpattern_parse(&p, p.yyscanner);
-
-    TRACE("=> %s\n", debugstr_a((char const*)p.out));
-    xslpattern_lex_destroy(p.yyscanner);
-
-    if (p.err)
-    {
-        xmlFree(p.out);
-        return xmlStrdup(xslpat_str);
-    }
-    else
-    {
-        return p.out;
-    }
-
-}
diff --git a/dlls/msxml3/xslpattern.y b/dlls/msxml3/xslpattern.y
deleted file mode 100644
index 549118aa7fe6..000000000000
--- a/dlls/msxml3/xslpattern.y
+++ /dev/null
@@ -1,751 +0,0 @@
-/*
- *    XSLPattern parser (XSLPattern => XPath)
- *
- * Copyright 2010 Adam Martinson for CodeWeavers
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-%{
-#include "xslpattern.h"
-#include <libxml/xpathInternals.h>
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(msxml);
-
-
-static const xmlChar NameTest_mod_pre[] = "*[name()='";
-static const xmlChar NameTest_mod_post[] = "']";
-
-#define U(str) BAD_CAST str
-
-static inline BOOL is_literal(xmlChar const* tok)
-{
-    return (tok && tok[0] && tok[1] &&
-            tok[0]== tok[xmlStrlen(tok)-1] &&
-            (tok[0] == '\'' || tok[0] == '"'));
-}
-
-static void xslpattern_error(parser_param* param, void const* scanner, char const* msg)
-{
-    param->err++;
-    FIXME("%s:\n"
-          "  param {\n"
-          "    yyscanner=%p\n"
-          "    ctx=%p\n"
-          "    in=\"%s\"\n"
-          "    pos=%i\n"
-          "    len=%i\n"
-          "    out=\"%s\"\n"
-          "    err=%i\n"
-          "  }\n"
-          "  scanner=%p\n",
-          msg, param->yyscanner, param->ctx, param->in, param->pos,
-          param->len, param->out, param->err, scanner);
-}
-
-%}
-
-%token TOK_Parent TOK_Self TOK_DblFSlash TOK_FSlash TOK_Axis TOK_Colon
-%token TOK_OpAnd TOK_OpOr TOK_OpNot
-%token TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
-%token TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
-%token TOK_OpAll TOK_OpAny
-%token TOK_NCName TOK_Literal TOK_Number
-
-%start XSLPattern
-
-%define api.prefix {xslpattern_}
-%define api.pure
-%parse-param {parser_param* p}
-%parse-param {void* scanner}
-%lex-param {yyscan_t* scanner}
-
-%left TOK_OpAnd TOK_OpOr
-%left TOK_OpEq TOK_OpIEq TOK_OpNEq TOK_OpINEq
-%left TOK_OpLt TOK_OpILt TOK_OpGt TOK_OpIGt TOK_OpLEq TOK_OpILEq TOK_OpGEq TOK_OpIGEq
-
-%expect 14
-
-%%
-
-    XSLPattern              : Expr
-                            {
-                                p->out = $1;
-                                (void)xslpattern_nerrs; /* avoid unused variable warning */
-                            }
-    ;
-
-/* Mostly verbatim from the w3c XML Namespaces standard.
- * <http://www.w3.org/TR/REC-xml-names/> */
-
-    /* [4] Qualified Names */
-    QName                   : PrefixedName
-                            | UnprefixedName
-    ;
-    PrefixedName            : TOK_NCName TOK_Colon TOK_NCName
-                            {
-                                TRACE("Got PrefixedName: \"%s:%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(":"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-    ;
-    UnprefixedName          : TOK_NCName
-                            {
-                                TRACE("Got UnprefixedName: \"%s\"\n", $1);
-                                $$=$1;
-                            }
-    ;
-
-/* Based on the w3c XPath standard, adapted where needed.
- * <http://www.w3.org/TR/xpath/> */
-
-    /* [2] Location Paths */
-    LocationPath            : RelativeLocationPath
-                            | AbsoluteLocationPath
-    ;
-    AbsoluteLocationPath    : TOK_FSlash RelativeLocationPath
-                            {
-                                TRACE("Got AbsoluteLocationPath: \"/%s\"\n", $2);
-                                $$=xmlStrdup(U("/"));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-                            | TOK_FSlash
-                            {
-                                TRACE("Got AbsoluteLocationPath: \"/\"\n");
-                                $$=xmlStrdup(U("/"));
-                            }
-                            | AbbreviatedAbsoluteLocationPath
-    ;
-    RelativeLocationPath    : Step
-                            | RelativeLocationPath TOK_FSlash Step
-                            {
-                                TRACE("Got RelativeLocationPath: \"%s/%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("/"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | AbbreviatedRelativeLocationPath
-    ;
-    /* [2.1] Location Steps */
-    Step                    : AxisSpecifier NodeTest Predicates
-                            {
-                                TRACE("Got Step: \"%s%s%s\"\n", $1, $2, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | NodeTest Predicates
-                            {
-                                TRACE("Got Step: \"%s%s\"\n", $1, $2);
-                                $$=$1;
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-                            | AxisSpecifier NodeTest
-                            {
-                                TRACE("Got Step: \"%s%s\"\n", $1, $2);
-                                $$=$1;
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-                            | NodeTest
-                            | Attribute
-                            | AbbreviatedStep
-    ;
-    AxisSpecifier           : TOK_NCName TOK_Axis
-                            {
-                                TRACE("Got AxisSpecifier: \"%s::\"\n", $1);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("::"));
-                            }
-    ;
-    Attribute               : '@' QName
-                            {
-                                TRACE("Got Attribute: \"@%s\"\n", $2);
-                                $$=xmlStrdup(U("@"));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-                            | '@' '*'
-                            {
-                                TRACE("Got All attributes pattern: \"@*\"\n");
-                                $$=xmlStrdup(U("@*"));
-                            }
-    ;
-
-    /* [2.3] Node Tests */
-    NodeTest                : NameTest
-                            | FunctionCall
-    ;
-    NameTest                : '*'
-                            {
-                                TRACE("Got NameTest: \"*\"\n");
-                                $$=xmlStrdup(U("*"));
-                            }
-                            | TOK_NCName TOK_Colon '*'
-                            {
-                                TRACE("Got NameTest: \"%s:*\"\n", $1);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(":*"));
-                            }
-                            | TOK_NCName TOK_Colon TOK_NCName
-                            { /* PrefixedName */
-                                xmlChar const* registeredNsURI = xmlXPathNsLookup(p->ctx, $1);
-                                TRACE("Got PrefixedName: \"%s:%s\"\n", $1, $3);
-
-                                if (registeredNsURI)
-                                    $$=xmlStrdup(U(""));
-                                else
-                                    $$=xmlStrdup(NameTest_mod_pre);
-
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(":"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-
-                                if (!registeredNsURI)
-                                    $$=xmlStrcat($$,NameTest_mod_post);
-                            }
-                            | UnprefixedName
-                            {
-                                $$=xmlStrdup(NameTest_mod_pre);
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,NameTest_mod_post);
-                            }
-    /* [2.4] Predicates */
-    Predicates              : Predicates Predicate
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-                            | Predicate
-    ;
-    Predicate               : '[' PredicateExpr ']'
-                            {
-                                TRACE("Got Predicate: \"[%s]\"\n", $2);
-                                $$=xmlStrdup(U("["));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,U("]"));
-                            }
-    ;
-    PredicateExpr           : TOK_Number
-                            {
-                                $$=xmlStrdup(U("index()="));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                            }
-                            | BoolExpr
-                            | Attribute
-                            | TOK_NCName
-    ;
-    /* [2.5] Abbreviated Syntax */
-    AbbreviatedAbsoluteLocationPath : TOK_DblFSlash RelativeLocationPath
-                            {
-                                TRACE("Got AbbreviatedAbsoluteLocationPath: \"//%s\"\n", $2);
-                                $$=xmlStrdup(U("//"));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-    ;
-    AbbreviatedRelativeLocationPath : RelativeLocationPath TOK_DblFSlash Step
-                            {
-                                TRACE("Got AbbreviatedRelativeLocationPath: \"%s//%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("//"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-    ;
-    AbbreviatedStep         : TOK_Parent
-                            {
-                                TRACE("Got AbbreviatedStep: \"..\"\n");
-                                $$=xmlStrdup(U(".."));
-                            }
-                            | TOK_Self
-                            {
-                                TRACE("Got AbbreviatedStep: \".\"\n");
-                                $$=xmlStrdup(U("."));
-                            }
-    ;
-
-    /* [3] Expressions */
-    /* [3.1] Basics */
-    Expr                    : OrExpr
-    ;
-    BoolExpr                : FunctionCall
-                            | BoolUnaryExpr
-                            | BoolRelationalExpr
-                            | BoolEqualityExpr
-                            | BoolAndExpr
-                            | BoolOrExpr
-    ;
-    PrimaryExpr             : '(' Expr ')'
-                            {
-                                TRACE("Got PrimaryExpr: \"(%s)\"\n", $1);
-                                $$=xmlStrdup(U("("));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr '!' FunctionCall
-                            {
-                                TRACE("Got PrimaryExpr: \"%s!%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("/"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | TOK_Literal
-                            | TOK_Number
-    ;
-    /* [3.2] Function Calls */
-    FunctionCall            : QName '(' Arguments ')'
-                            {
-                                TRACE("Got FunctionCall: \"%s(%s)\"\n", $1, $3);
-                                if (xmlStrEqual($1,U("ancestor")))
-                                {
-                                    $$=$1;
-                                    $$=xmlStrcat($$,U("::"));
-                                    $$=xmlStrcat($$,$3);
-                                    xmlFree($3);
-                                }
-                                else if (xmlStrEqual($1,U("attribute")))
-                                {
-                                    if (is_literal($3))
-                                    {
-                                        $$=xmlStrdup(U("@*[name()="));
-                                        xmlFree($1);
-                                        $$=xmlStrcat($$,$3);
-                                        xmlFree($3);
-                                        $$=xmlStrcat($$,U("]"));
-                                    }
-                                    else
-                                    {
-                                        /* XML_XPATH_INVALID_TYPE */
-                                        $$=xmlStrdup(U("error(1211, 'Error: attribute("));
-                                        xmlFree($1);
-                                        $$=xmlStrcat($$,$3);
-                                        xmlFree($3);
-                                        $$=xmlStrcat($$,U("): invalid argument')"));
-                                    }
-                                }
-                                else if (xmlStrEqual($1,U("element")))
-                                {
-                                    if (is_literal($3))
-                                    {
-                                        $$=xmlStrdup(U("node()[nodeType()=1][name()="));
-                                        xmlFree($1);
-                                        $$=xmlStrcat($$,$3);
-                                        xmlFree($3);
-                                        $$=xmlStrcat($$,U("]"));
-                                    }
-                                    else
-                                    {
-                                        /* XML_XPATH_INVALID_TYPE */
-                                        $$=xmlStrdup(U("error(1211, 'Error: element("));
-                                        xmlFree($1);
-                                        $$=xmlStrcat($$,$3);
-                                        xmlFree($3);
-                                        $$=xmlStrcat($$,U("): invalid argument')"));
-                                    }
-                                }
-                                else
-                                {
-                                    $$=$1;
-                                    $$=xmlStrcat($$,U("("));
-                                    $$=xmlStrcat($$,$3);
-                                    xmlFree($3);
-                                    $$=xmlStrcat($$,U(")"));
-                                }
-                            }
-                            | QName '(' ')'
-                            {
-                                TRACE("Got FunctionCall: \"%s()\"\n", $1);
-                                /* comment() & node() work the same in XPath */
-                                if (xmlStrEqual($1,U("attribute")))
-                                {
-                                    $$=xmlStrdup(U("@*"));
-                                    xmlFree($1);
-                                }
-                                else if (xmlStrEqual($1,U("element")))
-                                {
-                                    $$=xmlStrdup(U("node()[nodeType()=1]"));
-                                    xmlFree($1);
-                                }
-                                else if (xmlStrEqual($1,U("pi")))
-                                {
-                                    $$=xmlStrdup(U("processing-instruction()"));
-                                    xmlFree($1);
-                                }
-                                else if (xmlStrEqual($1,U("textnode")))
-                                {
-                                    $$=xmlStrdup(U("text()"));
-                                    xmlFree($1);
-                                }
-                                else
-                                {
-                                    $$=$1;
-                                    $$=xmlStrcat($$,U("()"));
-                                }
-                            }
-    ;
-    Arguments               : Argument ',' Arguments
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | Argument
-    ;
-    Argument                : Expr
-    ;
-    /* [3.3] Node-sets */
-    UnionExpr               : PathExpr
-                            | UnionExpr '|' PathExpr
-                            {
-                                TRACE("Got UnionExpr: \"%s|%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("|"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-    ;
-    PathExpr                : LocationPath
-                            | FilterExpr TOK_FSlash RelativeLocationPath
-                            {
-                                TRACE("Got PathExpr: \"%s/%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("/"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | FilterExpr TOK_DblFSlash RelativeLocationPath
-                            {
-                                TRACE("Got PathExpr: \"%s//%s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("//"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | FilterExpr
-    ;
-    FilterExpr              : PrimaryExpr
-                            | FilterExpr Predicate
-                            {
-                                TRACE("Got FilterExpr: \"%s%s\"\n", $1, $2);
-                                $$=$1;
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                            }
-    ;
-    /* [3.4] Booleans */
-    OrExpr                  : AndExpr
-                            | BoolOrExpr
-    ;
-    BoolOrExpr              : OrExpr TOK_OpOr AndExpr
-                            {
-                                TRACE("Got OrExpr: \"%s $or$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(" or "));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-    ;
-    AndExpr                 : EqualityExpr
-                            | BoolAndExpr
-    ;
-    BoolAndExpr             : AndExpr TOK_OpAnd EqualityExpr
-                            {
-                                TRACE("Got AndExpr: \"%s $and$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(" and "));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-    ;
-    EqualityExpr            : RelationalExpr
-                            | BoolEqualityExpr
-    ;
-    BoolEqualityExpr        : EqualityExpr TOK_OpEq RelationalExpr
-                            {
-                                TRACE("Got EqualityExpr: \"%s $eq$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | EqualityExpr TOK_OpIEq RelationalExpr
-                            {
-                                TRACE("Got EqualityExpr: \"%s $ieq$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_IEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | EqualityExpr TOK_OpNEq RelationalExpr
-                            {
-                                TRACE("Got EqualityExpr: \"%s $ne$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("!="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | EqualityExpr TOK_OpINEq RelationalExpr
-                            {
-                                TRACE("Got EqualityExpr: \"%s $ine$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_INEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-    ;
-    RelationalExpr          : UnaryExpr
-                            | BoolRelationalExpr
-    ;
-    BoolRelationalExpr      : RelationalExpr TOK_OpLt UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $lt$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("<"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | RelationalExpr TOK_OpILt UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $ilt$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_ILt("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | RelationalExpr TOK_OpGt UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $gt$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(">"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | RelationalExpr TOK_OpIGt UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $igt$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_IGt("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | RelationalExpr TOK_OpLEq UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $le$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U("<="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | RelationalExpr TOK_OpILEq UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $ile$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_ILEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | RelationalExpr TOK_OpGEq UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $ge$ %s\"\n", $1, $3);
-                                $$=$1;
-                                $$=xmlStrcat($$,U(">="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | RelationalExpr TOK_OpIGEq UnaryExpr
-                            {
-                                TRACE("Got RelationalExpr: \"%s $ige$ %s\"\n", $1, $3);
-                                $$=xmlStrdup(U("OP_IGEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-    ;
-
-    /* [3.5] Numbers */
-    UnaryExpr               : UnionExpr
-                            | BoolUnaryExpr
-    ;
-    BoolUnaryExpr           : TOK_OpNot UnaryExpr
-                            {
-                                TRACE("Got UnaryExpr: \"$not$ %s\"\n", $2);
-                                $$=xmlStrdup(U(" not("));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | TOK_OpAny Expr
-                            {
-                                TRACE("Got UnaryExpr: \"$any$ %s\"\n", $2);
-                                $$=xmlStrdup(U("boolean("));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | TOK_OpAll AllExpr
-                            {
-                                TRACE("Got UnaryExpr: \"$all$ %s\"\n", $2);
-                                $$=xmlStrdup(U("not("));
-                                $$=xmlStrcat($$,$2);
-                                xmlFree($2);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | TOK_OpAll
-                            {
-                                FIXME("Unrecognized $all$ expression - ignoring\n");
-                                $$=xmlStrdup(U(""));
-                            }
-    ;
-    AllExpr                 : PathExpr TOK_OpEq PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U("!="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpNEq PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U("="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpLt PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U(">="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpLEq PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U(">"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpGt PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U("<="));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpGEq PathExpr
-                            {
-                                $$=$1;
-                                $$=xmlStrcat($$,U("<"));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                            }
-                            | PathExpr TOK_OpIEq PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_INEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr TOK_OpINEq PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_IEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr TOK_OpILt PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_IGEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr TOK_OpILEq PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_IGt("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr TOK_OpIGt PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_ILEq("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-                            | PathExpr TOK_OpIGEq PathExpr
-                            {
-                                $$=xmlStrdup(U("OP_ILt("));
-                                $$=xmlStrcat($$,$1);
-                                xmlFree($1);
-                                $$=xmlStrcat($$,U(","));
-                                $$=xmlStrcat($$,$3);
-                                xmlFree($3);
-                                $$=xmlStrcat($$,U(")"));
-                            }
-    ;
-
-%%
diff --git a/dlls/msxml6/tests/httpreq.c b/dlls/msxml6/tests/httpreq.c
index ad019123b669..1a6dfec44d42 100644
--- a/dlls/msxml6/tests/httpreq.c
+++ b/dlls/msxml6/tests/httpreq.c
@@ -84,6 +84,9 @@ static BOOL g_enablecallchecks;
         expect_ ## func = called_ ## func = FALSE; \
     }while(0)
 
+#define CLEAR_CALLED(func) \
+    expect_ ## func = called_ ## func = 0
+
 /* object site */
 DEFINE_EXPECT(site_qi_IServiceProvider);
 DEFINE_EXPECT(site_qi_IXMLDOMDocument);
@@ -95,10 +98,6 @@ DEFINE_EXPECT(sp_queryservice_SID_secmgr_htmldoc2);
 DEFINE_EXPECT(sp_queryservice_SID_secmgr_xmldomdoc);
 DEFINE_EXPECT(sp_queryservice_SID_secmgr_secmgr);
 
-DEFINE_EXPECT(htmldoc2_get_all);
-DEFINE_EXPECT(htmldoc2_get_url);
-DEFINE_EXPECT(collection_get_length);
-
 static int g_unexpectedcall, g_expectedcall;
 
 static int strcmp_wa(const WCHAR *strw, const char *stra)
@@ -138,108 +137,6 @@ static void free_bstrs(void)
 }
 
 
-/* test IHTMLElementCollection */
-static HRESULT WINAPI htmlecoll_QueryInterface(IHTMLElementCollection *iface, REFIID riid, void **ppvObject)
-{
-    ok(0, "unexpected call\n");
-    *ppvObject = NULL;
-    return E_NOINTERFACE;
-}
-
-static ULONG WINAPI htmlecoll_AddRef(IHTMLElementCollection *iface)
-{
-    return 2;
-}
-
-static ULONG WINAPI htmlecoll_Release(IHTMLElementCollection *iface)
-{
-    return 1;
-}
-
-static HRESULT WINAPI htmlecoll_GetTypeInfoCount(IHTMLElementCollection *iface, UINT *pctinfo)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_GetTypeInfo(IHTMLElementCollection *iface, UINT iTInfo,
-                                                LCID lcid, ITypeInfo **ppTInfo)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_GetIDsOfNames(IHTMLElementCollection *iface, REFIID riid,
-                                                LPOLESTR *rgszNames, UINT cNames,
-                                                LCID lcid, DISPID *rgDispId)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_Invoke(IHTMLElementCollection *iface, DISPID dispIdMember,
-                            REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
-                            VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_toString(IHTMLElementCollection *iface, BSTR *String)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_put_length(IHTMLElementCollection *iface, LONG v)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_get_length(IHTMLElementCollection *iface, LONG *v)
-{
-    CHECK_EXPECT2(collection_get_length);
-    *v = 0;
-    return S_OK;
-}
-
-static HRESULT WINAPI htmlecoll_get__newEnum(IHTMLElementCollection *iface, IUnknown **p)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_item(IHTMLElementCollection *iface, VARIANT name, VARIANT index, IDispatch **pdisp)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI htmlecoll_tags(IHTMLElementCollection *iface, VARIANT tagName, IDispatch **pdisp)
-{
-    ok(0, "unexpected call\n");
-    return E_NOTIMPL;
-}
-
-static const IHTMLElementCollectionVtbl TestHTMLECollectionVtbl = {
-    htmlecoll_QueryInterface,
-    htmlecoll_AddRef,
-    htmlecoll_Release,
-    htmlecoll_GetTypeInfoCount,
-    htmlecoll_GetTypeInfo,
-    htmlecoll_GetIDsOfNames,
-    htmlecoll_Invoke,
-    htmlecoll_toString,
-    htmlecoll_put_length,
-    htmlecoll_get_length,
-    htmlecoll_get__newEnum,
-    htmlecoll_item,
-    htmlecoll_tags
-};
-
-static IHTMLElementCollection htmlecoll = { &TestHTMLECollectionVtbl };
-
 /* test IHTMLDocument2 */
 static HRESULT WINAPI htmldoc2_QueryInterface(IHTMLDocument2 *iface, REFIID riid, void **ppvObject)
 {
@@ -294,9 +191,8 @@ static HRESULT WINAPI htmldoc2_get_Script(IHTMLDocument2 *iface, IDispatch **p)
 
 static HRESULT WINAPI htmldoc2_get_all(IHTMLDocument2 *iface, IHTMLElementCollection **p)
 {
-    CHECK_EXPECT2(htmldoc2_get_all);
-    *p = &htmlecoll;
-    return S_OK;
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
 }
 
 static HRESULT WINAPI htmldoc2_get_body(IHTMLDocument2 *iface, IHTMLElement **p)
@@ -487,7 +383,7 @@ static HRESULT WINAPI htmldoc2_put_URL(IHTMLDocument2 *iface, BSTR v)
 
 static HRESULT WINAPI htmldoc2_get_URL(IHTMLDocument2 *iface, BSTR *p)
 {
-    CHECK_EXPECT2(htmldoc2_get_url);
+    ok(0, "unexpected call\n");
     *p = SysAllocString(L"http://test.winehq.org/");
     return S_OK;
 }
@@ -1356,17 +1252,45 @@ static void set_safety_opt(IUnknown *unk, DWORD mask, DWORD opts)
     IObjectSafety_Release(obj_safety);
 }
 
-static void set_xhr_site(IXMLHTTPRequest *xhr)
+static void set_xhr_site(IXMLHTTPRequest *xhr, BOOL site_domdoc)
 {
     IObjectWithSite *obj_site;
     HRESULT hr;
 
-    hr = IXMLHTTPRequest_QueryInterface(xhr, &IID_IObjectWithSite, (void **)&obj_site);
+    hr = IXMLHTTPRequest_QueryInterface(xhr, &IID_IObjectWithSite, (void**)&obj_site);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
+    g_enablecallchecks = TRUE;
+
+    SET_EXPECT(site_qi_IServiceProvider);
+    SET_EXPECT(sp_queryservice_SID_SBindHost);
+    SET_EXPECT(sp_queryservice_SID_SContainerDispatch_htmldoc2);
+    SET_EXPECT(sp_queryservice_SID_secmgr_htmldoc2);
+    if (site_domdoc) SET_EXPECT(sp_queryservice_SID_secmgr_xmldomdoc);
+    SET_EXPECT(sp_queryservice_SID_secmgr_secmgr);
+
+    SET_EXPECT(site_qi_IXMLDOMDocument);
+    if (site_domdoc) SET_EXPECT(site_qi_IOleClientSite);
+
     hr = IObjectWithSite_SetSite(obj_site, &testsite);
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
+    CHECK_CALLED(site_qi_IServiceProvider);
+    todo_wine
+    CHECK_CALLED(sp_queryservice_SID_SBindHost);
+    CHECK_CALLED(sp_queryservice_SID_SContainerDispatch_htmldoc2);
+    CHECK_CALLED(sp_queryservice_SID_secmgr_htmldoc2);
+    if (site_domdoc) todo_wine CHECK_CALLED(sp_queryservice_SID_secmgr_xmldomdoc);
+    /* this one isn't very reliable */
+    CLEAR_CALLED(sp_queryservice_SID_secmgr_secmgr);
+
+todo_wine {
+    CHECK_CALLED(site_qi_IXMLDOMDocument);
+    if (site_domdoc) CHECK_CALLED(site_qi_IOleClientSite);
+}
+
+    g_enablecallchecks = FALSE;
+
     IObjectWithSite_Release(obj_site);
 }
 
@@ -1694,7 +1618,7 @@ static void test_XMLHTTP60(void)
     ok(obj_site == obj_site2, "got new instance\n");
     IObjectWithSite_Release(obj_site2);
 
-    set_xhr_site(xhr);
+    set_xhr_site(xhr, FALSE);
 
     /* try to set site another time */
     hr = IObjectWithSite_SetSite(obj_site, &testsite);
@@ -1801,7 +1725,7 @@ static void test_safe_httpreq(void)
     xhr = create_xhr();
 
     set_safety_opt((IUnknown*)xhr, INTERFACESAFE_FOR_UNTRUSTED_DATA, -1);
-    set_xhr_site(xhr);
+    set_xhr_site(xhr, TRUE);
 
     /* different scheme */
     test_open(xhr, "GET", "https://test.winehq.org/tests/hello.html", E_ACCESSDENIED);
diff --git a/dlls/netapi32/netapi32.c b/dlls/netapi32/netapi32.c
index 9737f2ae3703..f58647b34c3f 100644
--- a/dlls/netapi32/netapi32.c
+++ b/dlls/netapi32/netapi32.c
@@ -2182,97 +2182,6 @@ DWORD WINAPI DsGetSiteNameA(LPCSTR ComputerName, LPSTR *SiteName)
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
-/************************************************************
- *  DsRoleFreeMemory (NETAPI32.@)
- *
- * PARAMS
- *  Buffer [I] Pointer to the to-be-freed buffer.
- *
- * RETURNS
- *  Nothing
- */
-VOID WINAPI DsRoleFreeMemory(PVOID Buffer)
-{
-    TRACE("(%p)\n", Buffer);
-    HeapFree(GetProcessHeap(), 0, Buffer);
-}
-
-/************************************************************
- *  DsRoleGetPrimaryDomainInformation  (NETAPI32.@)
- *
- * PARAMS
- *  lpServer  [I] Pointer to UNICODE string with ComputerName
- *  InfoLevel [I] Type of data to retrieve
- *  Buffer    [O] Pointer to to the requested data
- *
- * RETURNS
- *
- * NOTES
- *  When lpServer is NULL, use the local computer
- */
-DWORD WINAPI DsRoleGetPrimaryDomainInformation(
-    LPCWSTR lpServer, DSROLE_PRIMARY_DOMAIN_INFO_LEVEL InfoLevel,
-    PBYTE* Buffer)
-{
-    DWORD ret;
-
-    FIXME("(%p, %d, %p) stub\n", lpServer, InfoLevel, Buffer);
-
-    /* Check some input parameters */
-
-    if (!Buffer) return ERROR_INVALID_PARAMETER;
-    if ((InfoLevel < DsRolePrimaryDomainInfoBasic) || (InfoLevel > DsRoleOperationState)) return ERROR_INVALID_PARAMETER;
-
-    *Buffer = NULL;
-    switch (InfoLevel)
-    {
-        case DsRolePrimaryDomainInfoBasic:
-        {
-            LSA_OBJECT_ATTRIBUTES ObjectAttributes;
-            LSA_HANDLE PolicyHandle;
-            PPOLICY_ACCOUNT_DOMAIN_INFO DomainInfo;
-            NTSTATUS NtStatus;
-            int logon_domain_sz;
-            DWORD size;
-            PDSROLE_PRIMARY_DOMAIN_INFO_BASIC basic;
-
-            ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
-            NtStatus = LsaOpenPolicy(NULL, &ObjectAttributes,
-             POLICY_VIEW_LOCAL_INFORMATION, &PolicyHandle);
-            if (NtStatus != STATUS_SUCCESS)
-            {
-                TRACE("LsaOpenPolicyFailed with NT status %lx\n",
-                    LsaNtStatusToWinError(NtStatus));
-                return ERROR_OUTOFMEMORY;
-            }
-            LsaQueryInformationPolicy(PolicyHandle,
-             PolicyAccountDomainInformation, (PVOID*)&DomainInfo);
-            logon_domain_sz = lstrlenW(DomainInfo->DomainName.Buffer) + 1;
-            LsaClose(PolicyHandle);
-
-            size = sizeof(DSROLE_PRIMARY_DOMAIN_INFO_BASIC) +
-             logon_domain_sz * sizeof(WCHAR);
-            basic = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
-            if (basic)
-            {
-                basic->MachineRole = DsRole_RoleStandaloneWorkstation;
-                basic->DomainNameFlat = (LPWSTR)((LPBYTE)basic +
-                 sizeof(DSROLE_PRIMARY_DOMAIN_INFO_BASIC));
-                lstrcpyW(basic->DomainNameFlat, DomainInfo->DomainName.Buffer);
-                ret = ERROR_SUCCESS;
-            }
-            else
-                ret = ERROR_OUTOFMEMORY;
-            *Buffer = (PBYTE)basic;
-            LsaFreeMemory(DomainInfo);
-        }
-        break;
-    default:
-        ret = ERROR_CALL_NOT_IMPLEMENTED;
-    }
-    return ret;
-}
-
 DWORD WINAPI DsGetDcOpenA(LPCSTR domain, ULONG flags, LPCSTR site,
     GUID *domain_guid, LPCSTR forest, ULONG dc_flags, PHANDLE context)
 {
diff --git a/dlls/netapi32/netapi32.spec b/dlls/netapi32/netapi32.spec
index 4906bfade6d4..14cf6a3a5f87 100644
--- a/dlls/netapi32/netapi32.spec
+++ b/dlls/netapi32/netapi32.spec
@@ -16,8 +16,8 @@
 @ stdcall DsGetSiteNameA(str ptr)
 @ stdcall DsGetSiteNameW(wstr ptr)
 @ stub DsMergeForestTrustInformationW
-@ stdcall DsRoleFreeMemory(ptr)
-@ stdcall DsRoleGetPrimaryDomainInformation(wstr long ptr)
+@ stdcall DsRoleFreeMemory(ptr) dsrole.DsRoleFreeMemory
+@ stdcall DsRoleGetPrimaryDomainInformation(wstr long ptr) dsrole.DsRoleGetPrimaryDomainInformation
 @ stub DsValidateSubnetName
 @ stub I_BrowserDebugCall
 @ stub I_BrowserDebugTrace
diff --git a/dlls/nsiproxy.sys/Makefile.in b/dlls/nsiproxy.sys/Makefile.in
index 40ea0701a461..6b5fbe7aa6dd 100644
--- a/dlls/nsiproxy.sys/Makefile.in
+++ b/dlls/nsiproxy.sys/Makefile.in
@@ -1,7 +1,7 @@
 MODULE    = nsiproxy.sys
 UNIXLIB   = nsiproxy.so
 IMPORTS   = ntoskrnl
-UNIX_LIBS = $(PROCSTAT_LIBS)
+UNIX_LIBS = $(PROCSTAT_LIBS) $(PTHREAD_LIBS)
 
 EXTRADLLFLAGS = -Wl,--subsystem,native
 
diff --git a/dlls/nsiproxy.sys/device.c b/dlls/nsiproxy.sys/device.c
index 4595bf8020cd..b7180d2cb943 100644
--- a/dlls/nsiproxy.sys/device.c
+++ b/dlls/nsiproxy.sys/device.c
@@ -19,6 +19,7 @@
  */
 
 #include <stdarg.h>
+#include <assert.h>
 
 #include "ntstatus.h"
 #include "windef.h"
@@ -61,9 +62,7 @@ static NTSTATUS nsiproxy_call( unsigned int code, void *args )
 
 enum unix_calls
 {
-    icmp_cancel_listen,
-    icmp_close,
-    icmp_listen,
+    icmp_get_reply,
     icmp_send_echo,
     nsi_enumerate_all_ex,
     nsi_get_all_parameters_ex,
@@ -184,35 +183,41 @@ static NTSTATUS nsiproxy_get_parameter( IRP *irp )
     return status;
 }
 
-static inline icmp_handle irp_get_icmp_handle( IRP *irp )
+struct icmp_data
 {
-    return PtrToUlong( irp->Tail.Overlay.DriverContext[0] );
+    icmp_handle handle;
+    HANDLE completion_event;
+    HANDLE wait_object;
+};
+
+static void free_icmp_data( struct icmp_data *data )
+{
+    UnregisterWait( data->wait_object );
+    CloseHandle( data->completion_event );
+    free( data );
+}
+
+static struct icmp_data *irp_get_icmp_data( IRP *irp )
+{
+    return irp->Tail.Overlay.DriverContext[0];
 }
 
-static inline icmp_handle irp_set_icmp_handle( IRP *irp, icmp_handle handle )
+static struct icmp_data *irp_set_icmp_data( IRP *irp, struct icmp_data *data )
 {
-    return PtrToUlong( InterlockedExchangePointer( irp->Tail.Overlay.DriverContext,
-                                                   ULongToPtr( handle ) ) );
+    return InterlockedExchangePointer( irp->Tail.Overlay.DriverContext, data );
 }
 
 DECLARE_CRITICAL_SECTION( icmp_echo_completion_cs );
 
 static void WINAPI icmp_echo_cancel( DEVICE_OBJECT *device, IRP *irp )
 {
-    struct icmp_cancel_listen_params params;
+    struct icmp_data *data;
 
     TRACE( "device %p, irp %p.\n", device, irp );
 
     IoReleaseCancelSpinLock( irp->CancelIrql );
     EnterCriticalSection( &icmp_echo_completion_cs );
-
-    /* If the handle is not set, either the irp is still
-       in the request queue, in which case the request thread will
-       cancel it, or the irp has already finished.  If the handle
-       does exist then notify the listen thread.  In all cases the irp
-       will be completed elsewhere. */
-    params.handle = irp_get_icmp_handle( irp );
-    if (params.handle) nsiproxy_call( icmp_cancel_listen, &params );
+    if ((data = irp_get_icmp_data( irp ))) SetEvent( data->completion_event );
     LeaveCriticalSection( &icmp_echo_completion_cs );
 }
 
@@ -225,48 +230,56 @@ static int icmp_echo_reply_struct_len( ULONG family, ULONG bits )
     return 0;
 }
 
-static DWORD WINAPI listen_thread_proc( void *arg )
+static void CALLBACK icmp_wait_complete( void *arg, BOOLEAN timed_out )
 {
     IRP *irp = arg;
     IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
     struct nsiproxy_icmp_echo *in = irp->AssociatedIrp.SystemBuffer;
-    struct icmp_close_params close_params;
-    struct icmp_listen_params params;
+    struct icmp_get_reply_params params;
+    struct icmp_data *data;
     NTSTATUS status;
 
-    TRACE( "\n" );
+    TRACE( "irp %p, timed_out %d.\n", irp, timed_out );
 
+    EnterCriticalSection( &icmp_echo_completion_cs );
+    data = irp_set_icmp_data( irp, NULL );
+    assert( data );
     params.user_reply_ptr = in->user_reply_ptr;
-    params.handle = irp_get_icmp_handle( irp );
-    params.timeout = in->timeout;
+    params.handle = data->handle;
     params.bits = in->bits;
     params.reply = irp->AssociatedIrp.SystemBuffer;
     params.reply_len = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
 
-    status = nsiproxy_call( icmp_listen, &params );
-    TRACE( "icmp_listen rets %08lx\n", status );
-
-    EnterCriticalSection( &icmp_echo_completion_cs );
-    close_params.handle = irp_set_icmp_handle( irp, 0 );
-    nsiproxy_call( icmp_close, &close_params );
+    status = nsiproxy_call( icmp_get_reply, &params );
 
-    irp->IoStatus.Status = status;
-    if (status == STATUS_SUCCESS)
-        irp->IoStatus.Information = params.reply_len;
+    irp->IoStatus.Information = 0;
+    if (irp->Cancel)
+    {
+        TRACE( "irp %p cancelled.\n", irp );
+        irp->IoStatus.Status = STATUS_CANCELLED;
+    }
     else
-        irp->IoStatus.Information = 0;
+    {
+        irp->IoStatus.Status = status;
+        if (status == STATUS_SUCCESS)
+            irp->IoStatus.Information = params.reply_len;
+    }
     LeaveCriticalSection( &icmp_echo_completion_cs );
     IoCompleteRequest( irp, IO_NO_INCREMENT );
-    return 0;
+    free_icmp_data( data );
 }
 
 static NTSTATUS handle_send_echo( IRP *irp )
 {
     struct nsiproxy_icmp_echo *in = (struct nsiproxy_icmp_echo *)irp->AssociatedIrp.SystemBuffer;
     struct icmp_send_echo_params params;
-    icmp_handle handle;
+    struct icmp_data *data;
     NTSTATUS status;
 
+    data = calloc( 1, sizeof(*data) );
+    data->completion_event = CreateEventW( NULL, TRUE, FALSE, NULL );
+    irp_set_icmp_data( irp, data );
+
     TRACE( "\n" );
     params.request = in->data + ((in->opt_size + 3) & ~3);
     params.request_size = in->req_size;
@@ -277,7 +290,8 @@ static NTSTATUS handle_send_echo( IRP *irp )
     params.tos = in->tos;
     params.src = &in->src;
     params.dst = &in->dst;
-    params.handle = &handle;
+    params.completion_event = data->completion_event;
+    params.handle = &data->handle;
 
     status = nsiproxy_call( icmp_send_echo, &params );
     TRACE( "icmp_send_echo status %#lx\n", status );
@@ -287,17 +301,24 @@ static NTSTATUS handle_send_echo( IRP *irp )
         irp->IoStatus.Status = status;
         if (status == STATUS_SUCCESS)
             irp->IoStatus.Information = params.reply_len;
+        free_icmp_data( data );
         return status;
     }
     IoSetCancelRoutine( irp, icmp_echo_cancel );
     if (irp->Cancel && IoSetCancelRoutine( irp, NULL ))
     {
         /* IRP was canceled before we set cancel routine */
+        icmp_wait_complete( irp, FALSE );
         return STATUS_CANCELLED;
     }
     IoMarkIrpPending( irp );
-    irp_set_icmp_handle( irp, handle );
-    RtlQueueWorkItem( listen_thread_proc, irp, WT_EXECUTELONGFUNCTION );
+    if (in->dst.si_family == AF_INET6 && !in->hop_limit)
+    {
+        /* This should fail at once but asynchronously. */
+        SetEvent( data->completion_event );
+    }
+    RegisterWaitForSingleObject( &data->wait_object, data->completion_event, icmp_wait_complete, irp, in->timeout,
+                                 WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD );
     return STATUS_PENDING;
 }
 
diff --git a/dlls/nsiproxy.sys/icmp_echo.c b/dlls/nsiproxy.sys/icmp_echo.c
index af1139e2d48d..22f63cf1427a 100644
--- a/dlls/nsiproxy.sys/icmp_echo.c
+++ b/dlls/nsiproxy.sys/icmp_echo.c
@@ -31,6 +31,7 @@
 #include <pthread.h>
 #include <poll.h>
 #include <sys/socket.h>
+#include <assert.h>
 
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -40,6 +41,11 @@
 #include <netinet/ip.h>
 #endif
 
+#ifdef HAVE_LINUX_ERRQUEUE_H
+#include <linux/errqueue.h>
+#define USE_ERRQUEUE
+#endif
+
 #include "ntstatus.h"
 #include "windef.h"
 #include "winbase.h"
@@ -52,6 +58,7 @@
 #include "ipexport.h"
 #include "ipmib.h"
 #include "wine/nsi.h"
+#include "wine/list.h"
 #include "wine/debug.h"
 
 #include "nsiproxy_private.h"
@@ -121,32 +128,59 @@ struct icmp_reply_ctx
     BYTE tos;
     BYTE flags;
     BYTE options_size;
-    void *options_data;
-    void *data;
+    unsigned int options_data_offset;
+    unsigned int data_offset;
+    BYTE packet[65536];
+    unsigned int packet_size;
+    uint16_t id, sequence;
 };
 
 struct family_ops;
-struct icmp_data
+
+struct icmp_socket
 {
-    LARGE_INTEGER send_time;
+    struct list entry;
+    struct list listen_entry;
+    struct list request_list;
+    LONG ref;
     int socket;
-    int cancel_pipe[2];
-    unsigned short id;
-    unsigned short seq;
     const struct family_ops *ops;
     struct sockaddr_storage src_storage;
-    struct sockaddr_storage dst_storage;
     int src_len;
-    int dst_len;
     int hop_limit;
+    BYTE ttl, tos;
     BOOL ping_socket;
+    unsigned short id;
+    BOOL polling;
+};
+
+struct icmp_data
+{
+    struct list entry;
+    LARGE_INTEGER send_time;
+    unsigned short seq;
+    struct sockaddr_storage dst_storage;
+    int dst_len;
+    struct icmp_socket *s;
+    struct icmp_reply_ctx reply_ctx;
+    HANDLE completion_event;
+    BOOL polling;
+    NTSTATUS status;
 };
 
+
+static pthread_mutex_t listen_lock = PTHREAD_MUTEX_INITIALIZER;
+struct list socket_list = LIST_INIT( socket_list );
+static int socket_list_update_pipe[2];
+static pthread_once_t init_once = PTHREAD_ONCE_INIT;
+
 #define MAX_HANDLES 256 /* Max number of simultaneous pings - could become dynamic if need be */
 static struct icmp_data *handle_table[MAX_HANDLES];
 static pthread_mutex_t handle_lock = PTHREAD_MUTEX_INITIALIZER;
 static struct icmp_data **next_free, **next_unused = handle_table;
 
+static void icmp_listen( void *args );
+
 static icmp_handle handle_alloc( struct icmp_data *data )
 {
     struct icmp_data **entry;
@@ -207,8 +241,8 @@ static void ipv4_init_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp_hd
     icmp_hdr->type = ICMP4_ECHO_REQUEST;
     icmp_hdr->code = 0;
     icmp_hdr->checksum = 0;
-    icmp_hdr->un.echo.id = data->id = getpid() & 0xffff; /* will be overwritten for linux ping socks */
-    icmp_hdr->un.echo.sequence = data->seq = InterlockedIncrement( &icmp_sequence ) & 0xffff;
+    icmp_hdr->un.echo.id = data->s->id = htons( 1 ); /* will be overwritten for linux ping socks */
+    icmp_hdr->un.echo.sequence = data->seq = htons( InterlockedIncrement( &icmp_sequence ) & 0xffff );
 }
 
 /* rfc 1071 checksum */
@@ -217,7 +251,7 @@ static unsigned short chksum( struct icmp_data *icmp_data, BYTE *data, unsigned
     unsigned int sum = 0, carry = 0;
     unsigned short check, s;
 
-    if (icmp_data->ping_socket) return 0;
+    if (icmp_data->s->ping_socket) return 0;
 
     while (count > 1)
     {
@@ -259,53 +293,40 @@ static int ipv4_set_reply_ip_status( IP_STATUS ip_status, unsigned int bits, voi
     }
 }
 
-static void ipv4_set_socket_opts( struct icmp_data *data, struct icmp_send_echo_params *params )
+static void ipv4_set_socket_opts( struct icmp_socket *s )
 {
     int val;
 
-    val = params->ttl;
-    if (val) setsockopt( data->socket, IPPROTO_IP, IP_TTL, &val, sizeof(val) );
-    val = params->tos;
-    if (val) setsockopt( data->socket, IPPROTO_IP, IP_TOS, &val, sizeof(val) );
+    val = s->ttl;
+    if (val) setsockopt( s->socket, IPPROTO_IP, IP_TTL, &val, sizeof(val) );
+    val = s->tos;
+    if (val) setsockopt( s->socket, IPPROTO_IP, IP_TOS, &val, sizeof(val) );
 }
 
 #ifdef __linux__
-static void ipv4_linux_ping_set_socket_opts( struct icmp_data *data, struct icmp_send_echo_params *params )
+static void ipv4_linux_ping_set_socket_opts( struct icmp_socket *s )
 {
     static const int val = 1;
 
-    ipv4_set_socket_opts( data, params );
+    ipv4_set_socket_opts( s );
 
-    setsockopt( data->socket, IPPROTO_IP, IP_RECVTTL, &val, sizeof(val) );
-    setsockopt( data->socket, IPPROTO_IP, IP_RECVTOS, &val, sizeof(val) );
+    setsockopt( s->socket, IPPROTO_IP, IP_RECVTTL, &val, sizeof(val) );
+    setsockopt( s->socket, IPPROTO_IP, IP_RECVTOS, &val, sizeof(val) );
+    setsockopt( s->socket, IPPROTO_IP, IP_RECVERR, &val, sizeof(val) );
 }
 #endif
 
-static int ipv4_reply_buffer_len( struct icmp_listen_params *params )
-{
-    int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
-    return sizeof(struct ip_hdr) + sizeof(struct icmp_hdr) + params->reply_len - struct_len;
-}
-
-#ifdef __linux__
-static int ipv4_linux_ping_reply_buffer_len( struct icmp_listen_params *params )
-{
-    int struct_len = (params->bits == 32) ? sizeof(struct icmp_echo_reply_32) : sizeof(struct icmp_echo_reply_64);
-    return sizeof(struct icmp_hdr) + params->reply_len - struct_len;
-}
-#endif
-
-static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int *recvd, int *ip_hdr_len,
                                struct icmp_reply_ctx *ctx )
 {
     struct ip_hdr *ip_hdr;
 
-    if (recvd < sizeof(*ip_hdr)) return FALSE;
+    if (*recvd < sizeof(*ip_hdr)) return FALSE;
     ip_hdr = msg->msg_iov[0].iov_base;
     if (ip_hdr->v_hl >> 4 != 4 || ip_hdr->protocol != IPPROTO_ICMP) return FALSE;
     *ip_hdr_len = (ip_hdr->v_hl & 0xf) << 2;
     if (*ip_hdr_len < sizeof(*ip_hdr)) return FALSE;
-    ctx->options_data = ip_hdr + 1;
+    ctx->options_data_offset = sizeof(*ip_hdr);
     ctx->ttl = ip_hdr->ttl;
     ctx->tos = ip_hdr->tos;
     ctx->flags = ip_hdr->frag_off >> 13;
@@ -315,13 +336,13 @@ static BOOL ipv4_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
 }
 
 #ifdef __linux__
-static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int *recvd, int *ip_hdr_len,
                                           struct icmp_reply_ctx *ctx )
 {
     struct cmsghdr *cmsg;
 
     *ip_hdr_len = 0;
-    ctx->options_data = NULL;
+    ctx->options_data_offset = 0;
     ctx->ttl = 0;
     ctx->tos = 0;
     ctx->flags = 0;
@@ -338,13 +359,32 @@ static BOOL ipv4_linux_ping_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip
         case IP_TOS:
             ctx->tos = *(BYTE *)CMSG_DATA( cmsg );
             break;
+#ifdef HAVE_LINUX_ERRQUEUE_H
+        case IP_RECVERR:
+        {
+            struct sock_extended_err *e;
+            struct icmp_hdr *icmp_h;
+
+            e = (struct sock_extended_err *)CMSG_DATA( cmsg );
+            icmp_h = msg->msg_iov[0].iov_base;
+            if (e->ee_origin != SO_EE_ORIGIN_ICMP) break;
+            if (*recvd + sizeof(*icmp_h) > ARRAY_SIZE(ctx->packet)) break;
+            memmove( ctx->packet + sizeof(*icmp_h), ctx->packet, *recvd );
+            *recvd += sizeof(*icmp_h);
+            memset( icmp_h, 0, sizeof(*icmp_h) );
+            icmp_h->type = e->ee_type;
+            icmp_h->code = e->ee_code;
+            TRACE( "got error packet type %d, code %d.\n", icmp_h->type, icmp_h->code );
+            break;
+        }
+#endif
         }
     }
     return TRUE;
 }
 #endif
 
-static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_size,
+static int ipv4_parse_icmp_hdr( struct icmp_socket *s, struct icmp_hdr *icmp, int icmp_size,
                                 struct icmp_reply_ctx *ctx )
 {
     static const IP_STATUS unreach_codes[] =
@@ -374,9 +414,8 @@ static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, i
     switch (icmp->type)
     {
     case ICMP4_ECHO_REPLY:
-        if ((!data->ping_socket && icmp->un.echo.id != data->id) ||
-            icmp->un.echo.sequence != data->seq) return -1;
-
+        ctx->id = icmp->un.echo.id;
+        ctx->sequence = icmp->un.echo.sequence;
         ctx->status = IP_SUCCESS;
         return icmp_size - sizeof(*icmp);
 
@@ -406,27 +445,32 @@ static int ipv4_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp, i
         return -1;
     }
 
-    if (data->ping_socket) return 0;
-
-    /* Check that the appended packet is really ours -
-     * all handled icmp replies have an 8-byte header
-     * followed by the original ip hdr. */
-    if (icmp_size < sizeof(*icmp) + sizeof(*orig_ip_hdr)) return -1;
-    orig_ip_hdr = (struct ip_hdr *)(icmp + 1);
-    if (orig_ip_hdr->v_hl >> 4 != 4 || orig_ip_hdr->protocol != IPPROTO_ICMP) return -1;
-    orig_ip_hdr_len = (orig_ip_hdr->v_hl & 0xf) << 2;
-    if (icmp_size < sizeof(*icmp) + orig_ip_hdr_len + sizeof(*orig_icmp_hdr)) return -1;
-    orig_icmp_hdr = (const struct icmp_hdr *)((const BYTE *)orig_ip_hdr + orig_ip_hdr_len);
+    icmp_size -= sizeof(*icmp);
+    if (s->ping_socket)
+    {
+        orig_ip_hdr_len = 0;
+        orig_icmp_hdr = icmp + 1;
+    }
+    else
+    {
+        /* All handled icmp replies have an 8-byte header followed by the original ip hdr. */
+        if (icmp_size < sizeof(*orig_ip_hdr)) return -1;
+        orig_ip_hdr = (struct ip_hdr *)(icmp + 1);
+        if (orig_ip_hdr->v_hl >> 4 != 4 || orig_ip_hdr->protocol != IPPROTO_ICMP) return -1;
+        orig_ip_hdr_len = (orig_ip_hdr->v_hl & 0xf) << 2;
+        orig_icmp_hdr = (const struct icmp_hdr *)((const BYTE *)orig_ip_hdr + orig_ip_hdr_len);
+    }
+    if (icmp_size < orig_ip_hdr_len + sizeof(*orig_icmp_hdr)) return -1;
     if (orig_icmp_hdr->type != ICMP4_ECHO_REQUEST ||
-        orig_icmp_hdr->code != 0 ||
-        (!data->ping_socket && orig_icmp_hdr->un.echo.id != data->id) ||
-        orig_icmp_hdr->un.echo.sequence != data->seq) return -1;
+        orig_icmp_hdr->code != 0) return -1;
 
+    ctx->id = orig_icmp_hdr->un.echo.id;
+    ctx->sequence = orig_icmp_hdr->un.echo.sequence;
     ctx->status = status;
     return 0;
 }
 
-static void ipv4_fill_reply( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx)
+static BOOL ipv4_fill_reply( struct icmp_get_reply_params *params, struct icmp_reply_ctx *ctx)
 {
     void *options_data;
     ULONG data_offset;
@@ -465,12 +509,17 @@ static void ipv4_fill_reply( struct icmp_listen_params *params, struct icmp_repl
         options_data = reply + 1;
     }
 
-    memcpy( options_data, ctx->options_data, ctx->options_size );
+    if (ctx->options_size && ((char *)options_data - (char *)params->reply) + ctx->options_size > params->reply_len)
+        return FALSE;
+    memcpy( options_data, ctx->packet + ctx->options_data_offset, ctx->options_size );
     if (ctx->options_size & 3)
         memset( (char *)options_data + ctx->options_size, 0, 4 - (ctx->options_size & 3) );
 
-    memcpy( (char *)params->reply + data_offset, ctx->data, ctx->data_size );
+    if (ctx->data_size && data_offset + ctx->data_size > params->reply_len)
+        return FALSE;
+    memcpy( (char *)params->reply + data_offset, ctx->packet + ctx->data_offset, ctx->data_size );
     params->reply_len = data_offset + ctx->data_size;
+    return TRUE;
 }
 
 struct family_ops
@@ -480,11 +529,10 @@ struct family_ops
     void (*init_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp_hdr );
     unsigned short (*chksum)( struct icmp_data *icmp_data, BYTE *data, unsigned int count );
     int (*set_reply_ip_status)( IP_STATUS ip_status, unsigned int bits, void *out );
-    void (*set_socket_opts)( struct icmp_data *data, struct icmp_send_echo_params *params );
-    int (*reply_buffer_len)( struct icmp_listen_params *params );
-    BOOL (*parse_ip_hdr)( struct msghdr *msg, int recvd, int *ip_hdr_len, struct icmp_reply_ctx *ctx );
-    int (*parse_icmp_hdr)( struct icmp_data *data, struct icmp_hdr *icmp, int icmp_len, struct icmp_reply_ctx *ctx );
-    void (*fill_reply)( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx );
+    void (*set_socket_opts)( struct icmp_socket *s );
+    BOOL (*parse_ip_hdr)( struct msghdr *msg, int *recvd, int *ip_hdr_len, struct icmp_reply_ctx *ctx );
+    int (*parse_icmp_hdr)( struct icmp_socket *s, struct icmp_hdr *icmp, int icmp_len, struct icmp_reply_ctx *ctx );
+    BOOL (*fill_reply)( struct icmp_get_reply_params *params, struct icmp_reply_ctx *ctx );
 };
 
 static const struct family_ops ipv4 =
@@ -495,7 +543,6 @@ static const struct family_ops ipv4 =
     chksum,
     ipv4_set_reply_ip_status,
     ipv4_set_socket_opts,
-    ipv4_reply_buffer_len,
     ipv4_parse_ip_hdr,
     ipv4_parse_icmp_hdr,
     ipv4_fill_reply,
@@ -511,7 +558,6 @@ static const struct family_ops ipv4_linux_ping =
     chksum,
     ipv4_set_reply_ip_status,
     ipv4_linux_ping_set_socket_opts,
-    ipv4_linux_ping_reply_buffer_len,
     ipv4_linux_ping_parse_ip_hdr,
     ipv4_parse_icmp_hdr,
     ipv4_fill_reply,
@@ -523,7 +569,7 @@ static void ipv6_init_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp_hd
     icmp_hdr->type = ICMP6_ECHO_REQUEST;
     icmp_hdr->code = 0;
     icmp_hdr->checksum = 0;
-    icmp_hdr->un.echo.id = data->id = getpid() & 0xffff; /* will be overwritten for linux ping socks */
+    icmp_hdr->un.echo.id = data->s->id;
     icmp_hdr->un.echo.sequence = data->seq = InterlockedIncrement( &icmp_sequence ) & 0xffff;
 }
 
@@ -535,7 +581,7 @@ static unsigned short ipv6_chksum( struct icmp_data *icmp_data, BYTE *data, unsi
     socklen_t slen;
     int s, ret;
 
-    if (icmp_data->ping_socket) return 0;
+    if (icmp_data->s->ping_socket) return 0;
 
     /* Determine source address. Do it on a separate socket or raw socket won't receive ICMP replies
      * originating not from the destination address. */
@@ -550,7 +596,7 @@ static unsigned short ipv6_chksum( struct icmp_data *icmp_data, BYTE *data, unsi
             return 0;
         }
     }
-    if (bind( s, (void *)&icmp_data->src_storage, icmp_data->src_len ))
+    if (bind( s, (void *)&icmp_data->s->src_storage, icmp_data->s->src_len ))
     {
         close( s );
         return 0;
@@ -587,35 +633,66 @@ static int ipv6_set_reply_ip_status( IP_STATUS ip_status, unsigned int bits, voi
     return sizeof(*reply);
 }
 
-static void ipv6_set_socket_opts( struct icmp_data *data, struct icmp_send_echo_params *params )
+static void ipv6_set_socket_opts( struct icmp_socket *s )
 {
 #ifdef IPV6_UNICAST_HOPS
 {
-    int val = params->hop_limit;
+    int val = s->hop_limit;
 
-    setsockopt( data->socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val) );
+    setsockopt( s->socket, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &val, sizeof(val) );
 }
 #endif
-}
-
-static int ipv6_reply_buffer_len( struct icmp_listen_params *params )
+#ifdef IP_RECVERR
 {
-    return sizeof(struct icmp_hdr) + params->reply_len - sizeof(ICMPV6_ECHO_REPLY);
+    int val = 1;
+
+    if (s->ping_socket)
+        setsockopt( s->socket, IPPROTO_IPV6, IPV6_RECVERR, &val, sizeof(val) );
+}
+#endif
 }
 
-static BOOL ipv6_parse_ip_hdr( struct msghdr *msg, int recvd, int *ip_hdr_len,
+static BOOL ipv6_parse_ip_hdr( struct msghdr *msg, int *recvd, int *ip_hdr_len,
                                           struct icmp_reply_ctx *ctx )
 {
     *ip_hdr_len = 0;
-    ctx->options_data = NULL;
+    ctx->options_data_offset = 0;
     ctx->ttl = 0;
     ctx->tos = 0;
     ctx->flags = 0;
     ctx->options_size = 0;
+
+#ifdef HAVE_LINUX_ERRQUEUE_H
+{
+    struct sock_extended_err *e;
+    struct icmp_hdr *icmp_h;
+    struct cmsghdr *cmsg;
+
+    for (cmsg = CMSG_FIRSTHDR( msg ); cmsg; cmsg = CMSG_NXTHDR( msg, cmsg ))
+    {
+        if (cmsg->cmsg_level != IPPROTO_IPV6) continue;
+        switch (cmsg->cmsg_type)
+        {
+        case IPV6_RECVERR:
+            e = (struct sock_extended_err *)CMSG_DATA( cmsg );
+            icmp_h = msg->msg_iov[0].iov_base;
+            if (e->ee_origin != SO_EE_ORIGIN_ICMP6) break;
+            if (*recvd + sizeof(*icmp_h) > ARRAY_SIZE(ctx->packet)) break;
+            TRACE( "got error packet.\n" );
+            memmove( ctx->packet + sizeof(*icmp_h), ctx->packet, *recvd );
+            *recvd += sizeof(*icmp_h);
+            memset( icmp_h, 0, sizeof(*icmp_h) );
+            icmp_h->type = e->ee_type;
+            icmp_h->code = e->ee_code;
+            break;
+        }
+    }
+}
+#endif
     return TRUE;
 }
 
-static int ipv6_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
+static int ipv6_parse_icmp_hdr( struct icmp_socket *s, struct icmp_hdr *icmp,
                                 int icmp_size, struct icmp_reply_ctx *ctx )
 {
     static const IP_STATUS unreach_codes[] =
@@ -636,9 +713,8 @@ static int ipv6_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
     switch (icmp->type)
     {
     case ICMP6_ECHO_REPLY:
-        if ((!data->ping_socket && icmp->un.echo.id != data->id) ||
-            icmp->un.echo.sequence != data->seq) return -1;
-
+        ctx->id = icmp->un.echo.id;
+        ctx->sequence = icmp->un.echo.sequence;
         ctx->status = IP_SUCCESS;
         return icmp_size - sizeof(*icmp);
 
@@ -670,24 +746,28 @@ static int ipv6_parse_icmp_hdr( struct icmp_data *data, struct icmp_hdr *icmp,
         return -1;
     }
 
-    if (data->ping_socket) return 0;
-    /* Check that the appended packet is really ours. */
-    if (icmp_size < sizeof(*icmp) + sizeof(*orig_ip_hdr)) return -1;
-    orig_ip_hdr = (struct ipv6_hdr *)(icmp + 1);
-    if ((orig_ip_hdr->v_prio >> 4) != 6 || orig_ip_hdr->next_hdr != IPPROTO_ICMPV6) return -1;
-    if (icmp_size < sizeof(*icmp) + sizeof(*orig_ip_hdr) + sizeof(*orig_icmp_hdr)) return -1;
-    orig_icmp_hdr = (const struct icmp_hdr *)((const BYTE *)orig_ip_hdr + sizeof(*orig_ip_hdr));
+    icmp_size -= sizeof(*icmp);
+    if (s->ping_socket) orig_icmp_hdr = icmp + 1;
+    else
+    {
+        /* All handled icmp replies have an 8-byte header followed by the original ip hdr. */
+        if (icmp_size < sizeof(*orig_ip_hdr)) return -1;
+        icmp_size -= sizeof(*orig_ip_hdr);
+        orig_ip_hdr = (struct ipv6_hdr *)(icmp + 1);
+        if ((orig_ip_hdr->v_prio >> 4) != 6 || orig_ip_hdr->next_hdr != IPPROTO_ICMPV6) return -1;
+        orig_icmp_hdr = (const struct icmp_hdr *)((const BYTE *)orig_ip_hdr + sizeof(*orig_ip_hdr));
+    }
+    if (icmp_size < sizeof(*orig_icmp_hdr)) return -1;
     if (orig_icmp_hdr->type != ICMP6_ECHO_REQUEST ||
-        orig_icmp_hdr->code != 0 ||
-        (!data->ping_socket && orig_icmp_hdr->un.echo.id != data->id) ||
-        orig_icmp_hdr->un.echo.sequence != data->seq) return -1;
+        orig_icmp_hdr->code != 0) return -1;
 
+    ctx->id = orig_icmp_hdr->un.echo.id;
+    ctx->sequence = orig_icmp_hdr->un.echo.sequence;
     ctx->status = status;
-
     return 0;
 }
 
-static void ipv6_fill_reply( struct icmp_listen_params *params, struct icmp_reply_ctx *ctx)
+static BOOL ipv6_fill_reply( struct icmp_get_reply_params *params, struct icmp_reply_ctx *ctx)
 {
     ICMPV6_ECHO_REPLY *reply = params->reply;
 
@@ -697,8 +777,11 @@ static void ipv6_fill_reply( struct icmp_listen_params *params, struct icmp_repl
     reply->Address.sin6_port = ctx->addr.Ipv6.sin6_port;
     reply->Address.sin6_scope_id = ctx->addr.Ipv6.sin6_scope_id;
     reply->RoundTripTime = ctx->round_trip_time;
-    memcpy( reply + 1, ctx->data, ctx->data_size );
+    if (sizeof(*reply) + ctx->data_size > params->reply_len)
+        return FALSE;
+    memcpy( reply + 1, ctx->packet + ctx->data_offset, ctx->data_size );
     params->reply_len = sizeof(*reply) + ctx->data_size;
+    return TRUE;
 }
 
 static const struct family_ops ipv6 =
@@ -709,7 +792,6 @@ static const struct family_ops ipv6 =
     ipv6_chksum,
     ipv6_set_reply_ip_status,
     ipv6_set_socket_opts,
-    ipv6_reply_buffer_len,
     ipv6_parse_ip_hdr,
     ipv6_parse_icmp_hdr,
     ipv6_fill_reply,
@@ -733,6 +815,7 @@ static int SOCKADDR_INET_to_sockaddr( const SOCKADDR_INET *in, struct sockaddr *
         struct sockaddr_in *sa = (struct sockaddr_in *)out;
 
         if (len < sizeof(*sa)) return 0;
+        memset( sa, 0, sizeof(*sa) );
         sa->sin_family = AF_INET;
         sa->sin_port = in->Ipv4.sin_port;
         sa->sin_addr.s_addr = in->Ipv4.sin_addr.WS_s_addr;
@@ -743,6 +826,7 @@ static int SOCKADDR_INET_to_sockaddr( const SOCKADDR_INET *in, struct sockaddr *
         struct sockaddr_in6 *sa = (struct sockaddr_in6 *)out;
 
         if (len < sizeof(*sa)) return 0;
+        memset( sa, 0, sizeof(*sa) );
         sa->sin6_family = AF_INET6;
         sa->sin6_port = in->Ipv6.sin6_port;
         sa->sin6_flowinfo = in->Ipv6.sin6_flowinfo;
@@ -782,81 +866,171 @@ static BOOL sockaddr_to_SOCKADDR_INET( const struct sockaddr *in, SOCKADDR_INET
     return FALSE;
 }
 
-static NTSTATUS icmp_data_create( ADDRESS_FAMILY win_family, struct icmp_data **icmp_data )
+static void icmp_grab_socket( struct icmp_socket *s )
+{
+    assert( s->ref > 0 );
+    InterlockedIncrement( &s->ref );
+}
+
+static void icmp_release_socket( struct icmp_socket *s )
+{
+    pthread_mutex_lock( &listen_lock );
+    if (!InterlockedDecrement( &s->ref ))
+    {
+        TRACE( "freeing socket %p, fd %d.\n", s, s->socket );
+        if (s->polling) list_remove( &s->entry );
+        if (s->socket >= 0) close( s->socket );
+        free( s );
+    }
+    pthread_mutex_unlock( &listen_lock );
+}
+
+static BOOL icmp_data_stop_polling( struct icmp_data *data, NTSTATUS status )
+{
+    BOOL ret;
+
+    pthread_mutex_lock( &listen_lock );
+    if ((ret = data->polling))
+    {
+        list_remove( &data->entry );
+        data->polling = FALSE;
+        data->status = status;
+    }
+    pthread_mutex_unlock( &listen_lock );
+    return ret;
+}
+
+static void icmp_data_free( struct icmp_data *data )
+{
+    assert( !data->polling );
+    icmp_release_socket( data->s );
+    free( data );
+}
+
+static void init_listen(void)
+{
+    HANDLE thread;
+
+    pipe( socket_list_update_pipe );
+
+    if (PsCreateSystemThread( &thread, THREAD_ALL_ACCESS, NULL, 0, NULL, icmp_listen, NULL ))
+        ERR( "Could not create listen thread.\n" );
+    else
+        NtClose( thread );
+}
+
+static NTSTATUS icmp_get_socket( struct icmp_send_echo_params *params, struct icmp_socket **ret_socket )
 {
-    struct icmp_data *data;
     const struct family_ops *ops;
+    struct icmp_socket *s;
+    struct sockaddr *src;
+    int src_len;
+    struct sockaddr_storage src_storage;
+
+    src = (struct sockaddr *)&src_storage;
+    src_len = SOCKADDR_INET_to_sockaddr( params->src, src, sizeof(src_storage) );
 
-    if (win_family == WS_AF_INET6)     ops = &ipv6;
-    else if (win_family == WS_AF_INET) ops = &ipv4;
+    if (params->dst->si_family == WS_AF_INET6)     ops = &ipv6;
+    else if (params->dst->si_family == WS_AF_INET) ops = &ipv4;
     else return STATUS_INVALID_PARAMETER;
 
-    data = malloc( sizeof(*data) );
-    if (!data) return STATUS_NO_MEMORY;
+    *ret_socket = NULL;
+    pthread_mutex_lock( &listen_lock );
+    LIST_FOR_EACH_ENTRY( s, &socket_list, struct icmp_socket, entry )
+    {
+        assert( s->polling );
+        if (params->dst->si_family == WS_AF_INET6 && ops->family != AF_INET6) continue;
+        if (params->dst->si_family == WS_AF_INET && ops->family != AF_INET) continue;
+        if (s->hop_limit != params->hop_limit || s->ttl != params->ttl || s->tos != params->tos) continue;
+        if (s->src_len != src_len) continue;
+        if (memcmp( src, &s->src_storage, src_len )) continue;
+
+        icmp_grab_socket( s );
+        pthread_mutex_unlock( &listen_lock );
+        *ret_socket = s;
+        TRACE( "Using socket %p.\n", s );
+        return STATUS_SUCCESS;
+    }
 
-    data->ping_socket = FALSE;
-    data->socket = socket( ops->family, SOCK_RAW, ops->icmp_protocol );
-    if (data->socket < 0) /* Try a ping-socket */
+    pthread_once( &init_once, init_listen );
+
+    if (!(s = calloc( 1, sizeof(*s) )))
+    {
+        pthread_mutex_unlock( &listen_lock );
+        return STATUS_NO_MEMORY;
+    }
+    s->ref = 1;
+    list_init( &s->request_list );
+    s->socket = -1;
+    s->id = getpid() & 0xffff; /* will be overwritten for linux ping socks */
+    s->ping_socket = FALSE;
+
+    s->socket = socket( ops->family, SOCK_RAW, ops->icmp_protocol );
+    if (s->socket < 0) /* Try a ping-socket */
     {
+        int value = 1;
+
         TRACE( "failed to open raw sock, trying a dgram sock\n" );
-        data->socket = socket( ops->family, SOCK_DGRAM, ops->icmp_protocol );
-        if (data->socket < 0)
+        s->socket = socket( ops->family, SOCK_DGRAM, ops->icmp_protocol );
+        if (s->socket < 0)
         {
             WARN( "Unable to create socket\n" );
-            free( data );
+            pthread_mutex_unlock( &listen_lock );
+            icmp_release_socket( s );
             return STATUS_ACCESS_DENIED;
         }
+        setsockopt( s->socket, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(value) );
 #ifdef __linux__
         if (ops->family == AF_INET) ops = &ipv4_linux_ping;
-        data->ping_socket = TRUE;
+        s->ping_socket = TRUE;
 #endif
     }
-    if (pipe( data->cancel_pipe ))
+
+    s->hop_limit = params->hop_limit;
+    s->ttl = params->ttl;
+    s->tos = params->tos;
+    s->src_len = src_len;
+    s->src_storage = src_storage;
+
+    if (bind( s->socket, src, s->src_len ))
     {
-        close( data->socket );
-        free( data );
-        return STATUS_ACCESS_DENIED;
+        pthread_mutex_unlock( &listen_lock );
+        icmp_release_socket( s );
+        return STATUS_INVALID_ADDRESS_COMPONENT;
     }
 
-    data->ops = ops;
-    *icmp_data = data;
+    s->ops = ops;
+    s->ops->set_socket_opts( s );
+    list_add_tail( &socket_list, &s->entry );
+    s->polling = TRUE;
+    pthread_mutex_unlock( &listen_lock );
+    write( socket_list_update_pipe[1], "x", 1 );
+    *ret_socket = s;
+    TRACE( "created socket %p.\n", s );
     return STATUS_SUCCESS;
 }
 
-static void icmp_data_free( struct icmp_data *data )
-{
-    close( data->socket );
-    close( data->cancel_pipe[0] );
-    close( data->cancel_pipe[1] );
-    free( data );
-}
-
 NTSTATUS icmp_send_echo( void *args )
 {
     struct icmp_send_echo_params *params = args;
     struct icmp_hdr *icmp_hdr; /* this is the same for both ipv4 and ipv6 */
     struct icmp_data *data;
-    int ret;
-    struct sockaddr *src, *dst;
+    struct sockaddr *dst;
+    int ret, err;
 
     NTSTATUS status;
 
-    status = icmp_data_create( params->dst->si_family, &data );
-    if (status) return status;
-
-    data->hop_limit = params->hop_limit;
-    src = (struct sockaddr *)&data->src_storage;
-    dst = (struct sockaddr *)&data->dst_storage;
-    data->src_len = SOCKADDR_INET_to_sockaddr( params->src, src, sizeof(data->src_storage) );
-    data->dst_len = SOCKADDR_INET_to_sockaddr( params->dst, dst, sizeof(data->dst_storage) );
-
-    if (bind( data->socket, src, data->src_len ))
+    data = calloc( 1, sizeof(*data) );
+    if (!data) return STATUS_NO_MEMORY;
+    if ((status = icmp_get_socket( params, &data->s )))
     {
-        icmp_data_free( data );
-        return STATUS_INVALID_ADDRESS_COMPONENT;
+        free( data );
+        return status;
     }
+    data->completion_event = params->completion_event;
 
-    data->ops->set_socket_opts( data, params );
+    dst = (struct sockaddr *)&data->dst_storage;
+    data->dst_len = SOCKADDR_INET_to_sockaddr( params->dst, dst, sizeof(data->dst_storage) );
 
     icmp_hdr = malloc( sizeof(*icmp_hdr) + params->request_size );
     if (!icmp_hdr)
@@ -864,38 +1038,42 @@ NTSTATUS icmp_send_echo( void *args )
         icmp_data_free( data );
         return STATUS_NO_MEMORY;
     }
-    data->ops->init_icmp_hdr( data, icmp_hdr );
+    data->s->ops->init_icmp_hdr( data, icmp_hdr );
     memcpy( icmp_hdr + 1, params->request, params->request_size );
-    icmp_hdr->checksum = data->ops->chksum( data, (BYTE *)icmp_hdr, sizeof(*icmp_hdr) + params->request_size );
+    icmp_hdr->checksum = data->s->ops->chksum( data, (BYTE *)icmp_hdr, sizeof(*icmp_hdr) + params->request_size );
+
+    TRACE( "data %p, seq %d.\n", data, data->seq );
+
+    pthread_mutex_lock( &listen_lock );
+    list_add_tail( &data->s->request_list, &data->entry );
+    data->polling = TRUE;
+    pthread_mutex_unlock( &listen_lock );
 
     NtQueryPerformanceCounter( &data->send_time, NULL );
-    ret = sendto( data->socket, icmp_hdr, sizeof(*icmp_hdr) + params->request_size, 0, dst, data->dst_len );
+    ret = sendto( data->s->socket, icmp_hdr, sizeof(*icmp_hdr) + params->request_size, 0,
+                  (struct sockaddr *)&data->dst_storage, data->dst_len );
+    if (ret < 0) err = errno;
     free( icmp_hdr );
 
     if (ret < 0)
     {
-        TRACE( "sendto() rets %d errno %d\n", ret, errno );
-        params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->bits, params->reply );
+        status = errno_to_ip_status( err );
+        TRACE( "sendto() rets %d errno %d\n", ret, err );
+        icmp_data_stop_polling( data, status );
+        params->reply_len = data->s->ops->set_reply_ip_status( status, params->bits, params->reply );
         icmp_data_free( data );
         return STATUS_SUCCESS;
     }
 
     *params->handle = handle_alloc( data );
-    if (!*params->handle) icmp_data_free( data );
+    if (!*params->handle)
+    {
+        icmp_data_stop_polling( data, STATUS_NO_MEMORY );
+        icmp_data_free( data );
+    }
     return *params->handle ? STATUS_PENDING : STATUS_NO_MEMORY;
 }
 
-static int get_timeout( LARGE_INTEGER start, UINT timeout )
-{
-    LARGE_INTEGER now, end;
-
-    end.QuadPart = start.QuadPart + (ULONGLONG)timeout * 10000;
-    NtQueryPerformanceCounter( &now, NULL );
-    if (now.QuadPart >= end.QuadPart) return 0;
-
-    return min( (end.QuadPart - now.QuadPart) / 10000, INT_MAX );
-}
-
 static ULONG get_rtt( LARGE_INTEGER start )
 {
     LARGE_INTEGER now;
@@ -904,121 +1082,159 @@ static ULONG get_rtt( LARGE_INTEGER start )
     return (now.QuadPart - start.QuadPart) / 10000;
 }
 
-static NTSTATUS recv_msg( struct icmp_data *data, struct icmp_listen_params *params )
+static void icmp_listen( void *args )
 {
     struct sockaddr_storage addr;
     struct icmp_reply_ctx ctx;
-    struct iovec iov[1];
     BYTE cmsg_buf[1024];
-    struct msghdr msg = { .msg_name = &addr, .msg_namelen = sizeof(addr),
-                          .msg_iov = iov, .msg_iovlen = ARRAY_SIZE(iov),
-                          .msg_control = cmsg_buf, .msg_controllen = sizeof(cmsg_buf) };
-    int ip_hdr_len, recvd, reply_buf_len;
-    char *reply_buf;
+    struct iovec iov[1] = {{ .iov_base = ctx.packet, .iov_len = sizeof(ctx.packet) }};
+    struct msghdr msg = { .msg_iov = iov, .msg_iovlen = ARRAY_SIZE(iov) };
+    struct list listen_list;
+    unsigned int fds_size = 64;
+    struct pollfd *fds = malloc( fds_size * sizeof(*fds) );
+    struct icmp_socket *s, *next;
     struct icmp_hdr *icmp_hdr;
+    int ip_hdr_len, recvd;
+    struct icmp_data *data;
+    unsigned int i, count;
+    BOOL matched;
+    int ret;
+    BYTE b;
 
-    reply_buf_len = data->ops->reply_buffer_len( params );
-    reply_buf = malloc( reply_buf_len );
-    if (!reply_buf) return STATUS_NO_MEMORY;
-
-    iov[0].iov_base = reply_buf;
-    iov[0].iov_len = reply_buf_len;
-
-    recvd = recvmsg( data->socket, &msg, 0 );
-    TRACE( "recvmsg() rets %d errno %d addr_len %d iovlen %d msg_flags %x\n",
-           recvd, errno, msg.msg_namelen, (int)iov[0].iov_len, msg.msg_flags );
-
-    if (recvd < 0) goto skip;
-    if (!data->ops->parse_ip_hdr( &msg, recvd, &ip_hdr_len, &ctx )) goto skip;
-    if (recvd < ip_hdr_len + sizeof(*icmp_hdr)) goto skip;
-
-    icmp_hdr = (struct icmp_hdr *)(reply_buf + ip_hdr_len);
-    if ((ctx.data_size = data->ops->parse_icmp_hdr( data, icmp_hdr, recvd - ip_hdr_len, &ctx )) < 0) goto skip;
-    if (ctx.data_size && msg.msg_flags & MSG_TRUNC)
+    pthread_once( &init_once, init_listen );
+    while (1)
     {
-        free( reply_buf );
-        params->reply_len = data->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->bits, params->reply );
-        return STATUS_SUCCESS;
-    }
-
-    sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &ctx.addr );
-    ctx.round_trip_time = get_rtt( data->send_time );
-    ctx.data = icmp_hdr + 1;
-
-    data->ops->fill_reply( params, &ctx );
+        list_init( &listen_list );
 
-    free( reply_buf );
-    return STATUS_SUCCESS;
+        pthread_mutex_lock( &listen_lock );
+        i = 0;
+        LIST_FOR_EACH_ENTRY( s, &socket_list, struct icmp_socket, entry )
+        {
+            icmp_grab_socket( s );
+            list_add_tail( &listen_list, &s->listen_entry );
+            if (i + 1 >= fds_size)
+            {
+                fds_size *= 2;
+                fds = realloc( fds, fds_size * sizeof(*fds) );
+            }
+            fds[i].fd = s->socket;
+            fds[i].events = POLLIN;
+            ++i;
+        }
+        pthread_mutex_unlock( &listen_lock );
+
+        fds[i].fd = socket_list_update_pipe[0];
+        fds[i].events = POLLIN;
+        count = i;
+        while ((ret = poll( fds, count + 1, -1 )) < 0 && (errno == EINTR || errno == EAGAIN))
+            ;
+        if (ret < 0)
+        {
+            ERR( "poll(): ret %d, %s.\n", ret, strerror( errno ));
+            return;
+        }
 
+        i = 0;
+        LIST_FOR_EACH_ENTRY( s, &listen_list, struct icmp_socket, listen_entry )
+        {
+            if (!(fds[i].revents & (POLLIN | POLLERR))) goto skip;
+            msg.msg_name = &addr;
+            msg.msg_namelen = sizeof(addr);
+            msg.msg_control = cmsg_buf;
+            msg.msg_controllen = sizeof(cmsg_buf);
+            recvd = recvmsg( s->socket, &msg, 0 );
+            TRACE( "s %p, recvmsg() rets %d errno %d addr_len %d iovlen %d msg_flags %x\n",
+                   s, recvd, errno, msg.msg_namelen, (int)iov[0].iov_len, msg.msg_flags );
+#ifdef __linux__
+            if (recvd < 0 && s->ping_socket && fds[i].revents & POLLERR)
+            {
+                msg.msg_name = &addr;
+                msg.msg_namelen = sizeof(addr);
+                msg.msg_control = cmsg_buf;
+                msg.msg_controllen = sizeof(cmsg_buf);
+                recvd = recvmsg( s->socket, &msg, MSG_ERRQUEUE );
+                TRACE( "s %p, recvmsg(MSG_ERRQUEUE) rets %d errno %d addr_len %d iovlen %d msg_flags %x\n",
+                       s, recvd, errno, msg.msg_namelen, (int)iov[0].iov_len, msg.msg_flags );
+            }
+#endif
+            if (recvd < 0) goto skip;
+            if (!s->ops->parse_ip_hdr( &msg, &recvd, &ip_hdr_len, &ctx )) goto skip;
+            if (recvd < ip_hdr_len + sizeof(*icmp_hdr)) goto skip;
+            ctx.packet_size = recvd;
+            icmp_hdr = (struct icmp_hdr *)(ctx.packet + ip_hdr_len);
+            if ((ctx.data_size = s->ops->parse_icmp_hdr( s, icmp_hdr, recvd - ip_hdr_len, &ctx )) < 0)
+            {
+                WARN( "parse_icmp_hdr failed.\n" );
+                goto skip;
+            }
+            pthread_mutex_lock( &listen_lock );
+            matched = FALSE;
+            LIST_FOR_EACH_ENTRY( data, &s->request_list, struct icmp_data, entry )
+            {
+                if ((!s->ping_socket && ctx.id != s->id) || ctx.sequence != data->seq) continue;
+                TRACE( "id %d, seq %d matched to %p.\n", ctx.id, ctx.sequence, data );
+                matched = TRUE;
+                data->polling = FALSE;
+                list_remove( &data->entry );
+                sockaddr_to_SOCKADDR_INET( (struct sockaddr *)&addr, &ctx.addr );
+                ctx.round_trip_time = get_rtt( data->send_time );
+                ctx.data_offset = (BYTE *)(icmp_hdr + 1) - ctx.packet;
+                data->reply_ctx = ctx;
+                NtSetEvent( data->completion_event, NULL );
+                break;
+            }
+            pthread_mutex_unlock( &listen_lock );
+            if (!matched) TRACE( "id %d, seq %d not matched.\n", ctx.id, ctx.sequence );
 skip:
-    free( reply_buf );
-    return STATUS_RETRY;
+            ++i;
+        }
+        if (fds[count].revents & POLLIN)
+        {
+            read( socket_list_update_pipe[0], &b, 1 );
+            TRACE( "updating socket list.\n" );
+        }
+
+        LIST_FOR_EACH_ENTRY_SAFE( s, next, &listen_list, struct icmp_socket, listen_entry )
+        {
+            icmp_release_socket( s );
+        }
+    }
 }
 
-NTSTATUS icmp_listen( void *args )
+NTSTATUS icmp_get_reply( void *args )
 {
-    struct icmp_listen_params *params = args;
+    struct icmp_get_reply_params *params = args;
     struct icmp_data *data;
-    struct pollfd fds[2];
-    NTSTATUS status;
-    int ret;
+    NTSTATUS ret = STATUS_SUCCESS;
 
     data = handle_data( params->handle );
     if (!data) return STATUS_INVALID_PARAMETER;
 
-    if (data->dst_storage.ss_family == AF_INET6 && !data->hop_limit)
+    if (data->dst_storage.ss_family == AF_INET6 && !data->s->hop_limit)
     {
-        TRACE( "Invalid hop_limit.\n" );
-        params->reply_len = data->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->bits, params->reply );
-        return STATUS_SUCCESS;
+        TRACE( "data %p, seq %u, invalid hop_limit.\n", data, data->seq );
+        icmp_data_stop_polling( data, STATUS_SUCCESS );
+        params->reply_len = data->s->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->bits, params->reply );
+        goto done;
     }
 
-    fds[0].fd = data->socket;
-    fds[0].events = POLLIN;
-    fds[1].fd = data->cancel_pipe[0];
-    fds[1].events = POLLIN;
-
-    while ((ret = poll( fds, ARRAY_SIZE(fds), get_timeout( data->send_time, params->timeout ) )) > 0)
+    if (icmp_data_stop_polling( data, STATUS_TIMEOUT ))
     {
-        if (fds[1].revents & POLLIN)
-        {
-            TRACE( "cancelled\n" );
-            return STATUS_CANCELLED;
-        }
-
-        status = recv_msg( data, params );
-        if (status == STATUS_RETRY) continue;
-        return status;
+        /* Was still polling, timeout. */
+        TRACE( "data %p, seq %u, timeout.\n", data, data->seq );
+        params->reply_len = data->s->ops->set_reply_ip_status( IP_REQ_TIMED_OUT, params->bits, params->reply );
     }
-
-    if (!ret) /* timeout */
+    else if (!(ret = data->status))
     {
-        TRACE( "timeout\n" );
-        params->reply_len = data->ops->set_reply_ip_status( IP_REQ_TIMED_OUT, params->bits, params->reply );
-        return STATUS_SUCCESS;
+        if (!data->s->ops->fill_reply( params, &data->reply_ctx ))
+        {
+            WARN( "data %p, seq %u, buffer too small.\n", data, data->seq );
+            params->reply_len = data->s->ops->set_reply_ip_status( IP_GENERAL_FAILURE, params->bits, params->reply );
+        }
+        else TRACE( "data %p, seq %u, got reply %u.\n", data, data->seq, data->reply_ctx.status );
     }
-    /* ret < 0 */
-    params->reply_len = data->ops->set_reply_ip_status( errno_to_ip_status( errno ), params->bits, params->reply );
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS icmp_cancel_listen( void *args )
-{
-    struct icmp_cancel_listen_params *params = args;
-    struct icmp_data *data = handle_data( params->handle );
-
-    if (!data) return STATUS_INVALID_PARAMETER;
-    write( data->cancel_pipe[1], "x", 1 );
-    return STATUS_SUCCESS;
-}
-
-NTSTATUS icmp_close( void *args )
-{
-    struct icmp_close_params *params = args;
-    struct icmp_data *data = handle_data( params->handle );
-
-    if (!data) return STATUS_INVALID_PARAMETER;
+done:
     icmp_data_free( data );
     handle_free( params->handle );
-    return STATUS_SUCCESS;
+    return ret;
 }
diff --git a/dlls/nsiproxy.sys/nsi.c b/dlls/nsiproxy.sys/nsi.c
index 7fe1e1c92743..09ced8f814ee 100644
--- a/dlls/nsiproxy.sys/nsi.c
+++ b/dlls/nsiproxy.sys/nsi.c
@@ -343,9 +343,7 @@ static NTSTATUS unix_nsi_get_notification( void *args )
 
 const unixlib_entry_t __wine_unix_call_funcs[] =
 {
-    icmp_cancel_listen,
-    icmp_close,
-    icmp_listen,
+    icmp_get_reply,
     icmp_send_echo,
     unix_nsi_enumerate_all_ex,
     unix_nsi_get_all_parameters_ex,
diff --git a/dlls/nsiproxy.sys/nsiproxy_private.h b/dlls/nsiproxy.sys/nsiproxy_private.h
index ab40fa2057aa..cd1a7508087e 100644
--- a/dlls/nsiproxy.sys/nsiproxy_private.h
+++ b/dlls/nsiproxy.sys/nsiproxy_private.h
@@ -20,23 +20,12 @@
 
 typedef UINT icmp_handle;
 
-struct icmp_cancel_listen_params
-{
-    icmp_handle handle;
-};
-
-struct icmp_close_params
-{
-    icmp_handle handle;
-};
-
-struct icmp_listen_params
+struct icmp_get_reply_params
 {
     icmp_handle handle;
     void *reply;
     ULONGLONG user_reply_ptr;
     unsigned int bits, reply_len;
-    int timeout;
 };
 
 struct icmp_send_echo_params
@@ -47,6 +36,7 @@ struct icmp_send_echo_params
     UINT request_size, reply_len;
     BYTE bits, ttl, tos;
     int hop_limit;
+    HANDLE completion_event;
     icmp_handle *handle;
 };
 
diff --git a/dlls/nsiproxy.sys/unix_private.h b/dlls/nsiproxy.sys/unix_private.h
index 5487de5111d8..170bdba665da 100644
--- a/dlls/nsiproxy.sys/unix_private.h
+++ b/dlls/nsiproxy.sys/unix_private.h
@@ -177,7 +177,5 @@ static inline int ascii_strcasecmp( const char *s1, const char *s2 )
     return ascii_strncasecmp( s1, s2, -1 );
 }
 
-NTSTATUS icmp_cancel_listen( void *args );
-NTSTATUS icmp_close( void *args );
-NTSTATUS icmp_listen( void *args );
+NTSTATUS icmp_get_reply( void *args );
 NTSTATUS icmp_send_echo( void *args );
diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c
index cae5e5d8bbd3..1ced62bf6087 100644
--- a/dlls/ntdll/env.c
+++ b/dlls/ntdll/env.c
@@ -699,6 +699,7 @@ void init_user_process_params(void)
         return;
 
     new_params->Environment     = env;
+    new_params->Flags           = params->Flags;
     new_params->DebugFlags      = params->DebugFlags;
     new_params->ConsoleHandle   = params->ConsoleHandle;
     new_params->ConsoleFlags    = params->ConsoleFlags;
diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c
index 2cb8d8819062..0ebcb15a379b 100644
--- a/dlls/ntdll/sec.c
+++ b/dlls/ntdll/sec.c
@@ -41,7 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
 SYMCRYPT_CPU_FEATURES SYMCRYPT_CALL SymCryptCpuFeaturesNeverPresent(void) { return 0; }
 void SYMCRYPT_CALL SymCryptFatal( UINT32 fatalCode ) { }
 void SYMCRYPT_CALL SymCryptInjectError( PBYTE pbBuf, SIZE_T cbBuf ) { }
-#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
+#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64
 SYMCRYPT_ERROR SYMCRYPT_CALL SymCryptSaveXmm( PSYMCRYPT_EXTENDED_SAVE_DATA pSaveArea ) { return SYMCRYPT_NO_ERROR; }
 void SYMCRYPT_CALL SymCryptRestoreXmm( PSYMCRYPT_EXTENDED_SAVE_DATA pSaveArea ) { }
 #endif
diff --git a/dlls/ntdll/tests/info.c b/dlls/ntdll/tests/info.c
index 3b133ce1c696..a9c85d0e58c5 100644
--- a/dlls/ntdll/tests/info.c
+++ b/dlls/ntdll/tests/info.c
@@ -25,6 +25,7 @@
 #define WIN32_NO_STATUS
 #include "windef.h"
 #include "winbase.h"
+#include "winreg.h"
 #include "winternl.h"
 #include "winnls.h"
 #include "ddk/ntddk.h"
@@ -4378,6 +4379,117 @@ static void test_processor_idle_cycle_time(void)
     ok( size == cpu_count * sizeof(*buffer), "got %#lx.\n", size );
 }
 
+static ULONG get_process_parameters_flags( HANDLE process )
+{
+    RTL_USER_PROCESS_PARAMETERS *params;
+    PROCESS_BASIC_INFORMATION pbi;
+    ULONG flags = 0xdeadbeef;
+    NTSTATUS status;
+    SIZE_T len;
+    BOOL ret;
+
+    status = pNtQueryInformationProcess( process, ProcessBasicInformation, &pbi, sizeof(pbi), NULL );
+    ok( !status, "got %#lx.\n", status );
+    ret = ReadProcessMemory( process, (char *)pbi.PebBaseAddress + offsetof(PEB, ProcessParameters), &params, sizeof(params), &len );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    ret = ReadProcessMemory( process, &params->Flags, &flags, sizeof(flags), &len );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    return flags;
+}
+
+static void test_debuggee_process_parameters_flags(int argc, char **argv)
+{
+    PEB *peb = NtCurrentTeb()->Peb;
+
+    ok( peb->ProcessParameters->Flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+    while (!IsDebuggerPresent())
+        Sleep( 10 );
+    ok( peb->ProcessParameters->Flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+}
+
+static void test_process_parameters_flags( int argc, char **argv )
+{
+    SECURITY_ATTRIBUTES sa = { .nLength = sizeof(sa), .bInheritHandle = TRUE };
+    PEB *peb = NtCurrentTeb()->Peb;
+    STARTUPINFOA si = { 0 };
+    char cmdline[MAX_PATH];
+    PROCESS_INFORMATION pi;
+    char keyname[MAX_PATH];
+    const char *basename;
+    ULONG flags;
+    DWORD err;
+    HKEY hkey;
+    BOOL ret;
+
+    if ((basename = strrchr( argv[0], '\\' ))) basename++;
+    else basename = argv[0];
+
+    sprintf( keyname, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s", basename );
+    if (!strcmp( keyname + strlen(keyname) - 3, ".so" )) keyname[strlen(keyname) - 3] = 0;
+    ok( peb->ProcessParameters->Flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+    sprintf( cmdline, "%s %s %s", argv[0], argv[1], "check_pp_flags" );
+
+    si.cb = sizeof(si);
+    ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, DEBUG_PROCESS | CREATE_SUSPENDED, NULL, NULL, &si, &pi );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    flags = get_process_parameters_flags( pi.hProcess );
+    ok( !(flags & PROCESS_PARAMS_IMAGE_KEY_MISSING), "got %#lx.\n", peb->ProcessParameters->Flags );
+    TerminateProcess( pi.hProcess, 0 );
+    CloseHandle( pi.hThread );
+    CloseHandle( pi.hProcess );
+
+    ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    flags = get_process_parameters_flags( pi.hProcess );
+    ok( flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+    TerminateProcess( pi.hProcess, 0 );
+    CloseHandle( pi.hThread );
+    CloseHandle( pi.hProcess );
+
+    ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    flags = get_process_parameters_flags( pi.hProcess );
+    ok( flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+    ResumeThread( pi.hThread );
+    ret = DebugActiveProcess( pi.dwProcessId );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    flags = get_process_parameters_flags( pi.hProcess );
+    ok( flags & PROCESS_PARAMS_IMAGE_KEY_MISSING, "got %#lx.\n", peb->ProcessParameters->Flags );
+    for (;;)
+    {
+        DEBUG_EVENT ev;
+
+        ret = WaitForDebugEvent( &ev, INFINITE );
+        ok( ret, "got error %ld.\n", GetLastError() );
+        if (!ret) break;
+        if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT && ev.dwProcessId == pi.dwProcessId) break;
+        ret = ContinueDebugEvent( ev.dwProcessId, ev.dwThreadId, DBG_CONTINUE );
+        ok( ret, "got error %ld.\n", GetLastError() );
+        if (!ret) break;
+    }
+    DebugActiveProcessStop( pi.dwProcessId );
+    wait_child_process( &pi );
+
+    err = RegCreateKeyA( HKEY_LOCAL_MACHINE, keyname, &hkey );
+    if (err == ERROR_ACCESS_DENIED)
+    {
+        skip( "Not authorized to change the image file execution options.\n" );
+        return;
+    }
+    ok( !err, "got %#lx.\n", err );
+
+    ret = CreateProcessA( NULL, cmdline, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi );
+    ok( ret, "got error %ld.\n", GetLastError() );
+    flags = get_process_parameters_flags( pi.hProcess );
+    ok( !(flags & PROCESS_PARAMS_IMAGE_KEY_MISSING), "got %#lx.\n", peb->ProcessParameters->Flags );
+    TerminateProcess( pi.hProcess, 0 );
+    CloseHandle( pi.hThread );
+    CloseHandle( pi.hProcess );
+
+    RegCloseKey( hkey );
+    RegDeleteKeyA( HKEY_LOCAL_MACHINE, keyname );
+}
+
 START_TEST(info)
 {
     char **argv;
@@ -4389,6 +4501,7 @@ START_TEST(info)
     if (argc >= 3)
     {
         if (strcmp(argv[2], "debuggee:dbgport") == 0) test_debuggee_dbgport(argc - 2, argv + 2);
+        else if (!strcmp(argv[2], "check_pp_flags"))  test_debuggee_process_parameters_flags(argc - 2, argv + 2);
         return; /* Child */
     }
 
@@ -4459,4 +4572,5 @@ START_TEST(info)
     test_process_token(argc, argv);
     test_process_id();
     test_processor_idle_cycle_time();
+    test_process_parameters_flags(argc, argv);
 }
diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c
index f7060b82d23a..460888b95df3 100644
--- a/dlls/ntdll/unix/env.c
+++ b/dlls/ntdll/unix/env.c
@@ -1706,7 +1706,7 @@ static ULONG get_dword_option( HANDLE key, const WCHAR *name, ULONG defval )
 /*************************************************************************
  *		load_global_options
  */
-static void load_global_options( const UNICODE_STRING *image )
+static void load_global_options( const UNICODE_STRING *image, BOOL debugged )
 {
     static const WCHAR optionsW[] = {'\\','R','e','g','i','s','t','r','y','\\',
         'M','a','c','h','i','n','e','\\','S','o','f','t','w','a','r','e','\\',
@@ -1740,6 +1740,12 @@ static void load_global_options( const UNICODE_STRING *image )
         peb->HeapDeCommitFreeBlockThreshold = get_dword_option( key, heapdecommitblockW, 0x1000 );
         NtClose( key );
     }
+
+    if (debugged) peb->NtGlobalFlag |= FLG_HEAP_ENABLE_TAIL_CHECK |
+                                       FLG_HEAP_ENABLE_FREE_CHECK |
+                                       FLG_HEAP_VALIDATE_PARAMETERS;
+    else peb->ProcessParameters->Flags |= PROCESS_PARAMS_IMAGE_KEY_MISSING;
+
     init_unicode_string( &nameW, optionsW );
     if (!NtOpenKey( &key, KEY_QUERY_VALUE, &attr ))
     {
@@ -1750,6 +1756,7 @@ static void load_global_options( const UNICODE_STRING *image )
         if (!NtOpenKey( &key, KEY_QUERY_VALUE, &attr ))
         {
             peb->NtGlobalFlag = get_dword_option( key, globalflagW, peb->NtGlobalFlag );
+            peb->ProcessParameters->Flags &= ~PROCESS_PARAMS_IMAGE_KEY_MISSING;
             NtClose( key );
         }
         NtClose( attr.RootDirectory );
@@ -1824,7 +1831,7 @@ static void *build_wow64_parameters( const RTL_USER_PROCESS_PARAMETERS *params )
 /*************************************************************************
  *		init_peb
  */
-static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module )
+static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module, BOOL debugged )
 {
     peb->ImageBaseAddress           = module;
     peb->ProcessParameters          = params;
@@ -1848,7 +1855,7 @@ static void init_peb( RTL_USER_PROCESS_PARAMETERS *params, void *module )
 #endif
 
     virtual_set_large_address_space();
-    load_global_options( &params->ImagePathName );
+    load_global_options( &params->ImagePathName, debugged );
 
     if (wow_peb)
     {
@@ -2010,11 +2017,12 @@ void init_startup_info(void)
     struct startup_info_data *info;
     UNICODE_STRING nt_name;
     USHORT machine;
+    BOOL debugged;
 
     if (!startup_info_size)
     {
         params = build_initial_params( &module );
-        init_peb( params, module );
+        init_peb( params, module, FALSE );
         return;
     }
 
@@ -2025,6 +2033,7 @@ void init_startup_info(void)
         wine_server_set_reply( req, info, startup_info_size );
         status = wine_server_call( req );
         machine = reply->machine;
+        debugged = reply->debugged;
         info_size = reply->info_size;
         env_size = (wine_server_reply_size( reply ) - info_size) / sizeof(WCHAR);
     }
@@ -2113,7 +2122,7 @@ void init_startup_info(void)
     rebuild_argv();
     main_wargv = build_wargv( params->ImagePathName.Buffer );
     free( nt_name.Buffer );
-    init_peb( params, module );
+    init_peb( params, module, debugged );
 }
 
 
diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
index ea535bd4d274..738e7169cad4 100644
--- a/dlls/ntdll/unix/signal_i386.c
+++ b/dlls/ntdll/unix/signal_i386.c
@@ -1590,13 +1590,12 @@ void call_raise_user_exception_dispatcher( struct thread_data *data )
 NTSTATUS call_user_exception_dispatcher( struct thread_data *data, EXCEPTION_RECORD *rec, CONTEXT *context )
 {
     struct syscall_frame *frame = get_syscall_frame( data );
-    ULONG esp = (frame->esp - sizeof(struct exc_stack_layout)) & ~3;
     struct exc_stack_layout *stack;
     XSAVE_AREA_HEADER *src_xs;
 
     if (rec->ExceptionCode == EXCEPTION_BREAKPOINT) context->Eip--;
 
-    stack = (struct exc_stack_layout *)((esp - sizeof(*stack) - xstate_size) & ~(ULONG_PTR)63);
+    stack = (struct exc_stack_layout *)((frame->esp - sizeof(*stack) - xstate_size) & ~(ULONG_PTR)63);
     stack->rec_ptr      = &stack->rec;
     stack->context_ptr  = &stack->context;
     stack->rec          = *rec;
@@ -1922,9 +1921,11 @@ static BOOL handle_syscall_trap( struct thread_data *data, ucontext_t *sigcontex
         EIP_sig( sigcontext ) = (ULONG)__wine_unix_call_dispatcher_prolog_end;
         fixup_frame_fpu_state( frame, sigcontext );
     }
-    else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ && is_inside_syscall( data, ESP_sig(sigcontext) ))
+    else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ &&
+             (is_inside_syscall( data, ESP_sig(sigcontext) ) ||
+              is_inside_signal_stack( data, (void *)ESP_sig(sigcontext) )))
     {
-        TRACE_(seh)( "ignoring HWBKPT in syscall eip=%p\n", (void *)EIP_sig(sigcontext) );
+        TRACE_(seh)( "ignoring HWBKPT eip=%p\n", (void *)EIP_sig(sigcontext) );
         return TRUE;
     }
     else return FALSE;
diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
index 41293fe56077..0023abf1d2b8 100644
--- a/dlls/ntdll/unix/signal_x86_64.c
+++ b/dlls/ntdll/unix/signal_x86_64.c
@@ -2149,9 +2149,11 @@ static BOOL handle_syscall_trap( struct thread_data *data, ucontext_t *sigcontex
         R10_sig( sigcontext ) = RCX_sig( sigcontext );
         fixup_frame_fpu_state( frame, sigcontext );
     }
-    else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ && is_inside_syscall( data, RSP_sig(sigcontext) ))
+    else if (siginfo->si_code == 4 /* TRAP_HWBKPT */ &&
+             (is_inside_syscall( data, RSP_sig(sigcontext) ) ||
+              is_inside_signal_stack( data, (void *)RSP_sig(sigcontext) )))
     {
-        TRACE_(seh)( "ignoring HWBKPT in syscall rip=%p\n", (void *)RIP_sig(sigcontext) );
+        TRACE_(seh)( "ignoring HWBKPT rip=%p\n", (void *)RIP_sig(sigcontext) );
         return TRUE;
     }
     else return FALSE;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index f6173f0d1e84..eda3fee3d8b3 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -4001,6 +4001,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
     teb32->Peb = PtrToUlong( (char *)peb + page_size );
     teb32->Tib.Self = PtrToUlong( teb32 );
     teb32->Tib.ExceptionList = ~0u;
+    teb32->Tib.FiberData = 0x1e00;
     teb32->ActivationContextStackPointer = PtrToUlong( &teb32->ActivationContextStack );
     teb32->ActivationContextStack.FrameListCache.Flink =
         teb32->ActivationContextStack.FrameListCache.Blink =
@@ -4013,9 +4014,11 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
 #else
     teb = (TEB *)teb32;
     teb32->Tib.ExceptionList = ~0u;
+    teb32->Tib.FiberData = 0x1e00;
     teb64->Peb = PtrToUlong( (char *)peb - page_size );
     teb64->Tib.Self = PtrToUlong( teb64 );
     teb64->Tib.ExceptionList = PtrToUlong( teb32 );
+    teb64->Tib.FiberData = 0x1e00;
     teb64->ActivationContextStackPointer = PtrToUlong( &teb64->ActivationContextStack );
     teb64->ActivationContextStack.FrameListCache.Flink =
         teb64->ActivationContextStack.FrameListCache.Blink =
@@ -4032,6 +4035,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
     teb->Peb = peb;
     teb->Tib.Self = &teb->Tib;
     teb->Tib.StackBase = (void *)~0ul;
+    teb->Tib.FiberData = (void *)0x1e00;
     teb->ActivationContextStackPointer = &teb->ActivationContextStack;
     InitializeListHead( &teb->ActivationContextStack.FrameListCache );
     teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
diff --git a/dlls/ntdll/unwind.c b/dlls/ntdll/unwind.c
index 5b79e48ad85e..f0707346a354 100644
--- a/dlls/ntdll/unwind.c
+++ b/dlls/ntdll/unwind.c
@@ -380,16 +380,16 @@ static void restore_any_reg( int reg, int count, int type, int pos, ARM64_NT_CON
 
 static void do_pac_auth( ARM64_NT_CONTEXT *context )
 {
-    register DWORD64 x17 __asm__( "x17" ) = context->Lr;
-    register DWORD64 x16 __asm__( "x16" ) = context->Sp;
+    register DWORD64 x30 __asm__( "x30" ) = context->Lr;
 
-    /* This is the autib1716 instruction. The hint instruction is used here
-     * as gcc does not assemble autib1716 for pre armv8.3a targets. For
-     * pre-armv8.3a targets, this is just treated as a hint instruction, which
-     * is ignored. */
-    __asm__( "hint 0xe" : "+r"(x17) : "r"(x16) );
+    /* This is the xpaclri instruction. Assemble it through the hint
+     * instruction to make sure it builds with any toolchain, even if it
+     * doesn't support pointer authentication instructions, or if it might not
+     * know to emit them as hint instructions when targeting older versions
+     * than armv8.3. */
+    __asm__( "hint 0x7" : "+r"(x30) );
 
-    context->Lr = x17;
+    context->Lr = x30;
 }
 
 static void process_unwind_codes( BYTE *ptr, BYTE *end, ARM64_NT_CONTEXT *context,
diff --git a/dlls/oleaut32/tests/typelib.c b/dlls/oleaut32/tests/typelib.c
index 153964e17d53..87a5f48d0607 100644
--- a/dlls/oleaut32/tests/typelib.c
+++ b/dlls/oleaut32/tests/typelib.c
@@ -64,7 +64,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/oleaut32/typelib.c b/dlls/oleaut32/typelib.c
index e9997a86d241..9350dd415a15 100644
--- a/dlls/oleaut32/typelib.c
+++ b/dlls/oleaut32/typelib.c
@@ -3899,7 +3899,15 @@ static WORD *SLTG_DoType(WORD *pType, char *pBlk, TYPEDESC *pTD, const sltg_ref_
 	    /* *(pType+1) is offset to a SAFEARRAY, *(pType+2) is type of
 	       array */
 
-	    SAFEARRAY *pSA = (SAFEARRAY *)(pBlk + *(++pType));
+	    struct SLTG_SAFEARRAY
+	    {
+	        short cDims;
+	        short fFetures;
+	        int cbElements;
+	        int cLocks;
+	        int pvData;
+	        SAFEARRAYBOUND rgsabound[1];
+	    } *pSA = (struct SLTG_SAFEARRAY *)(pBlk + *(++pType));
 
 	    pTD->vt = VT_CARRAY;
 	    pTD->lpadesc = calloc(1, sizeof(ARRAYDESC) + (pSA->cDims - 1) * sizeof(SAFEARRAYBOUND));
@@ -4358,6 +4366,23 @@ static void SLTG_ProcessRecord(char *pBlk, ITypeInfoImpl *pTI,
   free(ref_lookup);
 }
 
+static void SLTG_ProcessUnion(char *pBlk, ITypeInfoImpl *pTI,
+			       const char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
+			       const SLTG_TypeInfoTail *pTITail, const BYTE *hlp_strings)
+{
+  sltg_ref_lookup_t *ref_lookup = NULL;
+
+  if (pTIHeader->href_table != 0xffffffff)
+      ref_lookup = SLTG_DoRefs((SLTG_RefInfo*)((char *)pTIHeader + pTIHeader->href_table),
+                               pTI->pTypeLib, (char *)pNameTable);
+
+  if (pTITail->vars_off != 0xffff)
+    SLTG_DoVars(pBlk, pBlk + pTITail->vars_off, pTI, pTITail->cVars,
+                pNameTable, ref_lookup, hlp_strings);
+
+  free(ref_lookup);
+}
+
 static void SLTG_ProcessAlias(char *pBlk, ITypeInfoImpl *pTI,
 			      char *pNameTable, SLTG_TypeInfoHeader *pTIHeader,
 			      const SLTG_TypeInfoTail *pTITail)
@@ -4716,8 +4741,13 @@ static ITypeLib2* ITypeLib2_Constructor_SLTG(LPVOID pLib, DWORD dwTLBLength)
                            pTIHeader, pTITail, hlp_strings);
 	break;
 
+      case TKIND_UNION:
+	SLTG_ProcessUnion((char *)(pMemHeader + 1), *ppTypeInfoImpl, pNameTable,
+                           pTIHeader, pTITail, hlp_strings);
+	break;
+
       default:
-	FIXME("Not processing typekind %d\n", pTIHeader->typekind);
+	ERR("Unknown typekind %d, expected < %d\n", pTIHeader->typekind, TKIND_MAX);
 	break;
 
       }
diff --git a/dlls/opengl32/make_opengl b/dlls/opengl32/make_opengl
index ad4afc54076b..5ddd16af0daa 100755
--- a/dlls/opengl32/make_opengl
+++ b/dlls/opengl32/make_opengl
@@ -132,6 +132,7 @@ my %manual_win_functions =
     (
      "glDebugEntry" => 1,
      "wglChoosePixelFormat" => 1,
+     "wglChoosePixelFormatARB" => 1,
      "wglCreateContext" => 1,
      "wglCreateLayerContext" => 1,
      "wglDescribeLayerPlane" => 1,
@@ -143,10 +144,13 @@ my %manual_win_functions =
      "wglGetExtensionsStringARB" => 1,
      "wglGetExtensionsStringEXT" => 1,
      "wglGetLayerPaletteEntries" => 1,
+     "wglGetPixelFormatAttribfvARB" => 1,
+     "wglGetPixelFormatAttribivARB" => 1,
      "wglGetProcAddress" => 1,
      "wglMakeCurrent" => 1,
      "wglRealizeLayerPalette" => 1,
      "wglSetLayerPaletteEntries" => 1,
+     "wglShareLists" => 1,
      "wglSwapLayerBuffers" => 1,
      "wglUseFontBitmapsA" => 1,
      "wglUseFontBitmapsW" => 1,
@@ -165,18 +169,14 @@ my %manual_win_thunks =
      "glGetFramebufferAttachmentParameterivEXT" => 1,
      "glGetNamedFramebufferAttachmentParameteriv" => 1,
      "glGetNamedFramebufferAttachmentParameterivEXT" => 1,
-     "wglChoosePixelFormatARB" => 1,
      "wglCreateContextAttribsARB" => 1,
      "wglCreatePbufferARB" => 1,
      "wglDeleteContext" => 1,
      "wglDestroyPbufferARB" => 1,
      "wglGetPixelFormat" => 1,
-     "wglGetPixelFormatAttribfvARB" => 1,
-     "wglGetPixelFormatAttribivARB" => 1,
      "wglMakeContextCurrentARB" => 1,
      "wglQueryCurrentRendererStringWINE" => 1,
      "wglQueryRendererStringWINE" => 1,
-     "wglShareLists" => 1,
      "wglSwapBuffers" => 1,
     );
 
@@ -692,6 +692,24 @@ sub get_object_type($$$$)
     $class = "program" if $class eq "program/shader" and has_extension( $func, "GL_NV_vertex_program" );
     $class = "program" if $class eq "program/shader" and has_extension( $func, "GL_EXT_direct_state_access" );
 
+    $class = "shader" if $class eq "program/shader" and $func !~ /(ARB|EXT|NV)$/;
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_AMD_gpu_shader_int64" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_bindless_texture" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_geometry_shader4" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_gpu_shader_int64" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_robustness" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_separate_shader_objects" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_ARB_uniform_buffer_object" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_EXT_bindable_uniform" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_EXT_geometry_shader4" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_EXT_gpu_shader4" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_EXT_separate_shader_objects" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_EXT_transform_feedback" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_NV_bindless_texture" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_NV_path_rendering" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_NV_shader_buffer_load" );
+    $class = "shader" if $class eq "program/shader" and has_extension( $func, "GL_NV_transform_feedback" );
+
     $class = "shader_ati" if has_extension( $func, "GL_ATI_fragment_shader" );
     $class = "shader_ext" if has_extension( $func, "GL_EXT_vertex_shader" );
 
@@ -717,12 +735,16 @@ sub get_object_type($$$$)
     return "OBJ_TYPE_SEMAPHORE"           if $class eq "semaphore";
     return "OBJ_TYPE_SEMAPHORE"           if $ptype =~ /GLuint \*/ and $pname =~ /^(waitS|signalS|s)emaphore(s|Array)$/;
     return "OBJ_TYPE_SEMAPHORE"           if $ptype =~ /GLuint/ and $pname =~ /^semaphore$/;
+    return "OBJ_TYPE_SHADER"              if $class eq "shader";
+    return "OBJ_TYPE_SHADER"              if $func =~ /^gl(Get)?Attach(ed)?Object/ and $pname eq "obj";
+    return "OBJ_TYPE_SHADER"              if $func =~ /^glCreate(Program|Shader)Object/ and $pname eq "ret";
+    return "OBJ_TYPE_SHADER"              if $func =~ /^glGetShaderSource/ and $pname eq "obj";
+    return "OBJ_TYPE_SHADER"              if $ptype =~ /GLhandleARB/;
     return "OBJ_TYPE_SHADER_ATI"          if $class eq "shader_ati" and $func =~ /^gl(Bind|GenFragment|Delete)/ and $pname =~ /^(id|ret)$/;
     return "OBJ_TYPE_SHADER_EXT"          if $class eq "shader_ext" and $func =~ /^gl(Bind|GenVertex|Delete)/ and $pname =~ /^(id|ret)$/;
     return "OBJ_TYPE_TEXTURE"             if $class eq "texture";
     return "OBJ_TYPE_TEXTURE"             if $func =~ /^glVDPAURegister/ and $pname eq "textureNames";
     return "OBJ_TYPE_TEXTURE"             if $func =~ /^gl(LGPU|Multicast|Async|)CopyImageSubData/ and $pname =~ /^(src|dst)Name$/;
-    return 0                              if $class eq "program/shader";
 
     return 0 if $class eq "Color";
     return 0 if $class eq "ColorIndexMask";
@@ -733,6 +755,7 @@ sub get_object_type($$$$)
     return 0 if $class eq "StencilMask";
     return 0 if $class eq "StencilValue";
     return 0 if $class eq "SelectName";
+    return 0 if $class eq "shader";
     return 0 if $class eq "sync";
     return 0 if $class eq "transform feedback";
     return 0 if $class eq "vertex array";
@@ -749,7 +772,7 @@ sub get_object_type($$$$)
     return 0 if $func eq "glDeleteCommandListsNV" and $pname =~ /^list/;
     return 0 if $func eq "glIsCommandListNV" and $pname =~ /^list/;
     return 0 if $func eq "glListDrawCommandsStatesClientNV" and $pname =~ /^list/;
-    return 0 if $ptype !~ /GLuint|GLhandleARB/;
+    return 0 if $ptype !~ /GLuint/;
     return 0 if $ptype =~ /GLuint \*/ and $pname =~ /^fences$/;
     return 0 if $pname eq "fence";
     return 0 if $pname eq "vkSemaphore";
@@ -770,13 +793,13 @@ sub get_object_type($$$$)
     return 0;
 }
 
-sub allocate_object_names($)
+sub allocate_object_names($$)
 {
-    my $name = shift;
+    my ($name, $type) = @_;
     my $ret = $name =~ /(APPLE|ARB|ATI|EXT|NV)$/ ? "TRUE" : "FALSE";
 
     return "TRUE" if has_extension( $name, "GL_EXT_direct_state_access" );
-    return "TRUE" if has_extension( $name, "GL_NV_path_rendering" );
+    return "TRUE" if has_extension( $name, "GL_NV_path_rendering" ) and $type eq "OBJ_TYPE_PATH";
     return $ret if $name =~ /^glBindBuffer/;
     return $ret if $name =~ /^glBindFramebuffer/;
     return $ret if $name =~ /^glBindProgram/;
@@ -851,7 +874,7 @@ sub generate_win_thunk($$)
             else
             {
                 my $return = is_void_func($func) ? "" : " args.ret";
-                my $alloc = allocate_object_names( $name );
+                my $alloc = allocate_object_names( $name, $map_type );
 
                 if ($len eq "1")
                 {
@@ -878,7 +901,7 @@ sub generate_win_thunk($$)
     }
     if (my $map_type = get_object_type( $name, $func_ret, "ret", get_arg_class( $func->[0] ) ))
     {
-        $post_call .= "    args.ret = put_context_object_range( $map_type, range, args.ret );\n" if $name =~ /^glGen/;
+        $post_call .= "    if (range > 0) args.ret = put_context_object_range( $map_type, range, args.ret );\n" if $name =~ /^glGen/;
         $post_call .= "    put_context_objects( $map_type, 1, &args.ret );\n" if $name =~ /^glCreate/;
     }
     $ret .= "    struct $name\_params args = {$params };\n";
diff --git a/dlls/opengl32/private.h b/dlls/opengl32/private.h
index b297325c49ee..f90db28d544b 100644
--- a/dlls/opengl32/private.h
+++ b/dlls/opengl32/private.h
@@ -57,6 +57,7 @@ enum object_type
     OBJ_TYPE_RENDERBUFFER,
     OBJ_TYPE_SAMPLER,
     OBJ_TYPE_SEMAPHORE,
+    OBJ_TYPE_SHADER,
     OBJ_TYPE_SHADER_ATI,
     OBJ_TYPE_SHADER_EXT,
     OBJ_TYPE_TEXTURE,
diff --git a/dlls/opengl32/tests/opengl.c b/dlls/opengl32/tests/opengl.c
index ca2c877c5338..89d6d072f480 100644
--- a/dlls/opengl32/tests/opengl.c
+++ b/dlls/opengl32/tests/opengl.c
@@ -1982,7 +1982,7 @@ static void test_sharelists(HDC winhdc)
         ok_ret( TRUE, wglShareLists( ctx1, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         /* object 1 is now valid there as well */
-        todo_wine ok_ret( TRUE, test->exists( obj1 ) );
+        ok_ret( TRUE, test->exists( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* object 1 is still valid in ctx2 */
@@ -2018,7 +2018,7 @@ static void test_sharelists(HDC winhdc)
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* cannot overwrite non-empty lists with some other */
-        todo_wine_if( i >= 14 ) ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) );
+        ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, wglShareLists( ctx2, ctx1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
@@ -2052,21 +2052,19 @@ static void test_sharelists(HDC winhdc)
         ok_u4( obj3, ==, 3 );
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, test->exists( obj1 ) );
+        ok_ret( TRUE, test->exists( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, test->exists( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, test->exists( obj3 ) );
+        ok_ret( TRUE, test->exists( obj3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* test deleting objects in shared contexts */
         delete_object( test->type, obj1 );
-        todo_wine_if( test->type == OBJ_PROGRAM_OBJECT || test->type == OBJ_PROGRAM_OBJECT_ARB ||
-                      test->type == OBJ_SHADER_OBJECT || test->type == OBJ_SHADER_OBJECT_ARB )
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine_if( i >= 14 ) ok_ret( FALSE, test->exists( obj1 ) );
+        ok_ret( FALSE, test->exists( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, test->exists( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
@@ -2077,7 +2075,7 @@ static void test_sharelists(HDC winhdc)
         ok_ret( TRUE, wglDeleteContext( ctx3 ) );
 
         /* objects are still valid after shared context destruction */
-        todo_wine_if( i >= 14 ) ok_ret( FALSE, test->exists( obj1 ) );
+        ok_ret( FALSE, test->exists( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, test->exists( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
@@ -2125,7 +2123,7 @@ static void test_sharelists(HDC winhdc)
         /* object 1 is now valid in ctx2 */
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) );
+        ok_ret( TRUE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* object 1 is not valid in ctx3 */
@@ -2138,13 +2136,13 @@ static void test_sharelists(HDC winhdc)
         ok_ret( TRUE, wglShareLists( ctx1, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         /* object 1 is now valid there as well */
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) );
+        ok_ret( TRUE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* object 1 is still valid in ctx2 */
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) );
+        ok_ret( TRUE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         ok_ret( TRUE, wglDeleteContext( ctx1 ) );
@@ -2175,7 +2173,7 @@ static void test_sharelists(HDC winhdc)
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* cannot overwrite non-empty lists with some other */
-        todo_wine ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) );
+        ok_ret( FALSE, wglShareLists( ctx1, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ret = wglShareLists( ctx2, ctx1 );
         ok( !ret || broken(nvidia), "wglShareLists returned %d\n", ret );
@@ -2192,7 +2190,7 @@ static void test_sharelists(HDC winhdc)
 
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) );
+        ok_ret( TRUE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, ext.glIsSync( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
@@ -2211,21 +2209,21 @@ static void test_sharelists(HDC winhdc)
         todo_wine ok_ptr( obj3, ==, (GLsync)3 );
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj1 ) );
+        ok_ret( TRUE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, ext.glIsSync( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( TRUE, ext.glIsSync( obj3 ) );
+        ok_ret( TRUE, ext.glIsSync( obj3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
 
         /* test deleting objects in shared contexts */
         ext.glDeleteSync( obj1 );
-        todo_wine ok_ret( GL_NO_ERROR, glGetError() );
+        ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( TRUE, wglMakeCurrent( winhdc, ctx2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( FALSE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( FALSE, ext.glIsSync( obj2 ) );
+        ok_ret( FALSE, ext.glIsSync( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( TRUE, ext.glIsSync( obj3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
@@ -2236,7 +2234,7 @@ static void test_sharelists(HDC winhdc)
         /* objects are still valid after shared context destruction */
         ok_ret( FALSE, ext.glIsSync( obj1 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
-        todo_wine ok_ret( FALSE, ext.glIsSync( obj2 ) );
+        ok_ret( FALSE, ext.glIsSync( obj2 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
         ok_ret( TRUE, ext.glIsSync( obj3 ) );
         ok_ret( GL_NO_ERROR, glGetError() );
diff --git a/dlls/opengl32/thunks.c b/dlls/opengl32/thunks.c
index 20f05d022300..7d4efe25ac79 100644
--- a/dlls/opengl32/thunks.c
+++ b/dlls/opengl32/thunks.c
@@ -831,7 +831,7 @@ GLuint WINAPI glGenLists( GLsizei range )
     NTSTATUS status;
     TRACE( "range %d\n", range );
     if ((status = UNIX_CALL( glGenLists, &args ))) WARN( "glGenLists returned %#lx\n", status );
-    args.ret = put_context_object_range( OBJ_TYPE_DISPLAY_LIST, range, args.ret );
+    if (range > 0) args.ret = put_context_object_range( OBJ_TYPE_DISPLAY_LIST, range, args.ret );
     return args.ret;
 }
 
@@ -2780,17 +2780,19 @@ static GLboolean WINAPI glAcquireKeyedMutexWin32EXT( GLuint memory, GLuint64 key
 
 static void WINAPI glActiveProgramEXT( GLuint program )
 {
-    struct glActiveProgramEXT_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glActiveProgramEXT_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glActiveProgramEXT, &args ))) WARN( "glActiveProgramEXT returned %#lx\n", status );
 }
 
 static void WINAPI glActiveShaderProgram( GLuint pipeline, GLuint program )
 {
-    struct glActiveShaderProgram_params args = { .teb = NtCurrentTeb(), .pipeline = pipeline, .program = program };
+    struct glActiveShaderProgram_params args = { .teb = NtCurrentTeb(), .pipeline = pipeline };
     NTSTATUS status;
     TRACE( "pipeline %d, program %d\n", pipeline, program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glActiveShaderProgram, &args ))) WARN( "glActiveShaderProgram returned %#lx\n", status );
 }
 
@@ -2820,9 +2822,10 @@ static void WINAPI glActiveTextureARB( GLenum texture )
 
 static void WINAPI glActiveVaryingNV( GLuint program, const GLchar *name )
 {
-    struct glActiveVaryingNV_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glActiveVaryingNV_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glActiveVaryingNV, &args ))) WARN( "glActiveVaryingNV returned %#lx\n", status );
 }
 
@@ -2981,17 +2984,21 @@ static void WINAPI glAsyncMarkerSGIX( GLuint marker )
 
 static void WINAPI glAttachObjectARB( GLhandleARB containerObj, GLhandleARB obj )
 {
-    struct glAttachObjectARB_params args = { .teb = NtCurrentTeb(), .containerObj = containerObj, .obj = obj };
+    struct glAttachObjectARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "containerObj %d, obj %d\n", containerObj, obj );
+    args.containerObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &containerObj );
+    args.obj = *map_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glAttachObjectARB, &args ))) WARN( "glAttachObjectARB returned %#lx\n", status );
 }
 
 static void WINAPI glAttachShader( GLuint program, GLuint shader )
 {
-    struct glAttachShader_params args = { .teb = NtCurrentTeb(), .program = program, .shader = shader };
+    struct glAttachShader_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d, shader %d\n", program, shader );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glAttachShader, &args ))) WARN( "glAttachShader returned %#lx\n", status );
 }
 
@@ -3117,17 +3124,19 @@ static void WINAPI glBeginVideoCaptureNV( GLuint video_capture_slot )
 
 static void WINAPI glBindAttribLocation( GLuint program, GLuint index, const GLchar *name )
 {
-    struct glBindAttribLocation_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .name = name };
+    struct glBindAttribLocation_params args = { .teb = NtCurrentTeb(), .index = index, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, name %p\n", program, index, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glBindAttribLocation, &args ))) WARN( "glBindAttribLocation returned %#lx\n", status );
 }
 
 static void WINAPI glBindAttribLocationARB( GLhandleARB programObj, GLuint index, const GLcharARB *name )
 {
-    struct glBindAttribLocationARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .index = index, .name = name };
+    struct glBindAttribLocationARB_params args = { .teb = NtCurrentTeb(), .index = index, .name = name };
     NTSTATUS status;
     TRACE( "programObj %d, index %d, name %p\n", programObj, index, name );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glBindAttribLocationARB, &args ))) WARN( "glBindAttribLocationARB returned %#lx\n", status );
 }
 
@@ -3259,25 +3268,28 @@ static void WINAPI glBindBuffersRange( GLenum target, GLuint first, GLsizei coun
 
 static void WINAPI glBindFragDataLocation( GLuint program, GLuint color, const GLchar *name )
 {
-    struct glBindFragDataLocation_params args = { .teb = NtCurrentTeb(), .program = program, .color = color, .name = name };
+    struct glBindFragDataLocation_params args = { .teb = NtCurrentTeb(), .color = color, .name = name };
     NTSTATUS status;
     TRACE( "program %d, color %d, name %p\n", program, color, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glBindFragDataLocation, &args ))) WARN( "glBindFragDataLocation returned %#lx\n", status );
 }
 
 static void WINAPI glBindFragDataLocationEXT( GLuint program, GLuint color, const GLchar *name )
 {
-    struct glBindFragDataLocationEXT_params args = { .teb = NtCurrentTeb(), .program = program, .color = color, .name = name };
+    struct glBindFragDataLocationEXT_params args = { .teb = NtCurrentTeb(), .color = color, .name = name };
     NTSTATUS status;
     TRACE( "program %d, color %d, name %p\n", program, color, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glBindFragDataLocationEXT, &args ))) WARN( "glBindFragDataLocationEXT returned %#lx\n", status );
 }
 
 static void WINAPI glBindFragDataLocationIndexed( GLuint program, GLuint colorNumber, GLuint index, const GLchar *name )
 {
-    struct glBindFragDataLocationIndexed_params args = { .teb = NtCurrentTeb(), .program = program, .colorNumber = colorNumber, .index = index, .name = name };
+    struct glBindFragDataLocationIndexed_params args = { .teb = NtCurrentTeb(), .colorNumber = colorNumber, .index = index, .name = name };
     NTSTATUS status;
     TRACE( "program %d, colorNumber %d, index %d, name %p\n", program, colorNumber, index, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glBindFragDataLocationIndexed, &args ))) WARN( "glBindFragDataLocationIndexed returned %#lx\n", status );
 }
 
@@ -4806,25 +4818,28 @@ static void WINAPI glCompileCommandListNV( GLuint list )
 
 static void WINAPI glCompileShader( GLuint shader )
 {
-    struct glCompileShader_params args = { .teb = NtCurrentTeb(), .shader = shader };
+    struct glCompileShader_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "shader %d\n", shader );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glCompileShader, &args ))) WARN( "glCompileShader returned %#lx\n", status );
 }
 
 static void WINAPI glCompileShaderARB( GLhandleARB shaderObj )
 {
-    struct glCompileShaderARB_params args = { .teb = NtCurrentTeb(), .shaderObj = shaderObj };
+    struct glCompileShaderARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "shaderObj %d\n", shaderObj );
+    args.shaderObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &shaderObj );
     if ((status = UNIX_CALL( glCompileShaderARB, &args ))) WARN( "glCompileShaderARB returned %#lx\n", status );
 }
 
 static void WINAPI glCompileShaderIncludeARB( GLuint shader, GLsizei count, const GLchar *const*path, const GLint *length )
 {
-    struct glCompileShaderIncludeARB_params args = { .teb = NtCurrentTeb(), .shader = shader, .count = count, .path = path, .length = length };
+    struct glCompileShaderIncludeARB_params args = { .teb = NtCurrentTeb(), .count = count, .path = path, .length = length };
     NTSTATUS status;
     TRACE( "shader %d, count %d, path %p, length %p\n", shader, count, path, length );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glCompileShaderIncludeARB, &args ))) WARN( "glCompileShaderIncludeARB returned %#lx\n", status );
 }
 
@@ -5571,6 +5586,7 @@ static GLuint WINAPI glCreateProgram(void)
     NTSTATUS status;
     TRACE( "\n" );
     if ((status = UNIX_CALL( glCreateProgram, &args ))) WARN( "glCreateProgram returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5580,6 +5596,7 @@ static GLhandleARB WINAPI glCreateProgramObjectARB(void)
     NTSTATUS status;
     TRACE( "\n" );
     if ((status = UNIX_CALL( glCreateProgramObjectARB, &args ))) WARN( "glCreateProgramObjectARB returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5641,6 +5658,7 @@ static GLuint WINAPI glCreateShader( GLenum type )
     NTSTATUS status;
     TRACE( "type %d\n", type );
     if ((status = UNIX_CALL( glCreateShader, &args ))) WARN( "glCreateShader returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5650,6 +5668,7 @@ static GLhandleARB WINAPI glCreateShaderObjectARB( GLenum shaderType )
     NTSTATUS status;
     TRACE( "shaderType %d\n", shaderType );
     if ((status = UNIX_CALL( glCreateShaderObjectARB, &args ))) WARN( "glCreateShaderObjectARB returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5659,6 +5678,7 @@ static GLuint WINAPI glCreateShaderProgramEXT( GLenum type, const GLchar *string
     NTSTATUS status;
     TRACE( "type %d, string %p\n", type, string );
     if ((status = UNIX_CALL( glCreateShaderProgramEXT, &args ))) WARN( "glCreateShaderProgramEXT returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5668,6 +5688,7 @@ static GLuint WINAPI glCreateShaderProgramv( GLenum type, GLsizei count, const G
     NTSTATUS status;
     TRACE( "type %d, count %d, strings %p\n", type, count, strings );
     if ((status = UNIX_CALL( glCreateShaderProgramv, &args ))) WARN( "glCreateShaderProgramv returned %#lx\n", status );
+    put_context_objects( OBJ_TYPE_SHADER, 1, &args.ret );
     return args.ret;
 }
 
@@ -5951,9 +5972,10 @@ static void WINAPI glDeleteNamesAMD( GLenum identifier, GLuint num, const GLuint
 
 static void WINAPI glDeleteObjectARB( GLhandleARB obj )
 {
-    struct glDeleteObjectARB_params args = { .teb = NtCurrentTeb(), .obj = obj };
+    struct glDeleteObjectARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "obj %d\n", obj );
+    args.obj = *del_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glDeleteObjectARB, &args ))) WARN( "glDeleteObjectARB returned %#lx\n", status );
 }
 
@@ -6001,9 +6023,10 @@ static void WINAPI glDeletePerfQueryINTEL( GLuint queryHandle )
 
 static void WINAPI glDeleteProgram( GLuint program )
 {
-    struct glDeleteProgram_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glDeleteProgram_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *del_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glDeleteProgram, &args ))) WARN( "glDeleteProgram returned %#lx\n", status );
 }
 
@@ -6113,9 +6136,10 @@ static void WINAPI glDeleteSemaphoresEXT( GLsizei n, const GLuint *semaphores )
 
 static void WINAPI glDeleteShader( GLuint shader )
 {
-    struct glDeleteShader_params args = { .teb = NtCurrentTeb(), .shader = shader };
+    struct glDeleteShader_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "shader %d\n", shader );
+    args.shader = *del_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glDeleteShader, &args ))) WARN( "glDeleteShader returned %#lx\n", status );
 }
 
@@ -6270,17 +6294,21 @@ static void WINAPI glDepthRangexOES( GLfixed n, GLfixed f )
 
 static void WINAPI glDetachObjectARB( GLhandleARB containerObj, GLhandleARB attachedObj )
 {
-    struct glDetachObjectARB_params args = { .teb = NtCurrentTeb(), .containerObj = containerObj, .attachedObj = attachedObj };
+    struct glDetachObjectARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "containerObj %d, attachedObj %d\n", containerObj, attachedObj );
+    args.containerObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &containerObj );
+    args.attachedObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &attachedObj );
     if ((status = UNIX_CALL( glDetachObjectARB, &args ))) WARN( "glDetachObjectARB returned %#lx\n", status );
 }
 
 static void WINAPI glDetachShader( GLuint program, GLuint shader )
 {
-    struct glDetachShader_params args = { .teb = NtCurrentTeb(), .program = program, .shader = shader };
+    struct glDetachShader_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d, shader %d\n", program, shader );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glDetachShader, &args ))) WARN( "glDetachShader returned %#lx\n", status );
 }
 
@@ -7816,7 +7844,7 @@ static GLuint WINAPI glGenFragmentShadersATI( GLuint range )
     NTSTATUS status;
     TRACE( "range %d\n", range );
     if ((status = UNIX_CALL( glGenFragmentShadersATI, &args ))) WARN( "glGenFragmentShadersATI returned %#lx\n", status );
-    args.ret = put_context_object_range( OBJ_TYPE_SHADER_ATI, range, args.ret );
+    if (range > 0) args.ret = put_context_object_range( OBJ_TYPE_SHADER_ATI, range, args.ret );
     return args.ret;
 }
 
@@ -7860,7 +7888,7 @@ static GLuint WINAPI glGenPathsNV( GLsizei range )
     NTSTATUS status;
     TRACE( "range %d\n", range );
     if ((status = UNIX_CALL( glGenPathsNV, &args ))) WARN( "glGenPathsNV returned %#lx\n", status );
-    args.ret = put_context_object_range( OBJ_TYPE_PATH, range, args.ret );
+    if (range > 0) args.ret = put_context_object_range( OBJ_TYPE_PATH, range, args.ret );
     return args.ret;
 }
 
@@ -8014,7 +8042,7 @@ static GLuint WINAPI glGenVertexShadersEXT( GLuint range )
     NTSTATUS status;
     TRACE( "range %d\n", range );
     if ((status = UNIX_CALL( glGenVertexShadersEXT, &args ))) WARN( "glGenVertexShadersEXT returned %#lx\n", status );
-    args.ret = put_context_object_range( OBJ_TYPE_SHADER_EXT, range, args.ret );
+    if (range > 0) args.ret = put_context_object_range( OBJ_TYPE_SHADER_EXT, range, args.ret );
     return args.ret;
 }
 
@@ -8063,105 +8091,118 @@ static void WINAPI glGenerateTextureMipmapEXT( GLuint texture, GLenum target )
 
 static void WINAPI glGetActiveAtomicCounterBufferiv( GLuint program, GLuint bufferIndex, GLenum pname, GLint *params )
 {
-    struct glGetActiveAtomicCounterBufferiv_params args = { .teb = NtCurrentTeb(), .program = program, .bufferIndex = bufferIndex, .pname = pname, .params = params };
+    struct glGetActiveAtomicCounterBufferiv_params args = { .teb = NtCurrentTeb(), .bufferIndex = bufferIndex, .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "program %d, bufferIndex %d, pname %d, params %p\n", program, bufferIndex, pname, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveAtomicCounterBufferiv, &args ))) WARN( "glGetActiveAtomicCounterBufferiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveAttrib( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 {
-    struct glGetActiveAttrib_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
+    struct glGetActiveAttrib_params args = { .teb = NtCurrentTeb(), .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, bufSize %d, length %p, size %p, type %p, name %p\n", program, index, bufSize, length, size, type, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveAttrib, &args ))) WARN( "glGetActiveAttrib returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveAttribARB( GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name )
 {
-    struct glGetActiveAttribARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .index = index, .maxLength = maxLength, .length = length, .size = size, .type = type, .name = name };
+    struct glGetActiveAttribARB_params args = { .teb = NtCurrentTeb(), .index = index, .maxLength = maxLength, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "programObj %d, index %d, maxLength %d, length %p, size %p, type %p, name %p\n", programObj, index, maxLength, length, size, type, name );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetActiveAttribARB, &args ))) WARN( "glGetActiveAttribARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveSubroutineName( GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name )
 {
-    struct glGetActiveSubroutineName_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .index = index, .bufSize = bufSize, .length = length, .name = name };
+    struct glGetActiveSubroutineName_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .index = index, .bufSize = bufSize, .length = length, .name = name };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, index %d, bufSize %d, length %p, name %p\n", program, shadertype, index, bufSize, length, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveSubroutineName, &args ))) WARN( "glGetActiveSubroutineName returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveSubroutineUniformName( GLuint program, GLenum shadertype, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name )
 {
-    struct glGetActiveSubroutineUniformName_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .index = index, .bufSize = bufSize, .length = length, .name = name };
+    struct glGetActiveSubroutineUniformName_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .index = index, .bufSize = bufSize, .length = length, .name = name };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, index %d, bufSize %d, length %p, name %p\n", program, shadertype, index, bufSize, length, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveSubroutineUniformName, &args ))) WARN( "glGetActiveSubroutineUniformName returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveSubroutineUniformiv( GLuint program, GLenum shadertype, GLuint index, GLenum pname, GLint *values )
 {
-    struct glGetActiveSubroutineUniformiv_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .index = index, .pname = pname, .values = values };
+    struct glGetActiveSubroutineUniformiv_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .index = index, .pname = pname, .values = values };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, index %d, pname %d, values %p\n", program, shadertype, index, pname, values );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveSubroutineUniformiv, &args ))) WARN( "glGetActiveSubroutineUniformiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniform( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 {
-    struct glGetActiveUniform_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
+    struct glGetActiveUniform_params args = { .teb = NtCurrentTeb(), .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, bufSize %d, length %p, size %p, type %p, name %p\n", program, index, bufSize, length, size, type, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveUniform, &args ))) WARN( "glGetActiveUniform returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniformARB( GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLenum *type, GLcharARB *name )
 {
-    struct glGetActiveUniformARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .index = index, .maxLength = maxLength, .length = length, .size = size, .type = type, .name = name };
+    struct glGetActiveUniformARB_params args = { .teb = NtCurrentTeb(), .index = index, .maxLength = maxLength, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "programObj %d, index %d, maxLength %d, length %p, size %p, type %p, name %p\n", programObj, index, maxLength, length, size, type, name );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetActiveUniformARB, &args ))) WARN( "glGetActiveUniformARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniformBlockName( GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName )
 {
-    struct glGetActiveUniformBlockName_params args = { .teb = NtCurrentTeb(), .program = program, .uniformBlockIndex = uniformBlockIndex, .bufSize = bufSize, .length = length, .uniformBlockName = uniformBlockName };
+    struct glGetActiveUniformBlockName_params args = { .teb = NtCurrentTeb(), .uniformBlockIndex = uniformBlockIndex, .bufSize = bufSize, .length = length, .uniformBlockName = uniformBlockName };
     NTSTATUS status;
     TRACE( "program %d, uniformBlockIndex %d, bufSize %d, length %p, uniformBlockName %p\n", program, uniformBlockIndex, bufSize, length, uniformBlockName );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveUniformBlockName, &args ))) WARN( "glGetActiveUniformBlockName returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniformBlockiv( GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params )
 {
-    struct glGetActiveUniformBlockiv_params args = { .teb = NtCurrentTeb(), .program = program, .uniformBlockIndex = uniformBlockIndex, .pname = pname, .params = params };
+    struct glGetActiveUniformBlockiv_params args = { .teb = NtCurrentTeb(), .uniformBlockIndex = uniformBlockIndex, .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "program %d, uniformBlockIndex %d, pname %d, params %p\n", program, uniformBlockIndex, pname, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveUniformBlockiv, &args ))) WARN( "glGetActiveUniformBlockiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniformName( GLuint program, GLuint uniformIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformName )
 {
-    struct glGetActiveUniformName_params args = { .teb = NtCurrentTeb(), .program = program, .uniformIndex = uniformIndex, .bufSize = bufSize, .length = length, .uniformName = uniformName };
+    struct glGetActiveUniformName_params args = { .teb = NtCurrentTeb(), .uniformIndex = uniformIndex, .bufSize = bufSize, .length = length, .uniformName = uniformName };
     NTSTATUS status;
     TRACE( "program %d, uniformIndex %d, bufSize %d, length %p, uniformName %p\n", program, uniformIndex, bufSize, length, uniformName );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveUniformName, &args ))) WARN( "glGetActiveUniformName returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveUniformsiv( GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params )
 {
-    struct glGetActiveUniformsiv_params args = { .teb = NtCurrentTeb(), .program = program, .uniformCount = uniformCount, .uniformIndices = uniformIndices, .pname = pname, .params = params };
+    struct glGetActiveUniformsiv_params args = { .teb = NtCurrentTeb(), .uniformCount = uniformCount, .uniformIndices = uniformIndices, .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "program %d, uniformCount %d, uniformIndices %p, pname %d, params %p\n", program, uniformCount, uniformIndices, pname, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveUniformsiv, &args ))) WARN( "glGetActiveUniformsiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetActiveVaryingNV( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name )
 {
-    struct glGetActiveVaryingNV_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
+    struct glGetActiveVaryingNV_params args = { .teb = NtCurrentTeb(), .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, bufSize %d, length %p, size %p, type %p, name %p\n", program, index, bufSize, length, size, type, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetActiveVaryingNV, &args ))) WARN( "glGetActiveVaryingNV returned %#lx\n", status );
 }
 
@@ -8183,34 +8224,46 @@ static void WINAPI glGetArrayObjectivATI( GLenum array, GLenum pname, GLint *par
 
 static void WINAPI glGetAttachedObjectsARB( GLhandleARB containerObj, GLsizei maxCount, GLsizei *count, GLhandleARB *obj )
 {
-    struct glGetAttachedObjectsARB_params args = { .teb = NtCurrentTeb(), .containerObj = containerObj, .maxCount = maxCount, .count = count, .obj = obj };
+    GLuint obj_buf[64], *obj_tmp;
+    struct glGetAttachedObjectsARB_params args = { .teb = NtCurrentTeb(), .maxCount = maxCount, .count = count };
     NTSTATUS status;
     TRACE( "containerObj %d, maxCount %d, count %p, obj %p\n", containerObj, maxCount, count, obj );
+    args.containerObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &containerObj );
+    obj_tmp = maxCount > 0 ? memdup_objects( maxCount, obj, obj_buf, ARRAY_SIZE(obj_buf) ) : NULL;
+    args.obj = maxCount > 0 ? map_context_objects( OBJ_TYPE_SHADER, maxCount, obj_tmp ) : NULL;
     if ((status = UNIX_CALL( glGetAttachedObjectsARB, &args ))) WARN( "glGetAttachedObjectsARB returned %#lx\n", status );
+    if (obj_tmp != obj_buf) free( obj_tmp );
 }
 
 static void WINAPI glGetAttachedShaders( GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders )
 {
-    struct glGetAttachedShaders_params args = { .teb = NtCurrentTeb(), .program = program, .maxCount = maxCount, .count = count, .shaders = shaders };
+    GLuint shaders_buf[64], *shaders_tmp;
+    struct glGetAttachedShaders_params args = { .teb = NtCurrentTeb(), .maxCount = maxCount, .count = count };
     NTSTATUS status;
     TRACE( "program %d, maxCount %d, count %p, shaders %p\n", program, maxCount, count, shaders );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
+    shaders_tmp = maxCount > 0 ? memdup_objects( maxCount, shaders, shaders_buf, ARRAY_SIZE(shaders_buf) ) : NULL;
+    args.shaders = maxCount > 0 ? map_context_objects( OBJ_TYPE_SHADER, maxCount, shaders_tmp ) : NULL;
     if ((status = UNIX_CALL( glGetAttachedShaders, &args ))) WARN( "glGetAttachedShaders returned %#lx\n", status );
+    if (shaders_tmp != shaders_buf) free( shaders_tmp );
 }
 
 static GLint WINAPI glGetAttribLocation( GLuint program, const GLchar *name )
 {
-    struct glGetAttribLocation_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetAttribLocation_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetAttribLocation, &args ))) WARN( "glGetAttribLocation returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetAttribLocationARB( GLhandleARB programObj, const GLcharARB *name )
 {
-    struct glGetAttribLocationARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .name = name };
+    struct glGetAttribLocationARB_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "programObj %d, name %p\n", programObj, name );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetAttribLocationARB, &args ))) WARN( "glGetAttribLocationARB returned %#lx\n", status );
     return args.ret;
 }
@@ -8725,27 +8778,30 @@ static void WINAPI glGetFogFuncSGIS( GLfloat *points )
 
 static GLint WINAPI glGetFragDataIndex( GLuint program, const GLchar *name )
 {
-    struct glGetFragDataIndex_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetFragDataIndex_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetFragDataIndex, &args ))) WARN( "glGetFragDataIndex returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetFragDataLocation( GLuint program, const GLchar *name )
 {
-    struct glGetFragDataLocation_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetFragDataLocation_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetFragDataLocation, &args ))) WARN( "glGetFragDataLocation returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetFragDataLocationEXT( GLuint program, const GLchar *name )
 {
-    struct glGetFragDataLocationEXT_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetFragDataLocationEXT_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetFragDataLocationEXT, &args ))) WARN( "glGetFragDataLocationEXT returned %#lx\n", status );
     return args.ret;
 }
@@ -8945,9 +9001,10 @@ static void WINAPI glGetImageTransformParameterivHP( GLenum target, GLenum pname
 
 static void WINAPI glGetInfoLogARB( GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *infoLog )
 {
-    struct glGetInfoLogARB_params args = { .teb = NtCurrentTeb(), .obj = obj, .maxLength = maxLength, .length = length, .infoLog = infoLog };
+    struct glGetInfoLogARB_params args = { .teb = NtCurrentTeb(), .maxLength = maxLength, .length = length, .infoLog = infoLog };
     NTSTATUS status;
     TRACE( "obj %d, maxLength %d, length %p, infoLog %p\n", obj, maxLength, length, infoLog );
+    args.obj = *map_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glGetInfoLogARB, &args ))) WARN( "glGetInfoLogARB returned %#lx\n", status );
 }
 
@@ -9614,9 +9671,10 @@ static void WINAPI glGetObjectLabelEXT( GLenum type, GLuint object, GLsizei bufS
 
 static void WINAPI glGetObjectParameterfvARB( GLhandleARB obj, GLenum pname, GLfloat *params )
 {
-    struct glGetObjectParameterfvARB_params args = { .teb = NtCurrentTeb(), .obj = obj, .pname = pname, .params = params };
+    struct glGetObjectParameterfvARB_params args = { .teb = NtCurrentTeb(), .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "obj %d, pname %d, params %p\n", obj, pname, params );
+    args.obj = *map_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glGetObjectParameterfvARB, &args ))) WARN( "glGetObjectParameterfvARB returned %#lx\n", status );
 }
 
@@ -9630,9 +9688,10 @@ static void WINAPI glGetObjectParameterivAPPLE( GLenum objectType, GLuint name,
 
 static void WINAPI glGetObjectParameterivARB( GLhandleARB obj, GLenum pname, GLint *params )
 {
-    struct glGetObjectParameterivARB_params args = { .teb = NtCurrentTeb(), .obj = obj, .pname = pname, .params = params };
+    struct glGetObjectParameterivARB_params args = { .teb = NtCurrentTeb(), .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "obj %d, pname %d, params %p\n", obj, pname, params );
+    args.obj = *map_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glGetObjectParameterivARB, &args ))) WARN( "glGetObjectParameterivARB returned %#lx\n", status );
 }
 
@@ -9935,9 +9994,10 @@ static void WINAPI glGetPointervEXT( GLenum pname, void **params )
 
 static void WINAPI glGetProgramBinary( GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary )
 {
-    struct glGetProgramBinary_params args = { .teb = NtCurrentTeb(), .program = program, .bufSize = bufSize, .length = length, .binaryFormat = binaryFormat, .binary = binary };
+    struct glGetProgramBinary_params args = { .teb = NtCurrentTeb(), .bufSize = bufSize, .length = length, .binaryFormat = binaryFormat, .binary = binary };
     NTSTATUS status;
     TRACE( "program %d, bufSize %d, length %p, binaryFormat %p, binary %p\n", program, bufSize, length, binaryFormat, binary );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramBinary, &args ))) WARN( "glGetProgramBinary returned %#lx\n", status );
 }
 
@@ -9975,17 +10035,19 @@ static void WINAPI glGetProgramEnvParameterfvARB( GLenum target, GLuint index, G
 
 static void WINAPI glGetProgramInfoLog( GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog )
 {
-    struct glGetProgramInfoLog_params args = { .teb = NtCurrentTeb(), .program = program, .bufSize = bufSize, .length = length, .infoLog = infoLog };
+    struct glGetProgramInfoLog_params args = { .teb = NtCurrentTeb(), .bufSize = bufSize, .length = length, .infoLog = infoLog };
     NTSTATUS status;
     TRACE( "program %d, bufSize %d, length %p, infoLog %p\n", program, bufSize, length, infoLog );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramInfoLog, &args ))) WARN( "glGetProgramInfoLog returned %#lx\n", status );
 }
 
 static void WINAPI glGetProgramInterfaceiv( GLuint program, GLenum programInterface, GLenum pname, GLint *params )
 {
-    struct glGetProgramInterfaceiv_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .pname = pname, .params = params };
+    struct glGetProgramInterfaceiv_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, pname %d, params %p\n", program, programInterface, pname, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramInterfaceiv, &args ))) WARN( "glGetProgramInterfaceiv returned %#lx\n", status );
 }
 
@@ -10075,60 +10137,67 @@ static void WINAPI glGetProgramPipelineiv( GLuint pipeline, GLenum pname, GLint
 
 static GLuint WINAPI glGetProgramResourceIndex( GLuint program, GLenum programInterface, const GLchar *name )
 {
-    struct glGetProgramResourceIndex_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .name = name };
+    struct glGetProgramResourceIndex_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .name = name };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, name %p\n", program, programInterface, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourceIndex, &args ))) WARN( "glGetProgramResourceIndex returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetProgramResourceLocation( GLuint program, GLenum programInterface, const GLchar *name )
 {
-    struct glGetProgramResourceLocation_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .name = name };
+    struct glGetProgramResourceLocation_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .name = name };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, name %p\n", program, programInterface, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourceLocation, &args ))) WARN( "glGetProgramResourceLocation returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetProgramResourceLocationIndex( GLuint program, GLenum programInterface, const GLchar *name )
 {
-    struct glGetProgramResourceLocationIndex_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .name = name };
+    struct glGetProgramResourceLocationIndex_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .name = name };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, name %p\n", program, programInterface, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourceLocationIndex, &args ))) WARN( "glGetProgramResourceLocationIndex returned %#lx\n", status );
     return args.ret;
 }
 
 static void WINAPI glGetProgramResourceName( GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei *length, GLchar *name )
 {
-    struct glGetProgramResourceName_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .index = index, .bufSize = bufSize, .length = length, .name = name };
+    struct glGetProgramResourceName_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .index = index, .bufSize = bufSize, .length = length, .name = name };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, index %d, bufSize %d, length %p, name %p\n", program, programInterface, index, bufSize, length, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourceName, &args ))) WARN( "glGetProgramResourceName returned %#lx\n", status );
 }
 
 static void WINAPI glGetProgramResourcefvNV( GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLfloat *params )
 {
-    struct glGetProgramResourcefvNV_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .index = index, .propCount = propCount, .props = props, .count = count, .length = length, .params = params };
+    struct glGetProgramResourcefvNV_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .index = index, .propCount = propCount, .props = props, .count = count, .length = length, .params = params };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, index %d, propCount %d, props %p, count %d, length %p, params %p\n", program, programInterface, index, propCount, props, count, length, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourcefvNV, &args ))) WARN( "glGetProgramResourcefvNV returned %#lx\n", status );
 }
 
 static void WINAPI glGetProgramResourceiv( GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei count, GLsizei *length, GLint *params )
 {
-    struct glGetProgramResourceiv_params args = { .teb = NtCurrentTeb(), .program = program, .programInterface = programInterface, .index = index, .propCount = propCount, .props = props, .count = count, .length = length, .params = params };
+    struct glGetProgramResourceiv_params args = { .teb = NtCurrentTeb(), .programInterface = programInterface, .index = index, .propCount = propCount, .props = props, .count = count, .length = length, .params = params };
     NTSTATUS status;
     TRACE( "program %d, programInterface %d, index %d, propCount %d, props %p, count %d, length %p, params %p\n", program, programInterface, index, propCount, props, count, length, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramResourceiv, &args ))) WARN( "glGetProgramResourceiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetProgramStageiv( GLuint program, GLenum shadertype, GLenum pname, GLint *values )
 {
-    struct glGetProgramStageiv_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .pname = pname, .values = values };
+    struct glGetProgramStageiv_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .pname = pname, .values = values };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, pname %d, values %p\n", program, shadertype, pname, values );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramStageiv, &args ))) WARN( "glGetProgramStageiv returned %#lx\n", status );
 }
 
@@ -10159,9 +10228,10 @@ static void WINAPI glGetProgramSubroutineParameteruivNV( GLenum target, GLuint i
 
 static void WINAPI glGetProgramiv( GLuint program, GLenum pname, GLint *params )
 {
-    struct glGetProgramiv_params args = { .teb = NtCurrentTeb(), .program = program, .pname = pname, .params = params };
+    struct glGetProgramiv_params args = { .teb = NtCurrentTeb(), .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "program %d, pname %d, params %p\n", program, pname, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetProgramiv, &args ))) WARN( "glGetProgramiv returned %#lx\n", status );
 }
 
@@ -10396,9 +10466,10 @@ static void WINAPI glGetSeparableFilterEXT( GLenum target, GLenum format, GLenum
 
 static void WINAPI glGetShaderInfoLog( GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog )
 {
-    struct glGetShaderInfoLog_params args = { .teb = NtCurrentTeb(), .shader = shader, .bufSize = bufSize, .length = length, .infoLog = infoLog };
+    struct glGetShaderInfoLog_params args = { .teb = NtCurrentTeb(), .bufSize = bufSize, .length = length, .infoLog = infoLog };
     NTSTATUS status;
     TRACE( "shader %d, bufSize %d, length %p, infoLog %p\n", shader, bufSize, length, infoLog );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glGetShaderInfoLog, &args ))) WARN( "glGetShaderInfoLog returned %#lx\n", status );
 }
 
@@ -10412,25 +10483,28 @@ static void WINAPI glGetShaderPrecisionFormat( GLenum shadertype, GLenum precisi
 
 static void WINAPI glGetShaderSource( GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *source )
 {
-    struct glGetShaderSource_params args = { .teb = NtCurrentTeb(), .shader = shader, .bufSize = bufSize, .length = length, .source = source };
+    struct glGetShaderSource_params args = { .teb = NtCurrentTeb(), .bufSize = bufSize, .length = length, .source = source };
     NTSTATUS status;
     TRACE( "shader %d, bufSize %d, length %p, source %p\n", shader, bufSize, length, source );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glGetShaderSource, &args ))) WARN( "glGetShaderSource returned %#lx\n", status );
 }
 
 static void WINAPI glGetShaderSourceARB( GLhandleARB obj, GLsizei maxLength, GLsizei *length, GLcharARB *source )
 {
-    struct glGetShaderSourceARB_params args = { .teb = NtCurrentTeb(), .obj = obj, .maxLength = maxLength, .length = length, .source = source };
+    struct glGetShaderSourceARB_params args = { .teb = NtCurrentTeb(), .maxLength = maxLength, .length = length, .source = source };
     NTSTATUS status;
     TRACE( "obj %d, maxLength %d, length %p, source %p\n", obj, maxLength, length, source );
+    args.obj = *map_context_objects( OBJ_TYPE_SHADER, 1, &obj );
     if ((status = UNIX_CALL( glGetShaderSourceARB, &args ))) WARN( "glGetShaderSourceARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetShaderiv( GLuint shader, GLenum pname, GLint *params )
 {
-    struct glGetShaderiv_params args = { .teb = NtCurrentTeb(), .shader = shader, .pname = pname, .params = params };
+    struct glGetShaderiv_params args = { .teb = NtCurrentTeb(), .pname = pname, .params = params };
     NTSTATUS status;
     TRACE( "shader %d, pname %d, params %p\n", shader, pname, params );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glGetShaderiv, &args ))) WARN( "glGetShaderiv returned %#lx\n", status );
 }
 
@@ -10469,18 +10543,20 @@ static GLushort WINAPI glGetStageIndexNV( GLenum shadertype )
 
 static GLuint WINAPI glGetSubroutineIndex( GLuint program, GLenum shadertype, const GLchar *name )
 {
-    struct glGetSubroutineIndex_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .name = name };
+    struct glGetSubroutineIndex_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .name = name };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, name %p\n", program, shadertype, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetSubroutineIndex, &args ))) WARN( "glGetSubroutineIndex returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetSubroutineUniformLocation( GLuint program, GLenum shadertype, const GLchar *name )
 {
-    struct glGetSubroutineUniformLocation_params args = { .teb = NtCurrentTeb(), .program = program, .shadertype = shadertype, .name = name };
+    struct glGetSubroutineUniformLocation_params args = { .teb = NtCurrentTeb(), .shadertype = shadertype, .name = name };
     NTSTATUS status;
     TRACE( "program %d, shadertype %d, name %p\n", program, shadertype, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetSubroutineUniformLocation, &args ))) WARN( "glGetSubroutineUniformLocation returned %#lx\n", status );
     return args.ret;
 }
@@ -10810,25 +10886,28 @@ static void WINAPI glGetTrackMatrixivNV( GLenum target, GLuint address, GLenum p
 
 static void WINAPI glGetTransformFeedbackVarying( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name )
 {
-    struct glGetTransformFeedbackVarying_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
+    struct glGetTransformFeedbackVarying_params args = { .teb = NtCurrentTeb(), .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, bufSize %d, length %p, size %p, type %p, name %p\n", program, index, bufSize, length, size, type, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetTransformFeedbackVarying, &args ))) WARN( "glGetTransformFeedbackVarying returned %#lx\n", status );
 }
 
 static void WINAPI glGetTransformFeedbackVaryingEXT( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name )
 {
-    struct glGetTransformFeedbackVaryingEXT_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
+    struct glGetTransformFeedbackVaryingEXT_params args = { .teb = NtCurrentTeb(), .index = index, .bufSize = bufSize, .length = length, .size = size, .type = type, .name = name };
     NTSTATUS status;
     TRACE( "program %d, index %d, bufSize %d, length %p, size %p, type %p, name %p\n", program, index, bufSize, length, size, type, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetTransformFeedbackVaryingEXT, &args ))) WARN( "glGetTransformFeedbackVaryingEXT returned %#lx\n", status );
 }
 
 static void WINAPI glGetTransformFeedbackVaryingNV( GLuint program, GLuint index, GLint *location )
 {
-    struct glGetTransformFeedbackVaryingNV_params args = { .teb = NtCurrentTeb(), .program = program, .index = index, .location = location };
+    struct glGetTransformFeedbackVaryingNV_params args = { .teb = NtCurrentTeb(), .index = index, .location = location };
     NTSTATUS status;
     TRACE( "program %d, index %d, location %p\n", program, index, location );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetTransformFeedbackVaryingNV, &args ))) WARN( "glGetTransformFeedbackVaryingNV returned %#lx\n", status );
 }
 
@@ -10864,53 +10943,59 @@ static void WINAPI glGetTransformFeedbackiv( GLuint xfb, GLenum pname, GLint *pa
 
 static GLuint WINAPI glGetUniformBlockIndex( GLuint program, const GLchar *uniformBlockName )
 {
-    struct glGetUniformBlockIndex_params args = { .teb = NtCurrentTeb(), .program = program, .uniformBlockName = uniformBlockName };
+    struct glGetUniformBlockIndex_params args = { .teb = NtCurrentTeb(), .uniformBlockName = uniformBlockName };
     NTSTATUS status;
     TRACE( "program %d, uniformBlockName %p\n", program, uniformBlockName );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformBlockIndex, &args ))) WARN( "glGetUniformBlockIndex returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetUniformBufferSizeEXT( GLuint program, GLint location )
 {
-    struct glGetUniformBufferSizeEXT_params args = { .teb = NtCurrentTeb(), .program = program, .location = location };
+    struct glGetUniformBufferSizeEXT_params args = { .teb = NtCurrentTeb(), .location = location };
     NTSTATUS status;
     TRACE( "program %d, location %d\n", program, location );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformBufferSizeEXT, &args ))) WARN( "glGetUniformBufferSizeEXT returned %#lx\n", status );
     return args.ret;
 }
 
 static void WINAPI glGetUniformIndices( GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices )
 {
-    struct glGetUniformIndices_params args = { .teb = NtCurrentTeb(), .program = program, .uniformCount = uniformCount, .uniformNames = uniformNames, .uniformIndices = uniformIndices };
+    struct glGetUniformIndices_params args = { .teb = NtCurrentTeb(), .uniformCount = uniformCount, .uniformNames = uniformNames, .uniformIndices = uniformIndices };
     NTSTATUS status;
     TRACE( "program %d, uniformCount %d, uniformNames %p, uniformIndices %p\n", program, uniformCount, uniformNames, uniformIndices );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformIndices, &args ))) WARN( "glGetUniformIndices returned %#lx\n", status );
 }
 
 static GLint WINAPI glGetUniformLocation( GLuint program, const GLchar *name )
 {
-    struct glGetUniformLocation_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetUniformLocation_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformLocation, &args ))) WARN( "glGetUniformLocation returned %#lx\n", status );
     return args.ret;
 }
 
 static GLint WINAPI glGetUniformLocationARB( GLhandleARB programObj, const GLcharARB *name )
 {
-    struct glGetUniformLocationARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .name = name };
+    struct glGetUniformLocationARB_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "programObj %d, name %p\n", programObj, name );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetUniformLocationARB, &args ))) WARN( "glGetUniformLocationARB returned %#lx\n", status );
     return args.ret;
 }
 
 static GLintptr WINAPI glGetUniformOffsetEXT( GLuint program, GLint location )
 {
-    struct glGetUniformOffsetEXT_params args = { .teb = NtCurrentTeb(), .program = program, .location = location };
+    struct glGetUniformOffsetEXT_params args = { .teb = NtCurrentTeb(), .location = location };
     NTSTATUS status;
     TRACE( "program %d, location %d\n", program, location );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformOffsetEXT, &args ))) WARN( "glGetUniformOffsetEXT returned %#lx\n", status );
     return args.ret;
 }
@@ -10925,89 +11010,100 @@ static void WINAPI glGetUniformSubroutineuiv( GLenum shadertype, GLint location,
 
 static void WINAPI glGetUniformdv( GLuint program, GLint location, GLdouble *params )
 {
-    struct glGetUniformdv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformdv_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformdv, &args ))) WARN( "glGetUniformdv returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformfv( GLuint program, GLint location, GLfloat *params )
 {
-    struct glGetUniformfv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformfv_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformfv, &args ))) WARN( "glGetUniformfv returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformfvARB( GLhandleARB programObj, GLint location, GLfloat *params )
 {
-    struct glGetUniformfvARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .location = location, .params = params };
+    struct glGetUniformfvARB_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "programObj %d, location %d, params %p\n", programObj, location, params );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetUniformfvARB, &args ))) WARN( "glGetUniformfvARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformi64vARB( GLuint program, GLint location, GLint64 *params )
 {
-    struct glGetUniformi64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformi64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformi64vARB, &args ))) WARN( "glGetUniformi64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformi64vNV( GLuint program, GLint location, GLint64EXT *params )
 {
-    struct glGetUniformi64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformi64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformi64vNV, &args ))) WARN( "glGetUniformi64vNV returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformiv( GLuint program, GLint location, GLint *params )
 {
-    struct glGetUniformiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformiv_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformiv, &args ))) WARN( "glGetUniformiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformivARB( GLhandleARB programObj, GLint location, GLint *params )
 {
-    struct glGetUniformivARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj, .location = location, .params = params };
+    struct glGetUniformivARB_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "programObj %d, location %d, params %p\n", programObj, location, params );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glGetUniformivARB, &args ))) WARN( "glGetUniformivARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformui64vARB( GLuint program, GLint location, GLuint64 *params )
 {
-    struct glGetUniformui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformui64vARB, &args ))) WARN( "glGetUniformui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformui64vNV( GLuint program, GLint location, GLuint64EXT *params )
 {
-    struct glGetUniformui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformui64vNV, &args ))) WARN( "glGetUniformui64vNV returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformuiv( GLuint program, GLint location, GLuint *params )
 {
-    struct glGetUniformuiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformuiv_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformuiv, &args ))) WARN( "glGetUniformuiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetUniformuivEXT( GLuint program, GLint location, GLuint *params )
 {
-    struct glGetUniformuivEXT_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .params = params };
+    struct glGetUniformuivEXT_params args = { .teb = NtCurrentTeb(), .location = location, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, params %p\n", program, location, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetUniformuivEXT, &args ))) WARN( "glGetUniformuivEXT returned %#lx\n", status );
 }
 
@@ -11081,9 +11177,10 @@ static void WINAPI glGetVariantPointervEXT( GLuint id, GLenum value, void **data
 
 static GLint WINAPI glGetVaryingLocationNV( GLuint program, const GLchar *name )
 {
-    struct glGetVaryingLocationNV_params args = { .teb = NtCurrentTeb(), .program = program, .name = name };
+    struct glGetVaryingLocationNV_params args = { .teb = NtCurrentTeb(), .name = name };
     NTSTATUS status;
     TRACE( "program %d, name %p\n", program, name );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetVaryingLocationNV, &args ))) WARN( "glGetVaryingLocationNV returned %#lx\n", status );
     return args.ret;
 }
@@ -11687,81 +11784,91 @@ static void WINAPI glGetnTexImageARB( GLenum target, GLint level, GLenum format,
 
 static void WINAPI glGetnUniformdv( GLuint program, GLint location, GLsizei bufSize, GLdouble *params )
 {
-    struct glGetnUniformdv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformdv_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformdv, &args ))) WARN( "glGetnUniformdv returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformdvARB( GLuint program, GLint location, GLsizei bufSize, GLdouble *params )
 {
-    struct glGetnUniformdvARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformdvARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformdvARB, &args ))) WARN( "glGetnUniformdvARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformfv( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
 {
-    struct glGetnUniformfv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformfv_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformfv, &args ))) WARN( "glGetnUniformfv returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformfvARB( GLuint program, GLint location, GLsizei bufSize, GLfloat *params )
 {
-    struct glGetnUniformfvARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformfvARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformfvARB, &args ))) WARN( "glGetnUniformfvARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformi64vARB( GLuint program, GLint location, GLsizei bufSize, GLint64 *params )
 {
-    struct glGetnUniformi64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformi64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformi64vARB, &args ))) WARN( "glGetnUniformi64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformiv( GLuint program, GLint location, GLsizei bufSize, GLint *params )
 {
-    struct glGetnUniformiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformiv_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformiv, &args ))) WARN( "glGetnUniformiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformivARB( GLuint program, GLint location, GLsizei bufSize, GLint *params )
 {
-    struct glGetnUniformivARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformivARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformivARB, &args ))) WARN( "glGetnUniformivARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformui64vARB( GLuint program, GLint location, GLsizei bufSize, GLuint64 *params )
 {
-    struct glGetnUniformui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformui64vARB, &args ))) WARN( "glGetnUniformui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformuiv( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
 {
-    struct glGetnUniformuiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformuiv_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformuiv, &args ))) WARN( "glGetnUniformuiv returned %#lx\n", status );
 }
 
 static void WINAPI glGetnUniformuivARB( GLuint program, GLint location, GLsizei bufSize, GLuint *params )
 {
-    struct glGetnUniformuivARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .bufSize = bufSize, .params = params };
+    struct glGetnUniformuivARB_params args = { .teb = NtCurrentTeb(), .location = location, .bufSize = bufSize, .params = params };
     NTSTATUS status;
     TRACE( "program %d, location %d, bufSize %d, params %p\n", program, location, bufSize, params );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glGetnUniformuivARB, &args ))) WARN( "glGetnUniformuivARB returned %#lx\n", status );
 }
 
@@ -12308,9 +12415,10 @@ static GLboolean WINAPI glIsPointInStrokePathNV( GLuint path, GLfloat x, GLfloat
 
 static GLboolean WINAPI glIsProgram( GLuint program )
 {
-    struct glIsProgram_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glIsProgram_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glIsProgram, &args ))) WARN( "glIsProgram returned %#lx\n", status );
     return args.ret;
 }
@@ -12404,9 +12512,10 @@ static GLboolean WINAPI glIsSemaphoreEXT( GLuint semaphore )
 
 static GLboolean WINAPI glIsShader( GLuint shader )
 {
-    struct glIsShader_params args = { .teb = NtCurrentTeb(), .shader = shader };
+    struct glIsShader_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "shader %d\n", shader );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glIsShader, &args ))) WARN( "glIsShader returned %#lx\n", status );
     return args.ret;
 }
@@ -12637,17 +12746,19 @@ static void WINAPI glLineWidthxOES( GLfixed width )
 
 static void WINAPI glLinkProgram( GLuint program )
 {
-    struct glLinkProgram_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glLinkProgram_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glLinkProgram, &args ))) WARN( "glLinkProgram returned %#lx\n", status );
 }
 
 static void WINAPI glLinkProgramARB( GLhandleARB programObj )
 {
-    struct glLinkProgramARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj };
+    struct glLinkProgramARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "programObj %d\n", programObj );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glLinkProgramARB, &args ))) WARN( "glLinkProgramARB returned %#lx\n", status );
 }
 
@@ -16491,9 +16602,10 @@ static void WINAPI glPrioritizeTexturesxOES( GLsizei n, const GLuint *textures,
 
 static void WINAPI glProgramBinary( GLuint program, GLenum binaryFormat, const void *binary, GLsizei length )
 {
-    struct glProgramBinary_params args = { .teb = NtCurrentTeb(), .program = program, .binaryFormat = binaryFormat, .binary = binary, .length = length };
+    struct glProgramBinary_params args = { .teb = NtCurrentTeb(), .binaryFormat = binaryFormat, .binary = binary, .length = length };
     NTSTATUS status;
     TRACE( "program %d, binaryFormat %d, binary %p, length %d\n", program, binaryFormat, binary, length );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramBinary, &args ))) WARN( "glProgramBinary returned %#lx\n", status );
 }
 
@@ -16767,25 +16879,28 @@ static void WINAPI glProgramParameter4fvNV( GLenum target, GLuint index, const G
 
 static void WINAPI glProgramParameteri( GLuint program, GLenum pname, GLint value )
 {
-    struct glProgramParameteri_params args = { .teb = NtCurrentTeb(), .program = program, .pname = pname, .value = value };
+    struct glProgramParameteri_params args = { .teb = NtCurrentTeb(), .pname = pname, .value = value };
     NTSTATUS status;
     TRACE( "program %d, pname %d, value %d\n", program, pname, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramParameteri, &args ))) WARN( "glProgramParameteri returned %#lx\n", status );
 }
 
 static void WINAPI glProgramParameteriARB( GLuint program, GLenum pname, GLint value )
 {
-    struct glProgramParameteriARB_params args = { .teb = NtCurrentTeb(), .program = program, .pname = pname, .value = value };
+    struct glProgramParameteriARB_params args = { .teb = NtCurrentTeb(), .pname = pname, .value = value };
     NTSTATUS status;
     TRACE( "program %d, pname %d, value %d\n", program, pname, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramParameteriARB, &args ))) WARN( "glProgramParameteriARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramParameteriEXT( GLuint program, GLenum pname, GLint value )
 {
-    struct glProgramParameteriEXT_params args = { .teb = NtCurrentTeb(), .program = program, .pname = pname, .value = value };
+    struct glProgramParameteriEXT_params args = { .teb = NtCurrentTeb(), .pname = pname, .value = value };
     NTSTATUS status;
     TRACE( "program %d, pname %d, value %d\n", program, pname, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramParameteriEXT, &args ))) WARN( "glProgramParameteriEXT returned %#lx\n", status );
 }
 
@@ -16807,9 +16922,10 @@ static void WINAPI glProgramParameters4fvNV( GLenum target, GLuint index, GLsize
 
 static void WINAPI glProgramPathFragmentInputGenNV( GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs )
 {
-    struct glProgramPathFragmentInputGenNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .genMode = genMode, .components = components, .coeffs = coeffs };
+    struct glProgramPathFragmentInputGenNV_params args = { .teb = NtCurrentTeb(), .location = location, .genMode = genMode, .components = components, .coeffs = coeffs };
     NTSTATUS status;
     TRACE( "program %d, location %d, genMode %d, components %d, coeffs %p\n", program, location, genMode, components, coeffs );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramPathFragmentInputGenNV, &args ))) WARN( "glProgramPathFragmentInputGenNV returned %#lx\n", status );
 }
 
@@ -16831,9 +16947,10 @@ static void WINAPI glProgramSubroutineParametersuivNV( GLenum target, GLsizei co
 
 static void WINAPI glProgramUniform1d( GLuint program, GLint location, GLdouble v0 )
 {
-    struct glProgramUniform1d_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0 };
+    struct glProgramUniform1d_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f\n", program, location, v0 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1d, &args ))) WARN( "glProgramUniform1d returned %#lx\n", status );
 }
 
@@ -16849,9 +16966,10 @@ static void WINAPI glProgramUniform1dEXT( GLuint program, GLint location, GLdoub
 
 static void WINAPI glProgramUniform1dv( GLuint program, GLint location, GLsizei count, const GLdouble *value )
 {
-    struct glProgramUniform1dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1dv, &args ))) WARN( "glProgramUniform1dv returned %#lx\n", status );
 }
 
@@ -16867,9 +16985,10 @@ static void WINAPI glProgramUniform1dvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform1f( GLuint program, GLint location, GLfloat v0 )
 {
-    struct glProgramUniform1f_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0 };
+    struct glProgramUniform1f_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f\n", program, location, v0 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1f, &args ))) WARN( "glProgramUniform1f returned %#lx\n", status );
 }
 
@@ -16885,9 +17004,10 @@ static void WINAPI glProgramUniform1fEXT( GLuint program, GLint location, GLfloa
 
 static void WINAPI glProgramUniform1fv( GLuint program, GLint location, GLsizei count, const GLfloat *value )
 {
-    struct glProgramUniform1fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1fv, &args ))) WARN( "glProgramUniform1fv returned %#lx\n", status );
 }
 
@@ -16903,41 +17023,46 @@ static void WINAPI glProgramUniform1fvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform1i( GLuint program, GLint location, GLint v0 )
 {
-    struct glProgramUniform1i_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0 };
+    struct glProgramUniform1i_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d\n", program, location, v0 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1i, &args ))) WARN( "glProgramUniform1i returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1i64ARB( GLuint program, GLint location, GLint64 x )
 {
-    struct glProgramUniform1i64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x };
+    struct glProgramUniform1i64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s\n", program, location, wine_dbgstr_longlong(x) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1i64ARB, &args ))) WARN( "glProgramUniform1i64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1i64NV( GLuint program, GLint location, GLint64EXT x )
 {
-    struct glProgramUniform1i64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x };
+    struct glProgramUniform1i64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s\n", program, location, wine_dbgstr_longlong(x) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1i64NV, &args ))) WARN( "glProgramUniform1i64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1i64vARB( GLuint program, GLint location, GLsizei count, const GLint64 *value )
 {
-    struct glProgramUniform1i64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1i64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1i64vARB, &args ))) WARN( "glProgramUniform1i64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1i64vNV( GLuint program, GLint location, GLsizei count, const GLint64EXT *value )
 {
-    struct glProgramUniform1i64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1i64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1i64vNV, &args ))) WARN( "glProgramUniform1i64vNV returned %#lx\n", status );
 }
 
@@ -16953,9 +17078,10 @@ static void WINAPI glProgramUniform1iEXT( GLuint program, GLint location, GLint
 
 static void WINAPI glProgramUniform1iv( GLuint program, GLint location, GLsizei count, const GLint *value )
 {
-    struct glProgramUniform1iv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1iv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1iv, &args ))) WARN( "glProgramUniform1iv returned %#lx\n", status );
 }
 
@@ -16971,41 +17097,46 @@ static void WINAPI glProgramUniform1ivEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform1ui( GLuint program, GLint location, GLuint v0 )
 {
-    struct glProgramUniform1ui_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0 };
+    struct glProgramUniform1ui_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d\n", program, location, v0 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1ui, &args ))) WARN( "glProgramUniform1ui returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1ui64ARB( GLuint program, GLint location, GLuint64 x )
 {
-    struct glProgramUniform1ui64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x };
+    struct glProgramUniform1ui64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s\n", program, location, wine_dbgstr_longlong(x) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1ui64ARB, &args ))) WARN( "glProgramUniform1ui64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1ui64NV( GLuint program, GLint location, GLuint64EXT x )
 {
-    struct glProgramUniform1ui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x };
+    struct glProgramUniform1ui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s\n", program, location, wine_dbgstr_longlong(x) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1ui64NV, &args ))) WARN( "glProgramUniform1ui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1ui64vARB( GLuint program, GLint location, GLsizei count, const GLuint64 *value )
 {
-    struct glProgramUniform1ui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1ui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1ui64vARB, &args ))) WARN( "glProgramUniform1ui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform1ui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64EXT *value )
 {
-    struct glProgramUniform1ui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1ui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1ui64vNV, &args ))) WARN( "glProgramUniform1ui64vNV returned %#lx\n", status );
 }
 
@@ -17021,9 +17152,10 @@ static void WINAPI glProgramUniform1uiEXT( GLuint program, GLint location, GLuin
 
 static void WINAPI glProgramUniform1uiv( GLuint program, GLint location, GLsizei count, const GLuint *value )
 {
-    struct glProgramUniform1uiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform1uiv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform1uiv, &args ))) WARN( "glProgramUniform1uiv returned %#lx\n", status );
 }
 
@@ -17039,9 +17171,10 @@ static void WINAPI glProgramUniform1uivEXT( GLuint program, GLint location, GLsi
 
 static void WINAPI glProgramUniform2d( GLuint program, GLint location, GLdouble v0, GLdouble v1 )
 {
-    struct glProgramUniform2d_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1 };
+    struct glProgramUniform2d_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f\n", program, location, v0, v1 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2d, &args ))) WARN( "glProgramUniform2d returned %#lx\n", status );
 }
 
@@ -17057,9 +17190,10 @@ static void WINAPI glProgramUniform2dEXT( GLuint program, GLint location, GLdoub
 
 static void WINAPI glProgramUniform2dv( GLuint program, GLint location, GLsizei count, const GLdouble *value )
 {
-    struct glProgramUniform2dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2dv, &args ))) WARN( "glProgramUniform2dv returned %#lx\n", status );
 }
 
@@ -17075,9 +17209,10 @@ static void WINAPI glProgramUniform2dvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform2f( GLuint program, GLint location, GLfloat v0, GLfloat v1 )
 {
-    struct glProgramUniform2f_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1 };
+    struct glProgramUniform2f_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f\n", program, location, v0, v1 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2f, &args ))) WARN( "glProgramUniform2f returned %#lx\n", status );
 }
 
@@ -17093,9 +17228,10 @@ static void WINAPI glProgramUniform2fEXT( GLuint program, GLint location, GLfloa
 
 static void WINAPI glProgramUniform2fv( GLuint program, GLint location, GLsizei count, const GLfloat *value )
 {
-    struct glProgramUniform2fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2fv, &args ))) WARN( "glProgramUniform2fv returned %#lx\n", status );
 }
 
@@ -17111,41 +17247,46 @@ static void WINAPI glProgramUniform2fvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform2i( GLuint program, GLint location, GLint v0, GLint v1 )
 {
-    struct glProgramUniform2i_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1 };
+    struct glProgramUniform2i_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d\n", program, location, v0, v1 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2i, &args ))) WARN( "glProgramUniform2i returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2i64ARB( GLuint program, GLint location, GLint64 x, GLint64 y )
 {
-    struct glProgramUniform2i64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y };
+    struct glProgramUniform2i64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2i64ARB, &args ))) WARN( "glProgramUniform2i64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2i64NV( GLuint program, GLint location, GLint64EXT x, GLint64EXT y )
 {
-    struct glProgramUniform2i64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y };
+    struct glProgramUniform2i64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2i64NV, &args ))) WARN( "glProgramUniform2i64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2i64vARB( GLuint program, GLint location, GLsizei count, const GLint64 *value )
 {
-    struct glProgramUniform2i64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2i64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2i64vARB, &args ))) WARN( "glProgramUniform2i64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2i64vNV( GLuint program, GLint location, GLsizei count, const GLint64EXT *value )
 {
-    struct glProgramUniform2i64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2i64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2i64vNV, &args ))) WARN( "glProgramUniform2i64vNV returned %#lx\n", status );
 }
 
@@ -17161,9 +17302,10 @@ static void WINAPI glProgramUniform2iEXT( GLuint program, GLint location, GLint
 
 static void WINAPI glProgramUniform2iv( GLuint program, GLint location, GLsizei count, const GLint *value )
 {
-    struct glProgramUniform2iv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2iv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2iv, &args ))) WARN( "glProgramUniform2iv returned %#lx\n", status );
 }
 
@@ -17179,41 +17321,46 @@ static void WINAPI glProgramUniform2ivEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform2ui( GLuint program, GLint location, GLuint v0, GLuint v1 )
 {
-    struct glProgramUniform2ui_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1 };
+    struct glProgramUniform2ui_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d\n", program, location, v0, v1 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2ui, &args ))) WARN( "glProgramUniform2ui returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2ui64ARB( GLuint program, GLint location, GLuint64 x, GLuint64 y )
 {
-    struct glProgramUniform2ui64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y };
+    struct glProgramUniform2ui64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2ui64ARB, &args ))) WARN( "glProgramUniform2ui64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2ui64NV( GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y )
 {
-    struct glProgramUniform2ui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y };
+    struct glProgramUniform2ui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2ui64NV, &args ))) WARN( "glProgramUniform2ui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2ui64vARB( GLuint program, GLint location, GLsizei count, const GLuint64 *value )
 {
-    struct glProgramUniform2ui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2ui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2ui64vARB, &args ))) WARN( "glProgramUniform2ui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform2ui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64EXT *value )
 {
-    struct glProgramUniform2ui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2ui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2ui64vNV, &args ))) WARN( "glProgramUniform2ui64vNV returned %#lx\n", status );
 }
 
@@ -17229,9 +17376,10 @@ static void WINAPI glProgramUniform2uiEXT( GLuint program, GLint location, GLuin
 
 static void WINAPI glProgramUniform2uiv( GLuint program, GLint location, GLsizei count, const GLuint *value )
 {
-    struct glProgramUniform2uiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform2uiv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform2uiv, &args ))) WARN( "glProgramUniform2uiv returned %#lx\n", status );
 }
 
@@ -17247,9 +17395,10 @@ static void WINAPI glProgramUniform2uivEXT( GLuint program, GLint location, GLsi
 
 static void WINAPI glProgramUniform3d( GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2 )
 {
-    struct glProgramUniform3d_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
+    struct glProgramUniform3d_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f, v2 %f\n", program, location, v0, v1, v2 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3d, &args ))) WARN( "glProgramUniform3d returned %#lx\n", status );
 }
 
@@ -17265,9 +17414,10 @@ static void WINAPI glProgramUniform3dEXT( GLuint program, GLint location, GLdoub
 
 static void WINAPI glProgramUniform3dv( GLuint program, GLint location, GLsizei count, const GLdouble *value )
 {
-    struct glProgramUniform3dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3dv, &args ))) WARN( "glProgramUniform3dv returned %#lx\n", status );
 }
 
@@ -17283,9 +17433,10 @@ static void WINAPI glProgramUniform3dvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform3f( GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2 )
 {
-    struct glProgramUniform3f_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
+    struct glProgramUniform3f_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f, v2 %f\n", program, location, v0, v1, v2 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3f, &args ))) WARN( "glProgramUniform3f returned %#lx\n", status );
 }
 
@@ -17301,9 +17452,10 @@ static void WINAPI glProgramUniform3fEXT( GLuint program, GLint location, GLfloa
 
 static void WINAPI glProgramUniform3fv( GLuint program, GLint location, GLsizei count, const GLfloat *value )
 {
-    struct glProgramUniform3fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3fv, &args ))) WARN( "glProgramUniform3fv returned %#lx\n", status );
 }
 
@@ -17319,41 +17471,46 @@ static void WINAPI glProgramUniform3fvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform3i( GLuint program, GLint location, GLint v0, GLint v1, GLint v2 )
 {
-    struct glProgramUniform3i_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
+    struct glProgramUniform3i_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d, v2 %d\n", program, location, v0, v1, v2 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3i, &args ))) WARN( "glProgramUniform3i returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3i64ARB( GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z )
 {
-    struct glProgramUniform3i64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z };
+    struct glProgramUniform3i64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3i64ARB, &args ))) WARN( "glProgramUniform3i64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3i64NV( GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z )
 {
-    struct glProgramUniform3i64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z };
+    struct glProgramUniform3i64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3i64NV, &args ))) WARN( "glProgramUniform3i64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3i64vARB( GLuint program, GLint location, GLsizei count, const GLint64 *value )
 {
-    struct glProgramUniform3i64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3i64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3i64vARB, &args ))) WARN( "glProgramUniform3i64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3i64vNV( GLuint program, GLint location, GLsizei count, const GLint64EXT *value )
 {
-    struct glProgramUniform3i64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3i64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3i64vNV, &args ))) WARN( "glProgramUniform3i64vNV returned %#lx\n", status );
 }
 
@@ -17369,9 +17526,10 @@ static void WINAPI glProgramUniform3iEXT( GLuint program, GLint location, GLint
 
 static void WINAPI glProgramUniform3iv( GLuint program, GLint location, GLsizei count, const GLint *value )
 {
-    struct glProgramUniform3iv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3iv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3iv, &args ))) WARN( "glProgramUniform3iv returned %#lx\n", status );
 }
 
@@ -17387,41 +17545,46 @@ static void WINAPI glProgramUniform3ivEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform3ui( GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2 )
 {
-    struct glProgramUniform3ui_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
+    struct glProgramUniform3ui_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d, v2 %d\n", program, location, v0, v1, v2 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3ui, &args ))) WARN( "glProgramUniform3ui returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3ui64ARB( GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z )
 {
-    struct glProgramUniform3ui64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z };
+    struct glProgramUniform3ui64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3ui64ARB, &args ))) WARN( "glProgramUniform3ui64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3ui64NV( GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z )
 {
-    struct glProgramUniform3ui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z };
+    struct glProgramUniform3ui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3ui64NV, &args ))) WARN( "glProgramUniform3ui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3ui64vARB( GLuint program, GLint location, GLsizei count, const GLuint64 *value )
 {
-    struct glProgramUniform3ui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3ui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3ui64vARB, &args ))) WARN( "glProgramUniform3ui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform3ui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64EXT *value )
 {
-    struct glProgramUniform3ui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3ui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3ui64vNV, &args ))) WARN( "glProgramUniform3ui64vNV returned %#lx\n", status );
 }
 
@@ -17437,9 +17600,10 @@ static void WINAPI glProgramUniform3uiEXT( GLuint program, GLint location, GLuin
 
 static void WINAPI glProgramUniform3uiv( GLuint program, GLint location, GLsizei count, const GLuint *value )
 {
-    struct glProgramUniform3uiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform3uiv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform3uiv, &args ))) WARN( "glProgramUniform3uiv returned %#lx\n", status );
 }
 
@@ -17455,9 +17619,10 @@ static void WINAPI glProgramUniform3uivEXT( GLuint program, GLint location, GLsi
 
 static void WINAPI glProgramUniform4d( GLuint program, GLint location, GLdouble v0, GLdouble v1, GLdouble v2, GLdouble v3 )
 {
-    struct glProgramUniform4d_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
+    struct glProgramUniform4d_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f, v2 %f, v3 %f\n", program, location, v0, v1, v2, v3 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4d, &args ))) WARN( "glProgramUniform4d returned %#lx\n", status );
 }
 
@@ -17473,9 +17638,10 @@ static void WINAPI glProgramUniform4dEXT( GLuint program, GLint location, GLdoub
 
 static void WINAPI glProgramUniform4dv( GLuint program, GLint location, GLsizei count, const GLdouble *value )
 {
-    struct glProgramUniform4dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4dv, &args ))) WARN( "glProgramUniform4dv returned %#lx\n", status );
 }
 
@@ -17491,9 +17657,10 @@ static void WINAPI glProgramUniform4dvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform4f( GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3 )
 {
-    struct glProgramUniform4f_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
+    struct glProgramUniform4f_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %f, v1 %f, v2 %f, v3 %f\n", program, location, v0, v1, v2, v3 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4f, &args ))) WARN( "glProgramUniform4f returned %#lx\n", status );
 }
 
@@ -17509,9 +17676,10 @@ static void WINAPI glProgramUniform4fEXT( GLuint program, GLint location, GLfloa
 
 static void WINAPI glProgramUniform4fv( GLuint program, GLint location, GLsizei count, const GLfloat *value )
 {
-    struct glProgramUniform4fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4fv, &args ))) WARN( "glProgramUniform4fv returned %#lx\n", status );
 }
 
@@ -17527,41 +17695,46 @@ static void WINAPI glProgramUniform4fvEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform4i( GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3 )
 {
-    struct glProgramUniform4i_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
+    struct glProgramUniform4i_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d, v2 %d, v3 %d\n", program, location, v0, v1, v2, v3 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4i, &args ))) WARN( "glProgramUniform4i returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4i64ARB( GLuint program, GLint location, GLint64 x, GLint64 y, GLint64 z, GLint64 w )
 {
-    struct glProgramUniform4i64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z, .w = w };
+    struct glProgramUniform4i64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z, .w = w };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s, w %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z), wine_dbgstr_longlong(w) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4i64ARB, &args ))) WARN( "glProgramUniform4i64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4i64NV( GLuint program, GLint location, GLint64EXT x, GLint64EXT y, GLint64EXT z, GLint64EXT w )
 {
-    struct glProgramUniform4i64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z, .w = w };
+    struct glProgramUniform4i64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z, .w = w };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s, w %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z), wine_dbgstr_longlong(w) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4i64NV, &args ))) WARN( "glProgramUniform4i64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4i64vARB( GLuint program, GLint location, GLsizei count, const GLint64 *value )
 {
-    struct glProgramUniform4i64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4i64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4i64vARB, &args ))) WARN( "glProgramUniform4i64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4i64vNV( GLuint program, GLint location, GLsizei count, const GLint64EXT *value )
 {
-    struct glProgramUniform4i64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4i64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4i64vNV, &args ))) WARN( "glProgramUniform4i64vNV returned %#lx\n", status );
 }
 
@@ -17577,9 +17750,10 @@ static void WINAPI glProgramUniform4iEXT( GLuint program, GLint location, GLint
 
 static void WINAPI glProgramUniform4iv( GLuint program, GLint location, GLsizei count, const GLint *value )
 {
-    struct glProgramUniform4iv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4iv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4iv, &args ))) WARN( "glProgramUniform4iv returned %#lx\n", status );
 }
 
@@ -17595,41 +17769,46 @@ static void WINAPI glProgramUniform4ivEXT( GLuint program, GLint location, GLsiz
 
 static void WINAPI glProgramUniform4ui( GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3 )
 {
-    struct glProgramUniform4ui_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
+    struct glProgramUniform4ui_params args = { .teb = NtCurrentTeb(), .location = location, .v0 = v0, .v1 = v1, .v2 = v2, .v3 = v3 };
     NTSTATUS status;
     TRACE( "program %d, location %d, v0 %d, v1 %d, v2 %d, v3 %d\n", program, location, v0, v1, v2, v3 );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4ui, &args ))) WARN( "glProgramUniform4ui returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4ui64ARB( GLuint program, GLint location, GLuint64 x, GLuint64 y, GLuint64 z, GLuint64 w )
 {
-    struct glProgramUniform4ui64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z, .w = w };
+    struct glProgramUniform4ui64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z, .w = w };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s, w %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z), wine_dbgstr_longlong(w) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4ui64ARB, &args ))) WARN( "glProgramUniform4ui64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4ui64NV( GLuint program, GLint location, GLuint64EXT x, GLuint64EXT y, GLuint64EXT z, GLuint64EXT w )
 {
-    struct glProgramUniform4ui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .x = x, .y = y, .z = z, .w = w };
+    struct glProgramUniform4ui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .x = x, .y = y, .z = z, .w = w };
     NTSTATUS status;
     TRACE( "program %d, location %d, x %s, y %s, z %s, w %s\n", program, location, wine_dbgstr_longlong(x), wine_dbgstr_longlong(y), wine_dbgstr_longlong(z), wine_dbgstr_longlong(w) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4ui64NV, &args ))) WARN( "glProgramUniform4ui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4ui64vARB( GLuint program, GLint location, GLsizei count, const GLuint64 *value )
 {
-    struct glProgramUniform4ui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4ui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4ui64vARB, &args ))) WARN( "glProgramUniform4ui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniform4ui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64EXT *value )
 {
-    struct glProgramUniform4ui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4ui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4ui64vNV, &args ))) WARN( "glProgramUniform4ui64vNV returned %#lx\n", status );
 }
 
@@ -17645,9 +17824,10 @@ static void WINAPI glProgramUniform4uiEXT( GLuint program, GLint location, GLuin
 
 static void WINAPI glProgramUniform4uiv( GLuint program, GLint location, GLsizei count, const GLuint *value )
 {
-    struct glProgramUniform4uiv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniform4uiv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniform4uiv, &args ))) WARN( "glProgramUniform4uiv returned %#lx\n", status );
 }
 
@@ -17663,41 +17843,46 @@ static void WINAPI glProgramUniform4uivEXT( GLuint program, GLint location, GLsi
 
 static void WINAPI glProgramUniformHandleui64ARB( GLuint program, GLint location, GLuint64 value )
 {
-    struct glProgramUniformHandleui64ARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .value = value };
+    struct glProgramUniformHandleui64ARB_params args = { .teb = NtCurrentTeb(), .location = location, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, value %s\n", program, location, wine_dbgstr_longlong(value) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformHandleui64ARB, &args ))) WARN( "glProgramUniformHandleui64ARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniformHandleui64NV( GLuint program, GLint location, GLuint64 value )
 {
-    struct glProgramUniformHandleui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .value = value };
+    struct glProgramUniformHandleui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, value %s\n", program, location, wine_dbgstr_longlong(value) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformHandleui64NV, &args ))) WARN( "glProgramUniformHandleui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniformHandleui64vARB( GLuint program, GLint location, GLsizei count, const GLuint64 *values )
 {
-    struct glProgramUniformHandleui64vARB_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .values = values };
+    struct glProgramUniformHandleui64vARB_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .values = values };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, values %p\n", program, location, count, values );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformHandleui64vARB, &args ))) WARN( "glProgramUniformHandleui64vARB returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniformHandleui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64 *values )
 {
-    struct glProgramUniformHandleui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .values = values };
+    struct glProgramUniformHandleui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .values = values };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, values %p\n", program, location, count, values );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformHandleui64vNV, &args ))) WARN( "glProgramUniformHandleui64vNV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniformMatrix2dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix2dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2dv, &args ))) WARN( "glProgramUniformMatrix2dv returned %#lx\n", status );
 }
 
@@ -17713,9 +17898,10 @@ static void WINAPI glProgramUniformMatrix2dvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix2fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix2fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2fv, &args ))) WARN( "glProgramUniformMatrix2fv returned %#lx\n", status );
 }
 
@@ -17731,9 +17917,10 @@ static void WINAPI glProgramUniformMatrix2fvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix2x3dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix2x3dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2x3dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2x3dv, &args ))) WARN( "glProgramUniformMatrix2x3dv returned %#lx\n", status );
 }
 
@@ -17749,9 +17936,10 @@ static void WINAPI glProgramUniformMatrix2x3dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix2x3fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix2x3fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2x3fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2x3fv, &args ))) WARN( "glProgramUniformMatrix2x3fv returned %#lx\n", status );
 }
 
@@ -17767,9 +17955,10 @@ static void WINAPI glProgramUniformMatrix2x3fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix2x4dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix2x4dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2x4dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2x4dv, &args ))) WARN( "glProgramUniformMatrix2x4dv returned %#lx\n", status );
 }
 
@@ -17785,9 +17974,10 @@ static void WINAPI glProgramUniformMatrix2x4dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix2x4fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix2x4fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix2x4fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix2x4fv, &args ))) WARN( "glProgramUniformMatrix2x4fv returned %#lx\n", status );
 }
 
@@ -17803,9 +17993,10 @@ static void WINAPI glProgramUniformMatrix2x4fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix3dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix3dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3dv, &args ))) WARN( "glProgramUniformMatrix3dv returned %#lx\n", status );
 }
 
@@ -17821,9 +18012,10 @@ static void WINAPI glProgramUniformMatrix3dvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix3fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix3fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3fv, &args ))) WARN( "glProgramUniformMatrix3fv returned %#lx\n", status );
 }
 
@@ -17839,9 +18031,10 @@ static void WINAPI glProgramUniformMatrix3fvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix3x2dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix3x2dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3x2dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3x2dv, &args ))) WARN( "glProgramUniformMatrix3x2dv returned %#lx\n", status );
 }
 
@@ -17857,9 +18050,10 @@ static void WINAPI glProgramUniformMatrix3x2dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix3x2fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix3x2fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3x2fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3x2fv, &args ))) WARN( "glProgramUniformMatrix3x2fv returned %#lx\n", status );
 }
 
@@ -17875,9 +18069,10 @@ static void WINAPI glProgramUniformMatrix3x2fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix3x4dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix3x4dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3x4dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3x4dv, &args ))) WARN( "glProgramUniformMatrix3x4dv returned %#lx\n", status );
 }
 
@@ -17893,9 +18088,10 @@ static void WINAPI glProgramUniformMatrix3x4dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix3x4fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix3x4fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix3x4fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix3x4fv, &args ))) WARN( "glProgramUniformMatrix3x4fv returned %#lx\n", status );
 }
 
@@ -17911,9 +18107,10 @@ static void WINAPI glProgramUniformMatrix3x4fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix4dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix4dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4dv, &args ))) WARN( "glProgramUniformMatrix4dv returned %#lx\n", status );
 }
 
@@ -17929,9 +18126,10 @@ static void WINAPI glProgramUniformMatrix4dvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix4fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix4fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4fv, &args ))) WARN( "glProgramUniformMatrix4fv returned %#lx\n", status );
 }
 
@@ -17947,9 +18145,10 @@ static void WINAPI glProgramUniformMatrix4fvEXT( GLuint program, GLint location,
 
 static void WINAPI glProgramUniformMatrix4x2dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix4x2dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4x2dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4x2dv, &args ))) WARN( "glProgramUniformMatrix4x2dv returned %#lx\n", status );
 }
 
@@ -17965,9 +18164,10 @@ static void WINAPI glProgramUniformMatrix4x2dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix4x2fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix4x2fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4x2fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4x2fv, &args ))) WARN( "glProgramUniformMatrix4x2fv returned %#lx\n", status );
 }
 
@@ -17983,9 +18183,10 @@ static void WINAPI glProgramUniformMatrix4x2fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix4x3dv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLdouble *value )
 {
-    struct glProgramUniformMatrix4x3dv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4x3dv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4x3dv, &args ))) WARN( "glProgramUniformMatrix4x3dv returned %#lx\n", status );
 }
 
@@ -18001,9 +18202,10 @@ static void WINAPI glProgramUniformMatrix4x3dvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformMatrix4x3fv( GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value )
 {
-    struct glProgramUniformMatrix4x3fv_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .transpose = transpose, .value = value };
+    struct glProgramUniformMatrix4x3fv_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .transpose = transpose, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, transpose %d, value %p\n", program, location, count, transpose, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformMatrix4x3fv, &args ))) WARN( "glProgramUniformMatrix4x3fv returned %#lx\n", status );
 }
 
@@ -18019,17 +18221,19 @@ static void WINAPI glProgramUniformMatrix4x3fvEXT( GLuint program, GLint locatio
 
 static void WINAPI glProgramUniformui64NV( GLuint program, GLint location, GLuint64EXT value )
 {
-    struct glProgramUniformui64NV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .value = value };
+    struct glProgramUniformui64NV_params args = { .teb = NtCurrentTeb(), .location = location, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, value %s\n", program, location, wine_dbgstr_longlong(value) );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformui64NV, &args ))) WARN( "glProgramUniformui64NV returned %#lx\n", status );
 }
 
 static void WINAPI glProgramUniformui64vNV( GLuint program, GLint location, GLsizei count, const GLuint64EXT *value )
 {
-    struct glProgramUniformui64vNV_params args = { .teb = NtCurrentTeb(), .program = program, .location = location, .count = count, .value = value };
+    struct glProgramUniformui64vNV_params args = { .teb = NtCurrentTeb(), .location = location, .count = count, .value = value };
     NTSTATUS status;
     TRACE( "program %d, location %d, count %d, value %p\n", program, location, count, value );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glProgramUniformui64vNV, &args ))) WARN( "glProgramUniformui64vNV returned %#lx\n", status );
 }
 
@@ -19212,10 +19416,14 @@ static void WINAPI glSetMultisamplefvAMD( GLenum pname, GLuint index, const GLfl
 
 static void WINAPI glShaderBinary( GLsizei count, const GLuint *shaders, GLenum binaryFormat, const void *binary, GLsizei length )
 {
-    struct glShaderBinary_params args = { .teb = NtCurrentTeb(), .count = count, .shaders = shaders, .binaryFormat = binaryFormat, .binary = binary, .length = length };
+    GLuint shaders_buf[64], *shaders_tmp;
+    struct glShaderBinary_params args = { .teb = NtCurrentTeb(), .count = count, .binaryFormat = binaryFormat, .binary = binary, .length = length };
     NTSTATUS status;
     TRACE( "count %d, shaders %p, binaryFormat %d, binary %p, length %d\n", count, shaders, binaryFormat, binary, length );
+    shaders_tmp = count > 0 ? memdup_objects( count, shaders, shaders_buf, ARRAY_SIZE(shaders_buf) ) : NULL;
+    args.shaders = count > 0 ? map_context_objects( OBJ_TYPE_SHADER, count, shaders_tmp ) : NULL;
     if ((status = UNIX_CALL( glShaderBinary, &args ))) WARN( "glShaderBinary returned %#lx\n", status );
+    if (shaders_tmp != shaders_buf) free( shaders_tmp );
 }
 
 static void WINAPI glShaderOp1EXT( GLenum op, GLuint res, GLuint arg1 )
@@ -19244,25 +19452,28 @@ static void WINAPI glShaderOp3EXT( GLenum op, GLuint res, GLuint arg1, GLuint ar
 
 static void WINAPI glShaderSource( GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length )
 {
-    struct glShaderSource_params args = { .teb = NtCurrentTeb(), .shader = shader, .count = count, .string = string, .length = length };
+    struct glShaderSource_params args = { .teb = NtCurrentTeb(), .count = count, .string = string, .length = length };
     NTSTATUS status;
     TRACE( "shader %d, count %d, string %p, length %p\n", shader, count, string, length );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glShaderSource, &args ))) WARN( "glShaderSource returned %#lx\n", status );
 }
 
 static void WINAPI glShaderSourceARB( GLhandleARB shaderObj, GLsizei count, const GLcharARB **string, const GLint *length )
 {
-    struct glShaderSourceARB_params args = { .teb = NtCurrentTeb(), .shaderObj = shaderObj, .count = count, .string = string, .length = length };
+    struct glShaderSourceARB_params args = { .teb = NtCurrentTeb(), .count = count, .string = string, .length = length };
     NTSTATUS status;
     TRACE( "shaderObj %d, count %d, string %p, length %p\n", shaderObj, count, string, length );
+    args.shaderObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &shaderObj );
     if ((status = UNIX_CALL( glShaderSourceARB, &args ))) WARN( "glShaderSourceARB returned %#lx\n", status );
 }
 
 static void WINAPI glShaderStorageBlockBinding( GLuint program, GLuint storageBlockIndex, GLuint storageBlockBinding )
 {
-    struct glShaderStorageBlockBinding_params args = { .teb = NtCurrentTeb(), .program = program, .storageBlockIndex = storageBlockIndex, .storageBlockBinding = storageBlockBinding };
+    struct glShaderStorageBlockBinding_params args = { .teb = NtCurrentTeb(), .storageBlockIndex = storageBlockIndex, .storageBlockBinding = storageBlockBinding };
     NTSTATUS status;
     TRACE( "program %d, storageBlockIndex %d, storageBlockBinding %d\n", program, storageBlockIndex, storageBlockBinding );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glShaderStorageBlockBinding, &args ))) WARN( "glShaderStorageBlockBinding returned %#lx\n", status );
 }
 
@@ -19369,17 +19580,19 @@ static void WINAPI glSignalVkSemaphoreNV( GLuint64 vkSemaphore )
 
 static void WINAPI glSpecializeShader( GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue )
 {
-    struct glSpecializeShader_params args = { .teb = NtCurrentTeb(), .shader = shader, .pEntryPoint = pEntryPoint, .numSpecializationConstants = numSpecializationConstants, .pConstantIndex = pConstantIndex, .pConstantValue = pConstantValue };
+    struct glSpecializeShader_params args = { .teb = NtCurrentTeb(), .pEntryPoint = pEntryPoint, .numSpecializationConstants = numSpecializationConstants, .pConstantIndex = pConstantIndex, .pConstantValue = pConstantValue };
     NTSTATUS status;
     TRACE( "shader %d, pEntryPoint %p, numSpecializationConstants %d, pConstantIndex %p, pConstantValue %p\n", shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glSpecializeShader, &args ))) WARN( "glSpecializeShader returned %#lx\n", status );
 }
 
 static void WINAPI glSpecializeShaderARB( GLuint shader, const GLchar *pEntryPoint, GLuint numSpecializationConstants, const GLuint *pConstantIndex, const GLuint *pConstantValue )
 {
-    struct glSpecializeShaderARB_params args = { .teb = NtCurrentTeb(), .shader = shader, .pEntryPoint = pEntryPoint, .numSpecializationConstants = numSpecializationConstants, .pConstantIndex = pConstantIndex, .pConstantValue = pConstantValue };
+    struct glSpecializeShaderARB_params args = { .teb = NtCurrentTeb(), .pEntryPoint = pEntryPoint, .numSpecializationConstants = numSpecializationConstants, .pConstantIndex = pConstantIndex, .pConstantValue = pConstantValue };
     NTSTATUS status;
     TRACE( "shader %d, pEntryPoint %p, numSpecializationConstants %d, pConstantIndex %p, pConstantValue %p\n", shader, pEntryPoint, numSpecializationConstants, pConstantIndex, pConstantValue );
+    args.shader = *map_context_objects( OBJ_TYPE_SHADER, 1, &shader );
     if ((status = UNIX_CALL( glSpecializeShaderARB, &args ))) WARN( "glSpecializeShaderARB returned %#lx\n", status );
 }
 
@@ -21162,25 +21375,28 @@ static void WINAPI glTransformFeedbackStreamAttribsNV( GLsizei count, const GLin
 
 static void WINAPI glTransformFeedbackVaryings( GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode )
 {
-    struct glTransformFeedbackVaryings_params args = { .teb = NtCurrentTeb(), .program = program, .count = count, .varyings = varyings, .bufferMode = bufferMode };
+    struct glTransformFeedbackVaryings_params args = { .teb = NtCurrentTeb(), .count = count, .varyings = varyings, .bufferMode = bufferMode };
     NTSTATUS status;
     TRACE( "program %d, count %d, varyings %p, bufferMode %d\n", program, count, varyings, bufferMode );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glTransformFeedbackVaryings, &args ))) WARN( "glTransformFeedbackVaryings returned %#lx\n", status );
 }
 
 static void WINAPI glTransformFeedbackVaryingsEXT( GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode )
 {
-    struct glTransformFeedbackVaryingsEXT_params args = { .teb = NtCurrentTeb(), .program = program, .count = count, .varyings = varyings, .bufferMode = bufferMode };
+    struct glTransformFeedbackVaryingsEXT_params args = { .teb = NtCurrentTeb(), .count = count, .varyings = varyings, .bufferMode = bufferMode };
     NTSTATUS status;
     TRACE( "program %d, count %d, varyings %p, bufferMode %d\n", program, count, varyings, bufferMode );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glTransformFeedbackVaryingsEXT, &args ))) WARN( "glTransformFeedbackVaryingsEXT returned %#lx\n", status );
 }
 
 static void WINAPI glTransformFeedbackVaryingsNV( GLuint program, GLsizei count, const GLint *locations, GLenum bufferMode )
 {
-    struct glTransformFeedbackVaryingsNV_params args = { .teb = NtCurrentTeb(), .program = program, .count = count, .locations = locations, .bufferMode = bufferMode };
+    struct glTransformFeedbackVaryingsNV_params args = { .teb = NtCurrentTeb(), .count = count, .locations = locations, .bufferMode = bufferMode };
     NTSTATUS status;
     TRACE( "program %d, count %d, locations %p, bufferMode %d\n", program, count, locations, bufferMode );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glTransformFeedbackVaryingsNV, &args ))) WARN( "glTransformFeedbackVaryingsNV returned %#lx\n", status );
 }
 
@@ -21918,17 +22134,19 @@ static void WINAPI glUniform4uivEXT( GLint location, GLsizei count, const GLuint
 
 static void WINAPI glUniformBlockBinding( GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding )
 {
-    struct glUniformBlockBinding_params args = { .teb = NtCurrentTeb(), .program = program, .uniformBlockIndex = uniformBlockIndex, .uniformBlockBinding = uniformBlockBinding };
+    struct glUniformBlockBinding_params args = { .teb = NtCurrentTeb(), .uniformBlockIndex = uniformBlockIndex, .uniformBlockBinding = uniformBlockBinding };
     NTSTATUS status;
     TRACE( "program %d, uniformBlockIndex %d, uniformBlockBinding %d\n", program, uniformBlockIndex, uniformBlockBinding );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glUniformBlockBinding, &args ))) WARN( "glUniformBlockBinding returned %#lx\n", status );
 }
 
 static void WINAPI glUniformBufferEXT( GLuint program, GLint location, GLuint buffer )
 {
-    struct glUniformBufferEXT_params args = { .teb = NtCurrentTeb(), .program = program, .location = location };
+    struct glUniformBufferEXT_params args = { .teb = NtCurrentTeb(), .location = location };
     NTSTATUS status;
     TRACE( "program %d, location %d, buffer %d\n", program, location, buffer );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     args.buffer = *map_context_objects( OBJ_TYPE_BUFFER, 1, &buffer );
     if ((status = UNIX_CALL( glUniformBufferEXT, &args ))) WARN( "glUniformBufferEXT returned %#lx\n", status );
 }
@@ -22241,33 +22459,37 @@ static void WINAPI glUploadGpuMaskNVX( GLbitfield mask )
 
 static void WINAPI glUseProgram( GLuint program )
 {
-    struct glUseProgram_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glUseProgram_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glUseProgram, &args ))) WARN( "glUseProgram returned %#lx\n", status );
 }
 
 static void WINAPI glUseProgramObjectARB( GLhandleARB programObj )
 {
-    struct glUseProgramObjectARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj };
+    struct glUseProgramObjectARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "programObj %d\n", programObj );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glUseProgramObjectARB, &args ))) WARN( "glUseProgramObjectARB returned %#lx\n", status );
 }
 
 static void WINAPI glUseProgramStages( GLuint pipeline, GLbitfield stages, GLuint program )
 {
-    struct glUseProgramStages_params args = { .teb = NtCurrentTeb(), .pipeline = pipeline, .stages = stages, .program = program };
+    struct glUseProgramStages_params args = { .teb = NtCurrentTeb(), .pipeline = pipeline, .stages = stages };
     NTSTATUS status;
     TRACE( "pipeline %d, stages %d, program %d\n", pipeline, stages, program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glUseProgramStages, &args ))) WARN( "glUseProgramStages returned %#lx\n", status );
 }
 
 static void WINAPI glUseShaderProgramEXT( GLenum type, GLuint program )
 {
-    struct glUseShaderProgramEXT_params args = { .teb = NtCurrentTeb(), .type = type, .program = program };
+    struct glUseShaderProgramEXT_params args = { .teb = NtCurrentTeb(), .type = type };
     NTSTATUS status;
     TRACE( "type %d, program %d\n", type, program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glUseShaderProgramEXT, &args ))) WARN( "glUseShaderProgramEXT returned %#lx\n", status );
 }
 
@@ -22377,17 +22599,19 @@ static void WINAPI glVDPAUUnregisterSurfaceNV( GLvdpauSurfaceNV surface )
 
 static void WINAPI glValidateProgram( GLuint program )
 {
-    struct glValidateProgram_params args = { .teb = NtCurrentTeb(), .program = program };
+    struct glValidateProgram_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "program %d\n", program );
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
     if ((status = UNIX_CALL( glValidateProgram, &args ))) WARN( "glValidateProgram returned %#lx\n", status );
 }
 
 static void WINAPI glValidateProgramARB( GLhandleARB programObj )
 {
-    struct glValidateProgramARB_params args = { .teb = NtCurrentTeb(), .programObj = programObj };
+    struct glValidateProgramARB_params args = { .teb = NtCurrentTeb() };
     NTSTATUS status;
     TRACE( "programObj %d\n", programObj );
+    args.programObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &programObj );
     if ((status = UNIX_CALL( glValidateProgramARB, &args ))) WARN( "glValidateProgramARB returned %#lx\n", status );
 }
 
diff --git a/dlls/opengl32/unix_thunks.c b/dlls/opengl32/unix_thunks.c
index ad93a866a6d0..1d3f8a8dbd3d 100644
--- a/dlls/opengl32/unix_thunks.c
+++ b/dlls/opengl32/unix_thunks.c
@@ -58,15 +58,6 @@ static NTSTATUS wgl_wglSetPixelFormat( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS wgl_wglShareLists( void *args )
-{
-    struct wglShareLists_params *params = args;
-    const struct opengl_funcs *funcs = get_context_funcs( params->hrcSrvShare );
-    if (!funcs || !funcs->p_wglShareLists) return STATUS_NOT_IMPLEMENTED;
-    params->ret = wrap_wglShareLists( params->teb, params->hrcSrvShare, params->hrcSrvSource );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS wgl_wglSwapBuffers( void *args )
 {
     struct wglSwapBuffers_params *params = args;
@@ -30376,15 +30367,6 @@ static NTSTATUS ext_wglBindTexImageARB( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS ext_wglChoosePixelFormatARB( void *args )
-{
-    struct wglChoosePixelFormatARB_params *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( params->hdc );
-    if (!funcs || !funcs->p_wglChoosePixelFormatARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglChoosePixelFormatARB( params->hdc, params->piAttribIList, params->pfAttribFList, params->nMaxFormats, params->piFormats, params->nNumFormats );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS ext_wglCreateContextAttribsARB( void *args )
 {
     struct wglCreateContextAttribsARB_params *params = args;
@@ -30430,24 +30412,6 @@ static NTSTATUS ext_wglGetPbufferDCARB( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS ext_wglGetPixelFormatAttribfvARB( void *args )
-{
-    struct wglGetPixelFormatAttribfvARB_params *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( params->hdc );
-    if (!funcs || !funcs->p_wglGetPixelFormatAttribfvARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglGetPixelFormatAttribfvARB( params->hdc, params->iPixelFormat, params->iLayerPlane, params->nAttributes, params->piAttributes, params->pfValues );
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS ext_wglGetPixelFormatAttribivARB( void *args )
-{
-    struct wglGetPixelFormatAttribivARB_params *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( params->hdc );
-    if (!funcs || !funcs->p_wglGetPixelFormatAttribivARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglGetPixelFormatAttribivARB( params->hdc, params->iPixelFormat, params->iLayerPlane, params->nAttributes, params->piAttributes, params->piValues );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS ext_wglGetSwapIntervalEXT( void *args )
 {
     struct wglGetSwapIntervalEXT_params *params = args;
@@ -30564,7 +30528,6 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     wgl_wglDeleteContext,
     wgl_wglGetPixelFormat,
     wgl_wglSetPixelFormat,
-    wgl_wglShareLists,
     wgl_wglSwapBuffers,
     gl_glAccum,
     gl_glAlphaFunc,
@@ -33637,14 +33600,11 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     ext_glWriteMaskEXT,
     ext_wglAllocateMemoryNV,
     ext_wglBindTexImageARB,
-    ext_wglChoosePixelFormatARB,
     ext_wglCreateContextAttribsARB,
     ext_wglCreatePbufferARB,
     ext_wglDestroyPbufferARB,
     ext_wglFreeMemoryNV,
     ext_wglGetPbufferDCARB,
-    ext_wglGetPixelFormatAttribfvARB,
-    ext_wglGetPixelFormatAttribivARB,
     ext_wglGetSwapIntervalEXT,
     ext_wglMakeContextCurrentARB,
     ext_wglQueryCurrentRendererIntegerWINE,
@@ -33729,22 +33689,6 @@ static NTSTATUS wow64_wgl_wglSetPixelFormat( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS wow64_wgl_wglShareLists( void *args )
-{
-    struct
-    {
-        PTR32 teb;
-        PTR32 hrcSrvShare;
-        PTR32 hrcSrvSource;
-        BOOL ret;
-    } *params = args;
-    TEB *teb = get_teb64( params->teb );
-    const struct opengl_funcs *funcs = get_context_funcs( ULongToPtr(params->hrcSrvShare) );
-    if (!funcs || !funcs->p_wglShareLists) return STATUS_NOT_IMPLEMENTED;
-    params->ret = wrap_wglShareLists( teb, ULongToPtr(params->hrcSrvShare), ULongToPtr(params->hrcSrvSource) );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS wow64_wgl_wglSwapBuffers( void *args )
 {
     struct
@@ -86625,25 +86569,6 @@ static NTSTATUS wow64_ext_wglBindTexImageARB( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS wow64_ext_wglChoosePixelFormatARB( void *args )
-{
-    struct
-    {
-        PTR32 teb;
-        PTR32 hdc;
-        PTR32 piAttribIList;
-        PTR32 pfAttribFList;
-        UINT nMaxFormats;
-        PTR32 piFormats;
-        PTR32 nNumFormats;
-        BOOL ret;
-    } *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( ULongToPtr(params->hdc) );
-    if (!funcs || !funcs->p_wglChoosePixelFormatARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglChoosePixelFormatARB( ULongToPtr(params->hdc), ULongToPtr(params->piAttribIList), ULongToPtr(params->pfAttribFList), params->nMaxFormats, ULongToPtr(params->piFormats), ULongToPtr(params->nNumFormats) );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS wow64_ext_wglCreateContextAttribsARB( void *args )
 {
     struct
@@ -86722,44 +86647,6 @@ static NTSTATUS wow64_ext_wglGetPbufferDCARB( void *args )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS wow64_ext_wglGetPixelFormatAttribfvARB( void *args )
-{
-    struct
-    {
-        PTR32 teb;
-        PTR32 hdc;
-        int iPixelFormat;
-        int iLayerPlane;
-        UINT nAttributes;
-        PTR32 piAttributes;
-        PTR32 pfValues;
-        BOOL ret;
-    } *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( ULongToPtr(params->hdc) );
-    if (!funcs || !funcs->p_wglGetPixelFormatAttribfvARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglGetPixelFormatAttribfvARB( ULongToPtr(params->hdc), params->iPixelFormat, params->iLayerPlane, params->nAttributes, ULongToPtr(params->piAttributes), ULongToPtr(params->pfValues) );
-    return STATUS_SUCCESS;
-}
-
-static NTSTATUS wow64_ext_wglGetPixelFormatAttribivARB( void *args )
-{
-    struct
-    {
-        PTR32 teb;
-        PTR32 hdc;
-        int iPixelFormat;
-        int iLayerPlane;
-        UINT nAttributes;
-        PTR32 piAttributes;
-        PTR32 piValues;
-        BOOL ret;
-    } *params = args;
-    const struct opengl_funcs *funcs = get_dc_funcs( ULongToPtr(params->hdc) );
-    if (!funcs || !funcs->p_wglGetPixelFormatAttribivARB) return STATUS_NOT_IMPLEMENTED;
-    params->ret = funcs->p_wglGetPixelFormatAttribivARB( ULongToPtr(params->hdc), params->iPixelFormat, params->iLayerPlane, params->nAttributes, ULongToPtr(params->piAttributes), ULongToPtr(params->piValues) );
-    return STATUS_SUCCESS;
-}
-
 static NTSTATUS wow64_ext_wglGetSwapIntervalEXT( void *args )
 {
     struct
@@ -86957,7 +86844,6 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
     wow64_wgl_wglDeleteContext,
     wow64_wgl_wglGetPixelFormat,
     wow64_wgl_wglSetPixelFormat,
-    wow64_wgl_wglShareLists,
     wow64_wgl_wglSwapBuffers,
     wow64_gl_glAccum,
     wow64_gl_glAlphaFunc,
@@ -90030,14 +89916,11 @@ const unixlib_entry_t __wine_unix_call_wow64_funcs[] =
     wow64_ext_glWriteMaskEXT,
     wow64_ext_wglAllocateMemoryNV,
     wow64_ext_wglBindTexImageARB,
-    wow64_ext_wglChoosePixelFormatARB,
     wow64_ext_wglCreateContextAttribsARB,
     wow64_ext_wglCreatePbufferARB,
     wow64_ext_wglDestroyPbufferARB,
     wow64_ext_wglFreeMemoryNV,
     wow64_ext_wglGetPbufferDCARB,
-    wow64_ext_wglGetPixelFormatAttribfvARB,
-    wow64_ext_wglGetPixelFormatAttribivARB,
     wow64_ext_wglGetSwapIntervalEXT,
     wow64_ext_wglMakeContextCurrentARB,
     wow64_ext_wglQueryCurrentRendererIntegerWINE,
@@ -90077,11 +89960,6 @@ static BOOL null_wglSetPixelFormat( HDC hdc, int ipfd, const PIXELFORMATDESCRIPT
     WARN( "unsupported\n" );
     return 0;
 }
-static BOOL null_wglShareLists( HGLRC hrcSrvShare, HGLRC hrcSrvSource )
-{
-    WARN( "unsupported\n" );
-    return 0;
-}
 static BOOL null_wglSwapBuffers( HDC hdc )
 {
     WARN( "unsupported\n" );
@@ -91446,7 +91324,6 @@ struct opengl_funcs null_opengl_funcs =
     .p_wglDeleteContext = null_wglDeleteContext,
     .p_wglGetPixelFormat = null_wglGetPixelFormat,
     .p_wglSetPixelFormat = null_wglSetPixelFormat,
-    .p_wglShareLists = null_wglShareLists,
     .p_wglSwapBuffers = null_wglSwapBuffers,
     .p_glAccum = null_glAccum,
     .p_glAlphaFunc = null_glAlphaFunc,
diff --git a/dlls/opengl32/unix_thunks.h b/dlls/opengl32/unix_thunks.h
index 77c5b81218d9..bc83223cdef0 100644
--- a/dlls/opengl32/unix_thunks.h
+++ b/dlls/opengl32/unix_thunks.h
@@ -4,7 +4,6 @@ typedef ULONG PTR32;
 
 extern BOOL wrap_wglCopyContext( TEB *teb, HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask );
 extern BOOL wrap_wglDeleteContext( TEB *teb, HGLRC oldContext );
-extern BOOL wrap_wglShareLists( TEB *teb, HGLRC hrcSrvShare, HGLRC hrcSrvSource );
 extern BOOL wrap_wglSwapBuffers( TEB *teb, HDC hdc );
 extern void wrap_glClear( TEB *teb, GLbitfield mask, PFN_glClear func );
 extern void wrap_glDrawBuffer( TEB *teb, GLenum buf, PFN_glDrawBuffer func );
diff --git a/dlls/opengl32/unix_wgl.c b/dlls/opengl32/unix_wgl.c
index fbf5654aeaac..46a8bb21abfd 100644
--- a/dlls/opengl32/unix_wgl.c
+++ b/dlls/opengl32/unix_wgl.c
@@ -127,8 +127,6 @@ struct context
     struct opengl_context base;
 
     HGLRC client;                  /* client-side context handle */
-    HGLRC share;                   /* context to be shared with */
-    int *attribs;                  /* creation attributes */
     UINT64 debug_callback;         /* client pointer */
     UINT64 debug_user;             /* client pointer */
     GLubyte *extensions;           /* extension string */
@@ -187,6 +185,7 @@ struct vk_device
 
 static ULONG_PTR zero_bits;
 
+static struct buffers *buffers;
 static const struct vulkan_funcs *vk_funcs;
 static VkInstance vk_instance;
 static PFN_vkDestroyInstance p_vkDestroyInstance;
@@ -409,7 +408,7 @@ void free_buffer( const struct opengl_funcs *funcs, struct buffer *buffer )
     free( buffer );
 }
 
-static void release_buffers( const struct opengl_funcs *funcs, struct buffers *buffers )
+static void release_buffers( const struct opengl_funcs *funcs )
 {
     struct buffer *buffer, *next;
 
@@ -418,62 +417,24 @@ static void release_buffers( const struct opengl_funcs *funcs, struct buffers *b
     RB_FOR_EACH_ENTRY_DESTRUCTOR( buffer, next, &buffers->map, struct buffer, entry )
         free_buffer( funcs, buffer );
     free( buffers );
+    buffers = NULL;
 }
 
-static struct context *context_from_client_context( HGLRC client_context )
-{
-    struct opengl_context *base = opengl_context_from_handle( client_context );
-    return base ? CONTAINING_RECORD( base, struct context, base ) : NULL;
-}
-
-static struct context *get_updated_context( TEB *teb, HGLRC client_context );
-
-/* update context if it has been re-shared with another one */
-static struct context *update_context( TEB *teb, HGLRC client_context, struct context *ctx )
+static struct buffers *acquire_buffers(void)
 {
-    struct opengl_client_context *client = opengl_client_context_from_client( client_context );
-    const struct opengl_funcs *funcs = get_context_funcs( client_context );
-    struct context *share;
-
-    if (client->current_tid) return ctx; /* currently in use */
-    if (ctx->share == (HGLRC)-1) return ctx; /* not re-shared */
-
-    share = ctx->share ? get_updated_context( teb, ctx->share ) : NULL;
-    if (!funcs->p_context_reset( &ctx->base, share ? &share->base : NULL, ctx->attribs ))
-    {
-        WARN( "Failed to re-create context for wglShareLists\n" );
-        return ctx;
-    }
-    if (share && share->buffers)
+    if (buffers) buffers->ref++;
+    else if ((buffers = calloc( 1, sizeof(*buffers ))))
     {
-        release_buffers( funcs, ctx->buffers );
-        ctx->buffers = share->buffers;
-        ctx->buffers->ref++;
+        buffers->ref = 1;
+        rb_init( &buffers->map, compare_buffer_name );
     }
-    ctx->share = (HGLRC)-1; /* initial shared context */
-    copy_context_attributes( teb, client_context, ctx, client_context, ctx, ctx->used );
-    return ctx;
+    return buffers;
 }
 
-static struct context *get_updated_context( TEB *teb, HGLRC client_context )
-{
-    struct context *context = context_from_client_context( client_context );
-    return client_context ? update_context( teb, client_context, context ) : NULL;
-}
-
-static int *memdup_attribs( const int *attribs )
+static struct context *context_from_client_context( HGLRC client_context )
 {
-    const int *attr;
-    size_t size;
-    int *copy;
-
-    if (!(attr = attribs)) return NULL;
-    while (*attr++) { /* nothing */ }
-
-    size = (attr - attribs) * sizeof(*attr);
-    if (!(copy = malloc( size ))) return NULL;
-    memcpy( copy, attribs, size );
-    return copy;
+    struct opengl_context *base = opengl_context_from_handle( client_context );
+    return base ? CONTAINING_RECORD( base, struct context, base ) : NULL;
 }
 
 struct extension_entry
@@ -849,8 +810,8 @@ const GLubyte *wrap_glGetString( TEB *teb, GLenum name, PFN_glGetString p_glGetS
 BOOL wrap_wglCopyContext( TEB *teb, HGLRC client_src, HGLRC client_dst, UINT mask )
 {
     struct context *src, *dst;
-    if (!(src = get_updated_context( teb, client_src ))) return FALSE;
-    if (!(dst = get_updated_context( teb, client_dst ))) return FALSE;
+    if (!(src = context_from_client_context( client_src ))) return FALSE;
+    if (!(dst = context_from_client_context( client_dst ))) return FALSE;
     return copy_context_attributes( teb, client_dst, dst, client_src, src, mask );
 }
 
@@ -869,7 +830,7 @@ static BOOL initialize_vk_device( TEB *teb, struct context *ctx )
     static PFN_vkGetPhysicalDeviceMemoryProperties p_vkGetPhysicalDeviceMemoryProperties;
     static PFN_vkGetPhysicalDeviceProperties2KHR p_vkGetPhysicalDeviceProperties2KHR;
 
-    if (ctx->buffers->vk_device) return TRUE; /* already initialized */
+    if (buffers->vk_device) return TRUE; /* already initialized */
     if (!client->extensions[GL_EXT_memory_object_win32] )
     {
         TRACE( "GL_EXT_memory_object_win32 is not supported\n" );
@@ -930,7 +891,7 @@ static BOOL initialize_vk_device( TEB *teb, struct context *ctx )
             vk_device = RB_ENTRY_VALUE( entry, struct vk_device, entry );
             if (!vk_device->vk_device) continue; /* known incompatible device */
             TRACE( "Found existing device %p for uuid %s\n", vk_device, debugstr_guid(&vk_device->uuid) );
-            ctx->buffers->vk_device = vk_device;
+            buffers->vk_device = vk_device;
             free( vk_physical_devices );
             return TRUE;
         }
@@ -1083,7 +1044,6 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD
     TRACE( "context %p version %d.%d\n", ctx, client->major_version, client->minor_version );
 
     funcs->p_init_extensions( client->extensions );
-    funcs->p_glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &client->profile_mask );
 
     if (client->major_version >= 3)
     {
@@ -1095,6 +1055,10 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD
             enum opengl_extension ext = parse_extension( name, strlen( name ) );
             if (ext != GL_EXTENSION_COUNT) client->extensions[ext] = TRUE;
         }
+
+        if (client->major_version > 3 || client->minor_version > 1)
+            funcs->p_glGetIntegerv( GL_CONTEXT_PROFILE_MASK, &client->profile_mask );
+        funcs->p_glGetIntegerv( GL_CONTEXT_FLAGS, &client->context_flags );
     }
     else
     {
@@ -1140,11 +1104,11 @@ static void make_context_current( TEB *teb, const struct opengl_funcs *funcs, HD
     ctx->pixel_mode.read_buffer = ctx->base.draw->doublebuffer ? GL_BACK : GL_FRONT;
 }
 
-static void free_context( struct context *ctx )
+static void free_context( const struct opengl_funcs *funcs, struct context *ctx )
 {
+    if (ctx->buffers) release_buffers( funcs );
     free( ctx->wow64_version );
     free( ctx->extensions );
-    free( ctx->attribs );
     free( ctx );
 }
 
@@ -1153,7 +1117,7 @@ BOOL wrap_wglDeleteContext( TEB *teb, HGLRC client_context )
     const struct opengl_funcs *funcs = get_context_funcs( client_context );
     struct context *ctx = context_from_client_context( client_context );
     funcs->p_context_destroy( &ctx->base );
-    free_context( ctx );
+    free_context( funcs, ctx );
     return TRUE;
 }
 
@@ -1300,25 +1264,10 @@ BOOL wrap_wglSwapBuffers( TEB *teb, HDC hdc )
     return ret;
 }
 
-BOOL wrap_wglShareLists( TEB *teb, HGLRC client_src, HGLRC client_dst )
-{
-    const struct opengl_funcs *src_funcs = get_context_funcs( client_src ), *dst_funcs = get_context_funcs( client_dst );
-    struct context *src, *dst;
-    BOOL ret = FALSE;
-
-    if (!(src = context_from_client_context( client_src ))) return FALSE;
-    if (!(dst = context_from_client_context( client_dst ))) return FALSE;
-    if (src_funcs != dst_funcs) RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
-    else if ((ret = dst->used != -1)) dst->share = client_src;
-    else FIXME( "Unsupported attributes on context %p/%p\n", client_dst, dst );
-
-    return ret;
-}
-
 HGLRC wrap_wglCreateContextAttribsARB( TEB *teb, HDC hdc, HGLRC client_shared, const int *attribs, HGLRC client_context )
 {
     const struct opengl_funcs *funcs = get_dc_funcs( hdc );
-    struct context *context, *shared = get_updated_context( teb, client_shared );
+    struct context *context;
 
     if (!funcs->p_context_create) return 0;
     if (!(context = calloc( 1, sizeof(*context) )))
@@ -1327,32 +1276,12 @@ HGLRC wrap_wglCreateContextAttribsARB( TEB *teb, HDC hdc, HGLRC client_shared, c
         return 0;
     }
     context->base.client_context = client_context;
-    context->share = (HGLRC)-1; /* initial shared context */
-    context->attribs = memdup_attribs( attribs );
 
-    if (is_win64 && is_wow64())
-    {
-        if (shared)
-        {
-            context->buffers = shared->buffers;
-            context->buffers->ref++;
-        }
-        else if (!(context->buffers = malloc( sizeof(*context->buffers ))))
-        {
-            free_context( context );
-            return 0;
-        }
-        else
-        {
-            context->buffers->ref = 1;
-            context->buffers->vk_device = NULL;
-            rb_init( &context->buffers->map, compare_buffer_name );
-        }
-    }
+    if (is_win64 && is_wow64()) context->buffers = acquire_buffers();
 
-    if (!(funcs->p_context_create( &context->base, hdc, shared ? &shared->base : NULL, attribs )))
+    if (!(funcs->p_context_create( &context->base, hdc, attribs )))
     {
-        free_context( context );
+        free_context( funcs, context );
         return 0;
     }
 
@@ -1363,21 +1292,21 @@ HGLRC wrap_wglCreateContextAttribsARB( TEB *teb, HDC hdc, HGLRC client_shared, c
 
 BOOL wrap_wglMakeContextCurrentARB( TEB *teb, HDC draw_hdc, HDC read_hdc, HGLRC client_context )
 {
-    struct context *ctx, *prev = get_current_context( teb, NULL, NULL );
+    struct context *ctx;
 
     if (client_context)
     {
         const struct opengl_funcs *funcs = get_context_funcs( client_context );
-        if (!(ctx = get_updated_context( teb, client_context ))) return FALSE;
+        if (!(ctx = context_from_client_context( client_context ))) return FALSE;
         if (!funcs->p_wglMakeContextCurrentARB( draw_hdc, read_hdc, client_context )) return FALSE;
         make_context_current( teb, funcs, draw_hdc, read_hdc, client_context, ctx );
     }
-    else if (prev)
+    else
     {
         const struct opengl_funcs *funcs = teb->glTable;
         if (!funcs->p_wglMakeContextCurrentARB( NULL, NULL, NULL )) return FALSE;
-        teb->glTable = &null_opengl_funcs;
     }
+
     return TRUE;
 }
 
diff --git a/dlls/opengl32/unixlib.h b/dlls/opengl32/unixlib.h
index 7b3bfca130e2..8f5f6391bbef 100644
--- a/dlls/opengl32/unixlib.h
+++ b/dlls/opengl32/unixlib.h
@@ -53,14 +53,6 @@ struct wglSetPixelFormat_params
     BOOL ret;
 };
 
-struct wglShareLists_params
-{
-    TEB *teb;
-    HGLRC hrcSrvShare;
-    HGLRC hrcSrvSource;
-    BOOL ret;
-};
-
 struct wglSwapBuffers_params
 {
     TEB *teb;
@@ -25666,18 +25658,6 @@ struct wglBindTexImageARB_params
     BOOL ret;
 };
 
-struct wglChoosePixelFormatARB_params
-{
-    TEB *teb;
-    HDC hdc;
-    const int *piAttribIList;
-    const FLOAT *pfAttribFList;
-    UINT nMaxFormats;
-    int *piFormats;
-    UINT *nNumFormats;
-    BOOL ret;
-};
-
 struct wglCreateContextAttribsARB_params
 {
     TEB *teb;
@@ -25718,30 +25698,6 @@ struct wglGetPbufferDCARB_params
     HDC ret;
 };
 
-struct wglGetPixelFormatAttribfvARB_params
-{
-    TEB *teb;
-    HDC hdc;
-    int iPixelFormat;
-    int iLayerPlane;
-    UINT nAttributes;
-    const int *piAttributes;
-    FLOAT *pfValues;
-    BOOL ret;
-};
-
-struct wglGetPixelFormatAttribivARB_params
-{
-    TEB *teb;
-    HDC hdc;
-    int iPixelFormat;
-    int iLayerPlane;
-    UINT nAttributes;
-    const int *piAttributes;
-    int *piValues;
-    BOOL ret;
-};
-
 struct wglGetSwapIntervalEXT_params
 {
     TEB *teb;
@@ -25859,7 +25815,6 @@ enum unix_funcs
     unix_wglDeleteContext,
     unix_wglGetPixelFormat,
     unix_wglSetPixelFormat,
-    unix_wglShareLists,
     unix_wglSwapBuffers,
     unix_glAccum,
     unix_glAlphaFunc,
@@ -28932,14 +28887,11 @@ enum unix_funcs
     unix_glWriteMaskEXT,
     unix_wglAllocateMemoryNV,
     unix_wglBindTexImageARB,
-    unix_wglChoosePixelFormatARB,
     unix_wglCreateContextAttribsARB,
     unix_wglCreatePbufferARB,
     unix_wglDestroyPbufferARB,
     unix_wglFreeMemoryNV,
     unix_wglGetPbufferDCARB,
-    unix_wglGetPixelFormatAttribfvARB,
-    unix_wglGetPixelFormatAttribivARB,
     unix_wglGetSwapIntervalEXT,
     unix_wglMakeContextCurrentARB,
     unix_wglQueryCurrentRendererIntegerWINE,
diff --git a/dlls/opengl32/wgl.c b/dlls/opengl32/wgl.c
index d7f27dfab34e..40f5ca818159 100644
--- a/dlls/opengl32/wgl.c
+++ b/dlls/opengl32/wgl.c
@@ -113,6 +113,7 @@ static const char *debugstr_object_type( enum object_type type )
     case OBJ_TYPE_PROGRAM: return "program";
     case OBJ_TYPE_RENDERBUFFER: return "renderbuffer";
     case OBJ_TYPE_SEMAPHORE: return "semaphore";
+    case OBJ_TYPE_SHADER: return "shader";
     case OBJ_TYPE_SAMPLER: return "sampler";
     case OBJ_TYPE_SHADER_ATI: return "fragment shader";
     case OBJ_TYPE_SHADER_EXT: return "vertex shader";
@@ -153,6 +154,7 @@ struct handle_entry
 
 struct handle_table
 {
+    SRWLOCK              lock;
     struct handle_entry  handles[1024];
     struct handle_entry *next_free;
     UINT                 count;
@@ -166,6 +168,7 @@ static struct handle_entry *alloc_handle( struct handle_table *table, void *user
     struct handle_entry *ptr = NULL;
     WORD generation;
 
+    AcquireSRWLockExclusive( &table->lock );
     if ((ptr = table->next_free)) table->next_free = ptr->next_free;
     else if (table->count < ARRAY_SIZE(table->handles)) ptr = table->handles + table->count++;
     else ptr = NULL;
@@ -178,14 +181,17 @@ static struct handle_entry *alloc_handle( struct handle_table *table, void *user
     }
 
     if (!ptr) RtlSetLastWin32Error( ERROR_NOT_ENOUGH_MEMORY );
+    ReleaseSRWLockExclusive( &table->lock );
     return ptr;
 }
 
 static void free_handle( struct handle_table *table, struct handle_entry *ptr )
 {
+    AcquireSRWLockExclusive( &table->lock );
     ptr->handle |= 0xffff;
     ptr->next_free = table->next_free;
     table->next_free = ptr;
+    ReleaseSRWLockExclusive( &table->lock );
 }
 
 static struct handle_entry *get_handle_ptr( struct handle_table *table, HANDLE handle )
@@ -193,20 +199,22 @@ static struct handle_entry *get_handle_ptr( struct handle_table *table, HANDLE h
     WORD index = LOWORD( handle ) - 1;
     struct handle_entry *ptr = table->handles + index;
 
-    if (index < table->count && ULongToHandle( ptr->handle ) == handle) return ptr;
-    RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
-    return NULL;
+    AcquireSRWLockShared( &table->lock );
+    if (index >= table->count || ULongToHandle( ptr->handle ) != handle)
+    {
+        RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
+        ptr = NULL;
+    }
+    ReleaseSRWLockShared( &table->lock );
+
+    return ptr;
 }
 
 static struct opengl_client_pbuffer *pbuffer_from_handle( HPBUFFERARB handle )
 {
     struct handle_entry *ptr;
-
-    EnterCriticalSection( &wgl_cs );
-    ptr = get_handle_ptr( &pbuffers, handle );
-    LeaveCriticalSection( &wgl_cs );
-
-    return ptr ? ptr->pbuffer : NULL;
+    if (!(ptr = get_handle_ptr( &pbuffers, handle ))) return NULL;
+    return ptr->pbuffer;
 }
 
 BOOL get_pbuffer_from_handle( HPBUFFERARB handle, HPBUFFERARB *obj )
@@ -222,21 +230,14 @@ static struct handle_entry *alloc_client_pbuffer(void)
     struct handle_entry *ptr;
 
     if (!(pbuffer = calloc( 1, sizeof(*pbuffer) ))) return NULL;
-
-    EnterCriticalSection( &wgl_cs );
-    ptr = alloc_handle( &pbuffers, pbuffer );
-    LeaveCriticalSection( &wgl_cs );
-
-    if (!ptr) free( pbuffer );
+    if (!(ptr = alloc_handle( &pbuffers, pbuffer ))) free( pbuffer );
     return ptr;
 }
 
 static void free_client_pbuffer( struct handle_entry *ptr )
 {
     struct opengl_client_pbuffer *pbuffer = ptr->pbuffer;
-    EnterCriticalSection( &wgl_cs );
     free_handle( &pbuffers, ptr );
-    LeaveCriticalSection( &wgl_cs );
     free( pbuffer );
 }
 
@@ -267,11 +268,7 @@ BOOL WINAPI wglDestroyPbufferARB( HPBUFFERARB handle )
 
     TRACE( "handle %p\n", handle );
 
-    EnterCriticalSection( &wgl_cs );
-    ptr = get_handle_ptr( &pbuffers, handle );
-    LeaveCriticalSection( &wgl_cs );
-
-    if (!ptr) return FALSE;
+    if (!(ptr = get_handle_ptr( &pbuffers, handle ))) return FALSE;
     args.hPbuffer = &ptr->pbuffer->obj;
 
     if ((status = UNIX_CALL( wglDestroyPbufferARB, &args ))) WARN( "wglDestroyPbufferARB returned %#lx\n", status );
@@ -310,9 +307,10 @@ static GLuint *alloc_object_ids( GLuint **ids[L1_COUNT], GLuint client_id )
     return ptr[j];
 }
 
-static void free_object_ids( struct object_table *table, GLuint **ids[L1_COUNT] )
+static void free_object_ids( struct object_table *table, GLuint **ids[L1_COUNT],
+                             void (*callback)(struct object_table *, GLuint, GLuint) )
 {
-    GLuint **l1_block, *l2_block;
+    GLuint id, **l1_block, *l2_block;
 
     for (int i = 0; i < L1_COUNT; i++)
     {
@@ -320,6 +318,11 @@ static void free_object_ids( struct object_table *table, GLuint **ids[L1_COUNT]
         for (int j = 0; j < L2_COUNT; j++)
         {
             if (!(l2_block = l1_block[j])) continue;
+            for (int k = 0; callback && k < L3_COUNT; k++)
+            {
+                if (!(id = l2_block[k])) continue;
+                callback( table, id, (i * L2_COUNT + j) * L3_COUNT + k );
+            }
             free( l2_block );
         }
         free( l1_block );
@@ -349,7 +352,7 @@ static GLuint set_object( struct object_table *table, GLuint client_id, GLuint h
     if (!(ids = alloc_object_ids( table->host_ids, client_id ))) goto failed;
     ids[client_id % L3_COUNT] = host_id;
 
-    if (table->implicit)
+    if (table->implicit || table->type == OBJ_TYPE_SHADER /* for destruction check */)
     {
         if (!(ids = alloc_object_ids( table->client_ids, host_id ))) goto failed;
         ids[host_id % L3_COUNT] = client_id;
@@ -370,7 +373,7 @@ static GLuint del_object( struct object_table *table, GLuint client_id )
     if (!client_id || !(object = find_object_id( table->host_ids, client_id ))) return -1;
     table->min_free = min( table->min_free, client_id - 1 );
     host_id = *object;
-    *object = 0;
+    if (table->type != OBJ_TYPE_SHADER) *object = 0; /* shader objects may outlive their deletion */
     if (host_id && (object = find_object_id( table->client_ids, host_id ))) *object = 0;
 
     TRACE( "Deleting %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id );
@@ -405,6 +408,7 @@ static GLuint create_object( enum object_type type )
     case OBJ_TYPE_RENDERBUFFER: { MAKE_OBJECT_CALL( glGenRenderbuffers, .n = 1, .renderbuffers = &object ); return object; }
     case OBJ_TYPE_SAMPLER: { MAKE_OBJECT_CALL( glGenSamplers, .count = 1, .samplers = &object ); return object; }
     case OBJ_TYPE_SEMAPHORE: { MAKE_OBJECT_CALL( glGenSemaphoresEXT, .n = 1, .semaphores = &object ); return object; }
+    case OBJ_TYPE_SHADER: assert( 0 ); return 0;
     case OBJ_TYPE_SHADER_ATI: { MAKE_OBJECT_CALL( glGenFragmentShadersATI, .range = 1 ); return args.ret; }
     case OBJ_TYPE_SHADER_EXT: { MAKE_OBJECT_CALL( glGenVertexShadersEXT, .range = 1 ); return args.ret; }
     case OBJ_TYPE_TEXTURE: { MAKE_OBJECT_CALL( glGenTextures, .n = 1, .textures = &object ); return object; }
@@ -414,12 +418,48 @@ static GLuint create_object( enum object_type type )
     return 0;
 }
 
+static void destroy_object( enum object_type type, GLuint object )
+{
+    switch (type)
+    {
+    case OBJ_TYPE_BUFFER: { MAKE_OBJECT_CALL( glDeleteBuffers, .n = 1, .buffers = &object ); return; }
+    case OBJ_TYPE_DISPLAY_LIST: { MAKE_OBJECT_CALL( glDeleteLists, .range = 1, .list = object ); return; }
+    case OBJ_TYPE_FRAMEBUFFER: { MAKE_OBJECT_CALL( glDeleteFramebuffers, .n = 1, .framebuffers = &object ); return; }
+    case OBJ_TYPE_MEMORY: { MAKE_OBJECT_CALL( glDeleteMemoryObjectsEXT, .n = 1, .memoryObjects = &object ); return; }
+    case OBJ_TYPE_PATH: { MAKE_OBJECT_CALL( glDeletePathsNV, .range = 1, .path = object ); return; }
+    case OBJ_TYPE_PROGRAM: { MAKE_OBJECT_CALL( glDeleteProgramsARB, .n = 1, .programs = &object ); return; }
+    case OBJ_TYPE_RENDERBUFFER: { MAKE_OBJECT_CALL( glDeleteRenderbuffers, .n = 1, .renderbuffers = &object ); return; }
+    case OBJ_TYPE_SAMPLER: { MAKE_OBJECT_CALL( glDeleteSamplers, .count = 1, .samplers = &object ); return; }
+    case OBJ_TYPE_SEMAPHORE: { MAKE_OBJECT_CALL( glDeleteSemaphoresEXT, .n = 1, .semaphores = &object ); return; }
+    case OBJ_TYPE_SHADER: { MAKE_OBJECT_CALL( glDeleteObjectARB, .obj = object ); return; }
+    case OBJ_TYPE_SHADER_ATI: { MAKE_OBJECT_CALL( glDeleteFragmentShaderATI, .id = object ); return; }
+    case OBJ_TYPE_SHADER_EXT: { MAKE_OBJECT_CALL( glDeleteVertexShaderEXT, .id = object ); return; }
+    case OBJ_TYPE_TEXTURE: { MAKE_OBJECT_CALL( glDeleteTextures, .n = 1, .textures = &object ); return; }
+    case OBJ_TYPE_COUNT: return;
+    }
+}
+
 #undef MAKE_OBJECT_CALL
 
+static void destroy_host_object( struct object_table *table, GLuint host_id, GLuint client_id )
+{
+    WARN( "Destroying %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id );
+    destroy_object( table->type, host_id );
+}
+
+static void destroy_host_shader( struct object_table *table, GLuint host_id, GLuint client_id )
+{
+    GLuint *object;
+    if (!(object = find_object_id( table->client_ids, host_id )) || !(client_id = *object)) return;
+    WARN( "Destroying %s client %#x, host %#x\n", debugstr_object_type( table->type ), client_id, host_id );
+    destroy_object( table->type, host_id );
+}
+
 static void free_object_table( struct object_table *table )
 {
-    free_object_ids( table, table->host_ids );
-    free_object_ids( table, table->client_ids );
+    if (table->type == OBJ_TYPE_SHADER) free_object_ids( table, table->host_ids, destroy_host_shader );
+    else free_object_ids( table, table->host_ids, destroy_host_object );
+    free_object_ids( table, table->client_ids, NULL );
 }
 
 static void init_object_table( struct object_table *table, enum object_type type )
@@ -433,6 +473,7 @@ struct display_lists
     LONG                refcount;
     LONG                modified;
     struct object_table tables[OBJ_TYPE_COUNT];
+    struct handle_table syncs;
 };
 
 static struct display_lists *display_lists_create(void)
@@ -444,6 +485,7 @@ static struct display_lists *display_lists_create(void)
 
     for (UINT i = 0; i < OBJ_TYPE_COUNT; i++)
         init_object_table( lists->tables + i, i );
+    InitializeSRWLock( &lists->syncs.lock );
 
     return lists;
 }
@@ -456,21 +498,30 @@ static struct display_lists *display_lists_acquire( struct display_lists *lists
 
 static void display_lists_release( struct display_lists *lists )
 {
+    struct glDeleteSync_params delete_sync = { .teb = NtCurrentTeb() };
+
     if (InterlockedDecrement( &lists->refcount )) return;
 
     for (UINT i = 0; i < OBJ_TYPE_COUNT; i++)
         free_object_table( lists->tables + i );
 
+    for (int i = 0; i < lists->syncs.count; i++)
+    {
+        struct handle_entry *entry = lists->syncs.handles + i;
+        if (LOWORD(entry->handle) == 0xffff) continue;
+        WARN( "Leaking sync client %#x, host %p\n", entry->handle, entry->user_data );
+        delete_sync.sync = entry->user_data;
+        UNIX_CALL( glDeleteSync, &delete_sync );
+        free( entry->user_data );
+    }
+
     free( lists );
 }
 
 struct context
 {
     struct opengl_client_context base;
-    struct handle_table          syncs;
-    struct display_lists        *lists;
-
-    GLuint list_base;
+    struct display_lists *lists;
 };
 
 static struct context *context_from_opengl_client_context( struct opengl_client_context *base )
@@ -481,12 +532,8 @@ static struct context *context_from_opengl_client_context( struct opengl_client_
 static struct opengl_client_context *opengl_client_context_from_handle( HGLRC handle )
 {
     struct handle_entry *ptr;
-
-    EnterCriticalSection( &wgl_cs );
-    ptr = get_handle_ptr( &contexts, handle );
-    LeaveCriticalSection( &wgl_cs );
-
-    return ptr ? ptr->context : NULL;
+    if (!(ptr = get_handle_ptr( &contexts, handle ))) return NULL;
+    return ptr->context;
 }
 
 static struct context *context_from_handle( HGLRC handle )
@@ -508,11 +555,7 @@ static struct handle_entry *alloc_client_context( struct context *share )
 
     if (!(context = calloc( 1, sizeof(*context) ))) return NULL;
     if (!(context->lists = share ? display_lists_acquire( share->lists ) : display_lists_create())) goto failed;
-
-    EnterCriticalSection( &wgl_cs );
-    ptr = alloc_handle( &contexts, context );
-    LeaveCriticalSection( &wgl_cs );
-    if (ptr) return ptr;
+    if ((ptr = alloc_handle( &contexts, context ))) return ptr;
 
     display_lists_release( context->lists );
 failed:
@@ -524,20 +567,18 @@ static void free_client_context( struct handle_entry *ptr )
 {
     struct context *context = context_from_opengl_client_context( ptr->context );
 
-    for (int i = 0; i < context->syncs.count; i++)
-    {
-        struct handle_entry *entry = context->syncs.handles + i;
-        if (LOWORD(entry->handle) == 0xffff) continue;
-        free( entry->user_data );
-    }
     display_lists_release( context->lists );
 
-    EnterCriticalSection( &wgl_cs );
     free_handle( &contexts, ptr );
-    LeaveCriticalSection( &wgl_cs );
     free( context );
 }
 
+static struct context *get_current_context(void)
+{
+    HGLRC current = NtCurrentTeb()->glCurrentRC;
+    return current ? context_from_handle( current ) : NULL;
+}
+
 void set_gl_error( GLenum error )
 {
     struct opengl_client_context *context;
@@ -556,7 +597,7 @@ void put_context_objects( enum object_type type, UINT n, GLuint *handles )
     struct object_table *table;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return;
+    if (!(ctx = get_current_context())) return;
     if (!(table = get_object_table( ctx, type, TRUE ))) return;
 
     AcquireSRWLockExclusive( &table->lock );
@@ -570,7 +611,7 @@ GLuint put_context_object_range( enum object_type type, UINT range, GLuint base
     struct context *ctx;
     GLuint first;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return base;
+    if (!(ctx = get_current_context())) return base;
     if (!(table = get_object_table( ctx, type, TRUE ))) return base;
 
     AcquireSRWLockExclusive( &table->lock );
@@ -598,20 +639,29 @@ static void alloc_client_objects( struct context *ctx, enum object_type type, UI
     ReleaseSRWLockExclusive( &table->lock );
 }
 
+static BOOL is_core_context( struct opengl_client_context *ctx )
+{
+    if (ctx->major_version < 3) return FALSE;
+    if (ctx->major_version > 3) return !!(ctx->profile_mask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
+    if (ctx->minor_version > 1) return !!(ctx->profile_mask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
+    if (ctx->minor_version == 1) return !ctx->extensions[GL_ARB_compatibility];
+    return !!(ctx->context_flags & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT);
+}
+
 BOOL alloc_context_objects( enum object_type type, UINT n, const GLuint *handles, BOOL extension )
 {
     BOOL alloc_client, needs_client = FALSE;
     struct object_table *table;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return TRUE;
+    if (!(ctx = get_current_context())) return TRUE;
     if (!(table = get_object_table( ctx, type, FALSE ))) return TRUE;
 
     /* only allow explicit allocation in some cases, use host allocated ids directly in that case */
     switch (type)
     {
     case OBJ_TYPE_DISPLAY_LIST:
-        if (ctx->base.profile_mask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB) return FALSE;
+        if (is_core_context( &ctx->base )) return FALSE;
         alloc_client = TRUE;
         break;
     case OBJ_TYPE_FRAMEBUFFER:
@@ -625,10 +675,11 @@ BOOL alloc_context_objects( enum object_type type, UINT n, const GLuint *handles
         break;
     case OBJ_TYPE_SAMPLER:
     case OBJ_TYPE_MEMORY:
+    case OBJ_TYPE_SHADER:
         alloc_client = FALSE;
         break;
     default:
-        alloc_client = !(ctx->base.profile_mask & WGL_CONTEXT_CORE_PROFILE_BIT_ARB);
+        alloc_client = !is_core_context( &ctx->base );
         break;
     }
 
@@ -649,7 +700,7 @@ GLuint *del_context_objects( enum object_type type, UINT n, GLuint *handles )
     struct object_table *table;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return handles;
+    if (!(ctx = get_current_context())) return handles;
     if (!(table = get_object_table( ctx, type, FALSE ))) return handles;
 
     AcquireSRWLockExclusive( &table->lock );
@@ -664,7 +715,7 @@ GLuint *map_context_objects( enum object_type type, UINT n, GLuint *handles )
     struct object_table *table;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return handles;
+    if (!(ctx = get_current_context())) return handles;
     if (!(table = get_object_table( ctx, type, FALSE ))) return handles;
 
     AcquireSRWLockShared( &table->lock );
@@ -745,6 +796,15 @@ static GLuint get_pname_object_type( GLenum pname )
     case GL_VERTEX_PROGRAM_BINDING_NV:
     case GL_FRAGMENT_PROGRAM_BINDING_NV:
         return OBJ_TYPE_PROGRAM;
+    case GL_COMPUTE_SHADER:
+    case GL_CURRENT_PROGRAM:
+    case GL_FRAGMENT_SHADER:
+    case GL_GEOMETRY_SHADER:
+    case GL_TESS_CONTROL_SHADER:
+    case GL_TESS_EVALUATION_SHADER:
+    case GL_VERTEX_SHADER:
+    case GL_ACTIVE_PROGRAM:
+        return OBJ_TYPE_SHADER;
     case GL_VERTEX_SHADER_BINDING_EXT:
         return OBJ_TYPE_SHADER_EXT;
     }
@@ -759,7 +819,7 @@ static BOOL map_client_objects( enum object_type type, GLuint host_id, GLuint *r
     struct context *ctx;
 
     if (!host_id || type == OBJ_TYPE_COUNT) return FALSE;
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return FALSE;
+    if (!(ctx = get_current_context())) return FALSE;
     if (!(table = get_object_table( ctx, type, FALSE ))) return FALSE;
 
     AcquireSRWLockShared( &table->lock );
@@ -882,11 +942,7 @@ BOOL WINAPI wglDeleteContext( HGLRC handle )
 
     TRACE( "handle %p\n", handle );
 
-    EnterCriticalSection( &wgl_cs );
-    ptr = get_handle_ptr( &contexts, handle );
-    LeaveCriticalSection( &wgl_cs );
-
-    if (!ptr) return FALSE;
+    if (!(ptr = get_handle_ptr( &contexts, handle ))) return FALSE;
     args.oldContext = &ptr->context->obj;
 
     if (handle == teb->glCurrentRC) wglMakeCurrent( NULL, NULL );
@@ -899,6 +955,8 @@ BOOL WINAPI wglDeleteContext( HGLRC handle )
     if ((status = UNIX_CALL( wglDeleteContext, &args ))) WARN( "wglDeleteContext returned %#lx\n", status );
     if (status || !args.ret) return FALSE;
 
+    /* make sure there's a (dummy) context before releasing and destroying display list objects */
+    if (!teb->glCurrentRC) wglMakeContextCurrentARB( NULL, NULL, NULL );
     free_client_context( ptr );
     return TRUE;
 }
@@ -947,10 +1005,8 @@ BOOL WINAPI wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC handle )
  */
 BOOL WINAPI wglShareLists( HGLRC src_handle, HGLRC dst_handle )
 {
-    struct wglShareLists_params args = { .teb = NtCurrentTeb() };
     struct context *src_context, *dst_context;
     struct display_lists *lists;
-    NTSTATUS status;
 
     TRACE( "src_handle %p, dst_handle %p\n", src_handle, dst_handle );
 
@@ -958,11 +1014,6 @@ BOOL WINAPI wglShareLists( HGLRC src_handle, HGLRC dst_handle )
     if (!(dst_context = context_from_handle( dst_handle ))) return FALSE;
     if (ReadNoFence( &dst_context->lists->modified )) return FALSE;
 
-    args.hrcSrvShare = &src_context->base.obj;
-    args.hrcSrvSource = &dst_context->base.obj;
-    if ((status = UNIX_CALL( wglShareLists, &args ))) WARN( "wglShareLists returned %#lx\n", status );
-    if (!args.ret) return FALSE;
-
     lists = display_lists_acquire( src_context->lists );
     lists = InterlockedExchangePointer( (void *)&dst_context->lists, lists );
     display_lists_release( lists );
@@ -1626,28 +1677,6 @@ BOOL WINAPI wglChoosePixelFormatARB( HDC hdc, const int *attribs_int, const FLOA
 
     wgl_formats = get_pixel_formats( hdc, &num_wgl_formats, &num_wgl_onscreen_formats );
 
-    /* If the driver doesn't yet provide ARB attrib information in
-     * wgl_pixel_format, fall back to an explicit call. */
-    if (num_wgl_formats && !wgl_formats[0].pixel_type)
-    {
-        struct wglChoosePixelFormatARB_params args =
-        {
-            .teb = NtCurrentTeb(),
-            .hdc = hdc,
-            .piAttribIList = attribs_int,
-            .pfAttribFList = attribs_float,
-            .nMaxFormats = max_formats,
-            .piFormats = formats,
-            .nNumFormats = num_formats
-        };
-        NTSTATUS status;
-
-        if ((status = UNIX_CALL( wglChoosePixelFormatARB, &args )))
-            WARN( "wglChoosePixelFormatARB returned %#lx\n", status );
-
-        return args.ret;
-    }
-
     /* Gather, validate and deduplicate all attributes */
     for (i = 0; attribs_int && attribs_int[i]; i += 2)
     {
@@ -1730,28 +1759,6 @@ BOOL WINAPI wglGetPixelFormatAttribivARB( HDC hdc, int index, int plane, UINT co
 
     formats = get_pixel_formats( hdc, &num_formats, &num_onscreen_formats );
 
-    /* If the driver doesn't yet provide ARB attrib information in
-     * wgl_pixel_format, fall back to an explicit call. */
-    if (num_formats && !formats[0].pixel_type)
-    {
-        struct wglGetPixelFormatAttribivARB_params args =
-        {
-            .teb = NtCurrentTeb(),
-            .hdc = hdc,
-            .iPixelFormat = index,
-            .iLayerPlane = plane,
-            .nAttributes = count,
-            .piAttributes = attributes,
-            .piValues = values
-        };
-        NTSTATUS status;
-
-        if ((status = UNIX_CALL( wglGetPixelFormatAttribivARB, &args )))
-            WARN( "wglGetPixelFormatAttribivARB returned %#lx\n", status );
-
-        return args.ret;
-    }
-
     if (!count) return TRUE;
     if (count == 1 && attributes[0] == WGL_NUMBER_PIXEL_FORMATS_ARB)
     {
@@ -1905,7 +1912,7 @@ PROC WINAPI wglGetProcAddress( LPCSTR name )
     const enum opengl_extension *ext;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return NULL;
+    if (!(ctx = get_current_context())) return NULL;
 
     if (!(func = get_function_entry( name )))
     {
@@ -2447,6 +2454,79 @@ BOOL WINAPI wglUseFontOutlinesW(HDC hdc,
     return wglUseFontOutlines_common(hdc, first, count, listBase, deviation, extrusion, format, lpgmf, TRUE);
 }
 
+GLhandleARB WINAPI glGetHandleARB( GLenum pname )
+{
+    struct glGetHandleARB_params args = { .teb = NtCurrentTeb(), .pname = pname };
+    GLuint *object, client_id = 0;
+    struct object_table *table;
+    struct context *ctx;
+    NTSTATUS status;
+
+    TRACE( "pname %d\n", pname );
+
+    if ((status = UNIX_CALL( glGetHandleARB, &args ))) WARN( "glGetHandleARB returned %#lx\n", status );
+    if (!args.ret) return args.ret;
+
+    if (!(ctx = context_from_handle( args.teb->glCurrentRC ))) return 0;
+    if (!(table = get_object_table( ctx, OBJ_TYPE_SHADER, FALSE ))) return 0;
+
+    AcquireSRWLockShared( &table->lock );
+    if ((object = find_object_id( table->client_ids, args.ret ))) client_id = *object;
+    ReleaseSRWLockShared( &table->lock );
+
+    return client_id;
+}
+
+void WINAPI glGetAttachedObjectsARB( GLhandleARB container, GLsizei max_count, GLsizei *count, GLhandleARB *obj )
+{
+    struct glGetAttachedObjectsARB_params args = { .teb = NtCurrentTeb(), .maxCount = max_count, .count = count };
+    struct object_table *table;
+    struct context *ctx;
+    NTSTATUS status;
+    GLuint *object;
+
+    TRACE( "container %d, max_count %d, count %p, obj %p\n", container, max_count, count, obj );
+
+    args.containerObj = *map_context_objects( OBJ_TYPE_SHADER, 1, &container );
+    if ((status = UNIX_CALL( glGetAttachedObjectsARB, &args ))) WARN( "glGetAttachedObjectsARB returned %#lx\n", status );
+
+    if (!(ctx = context_from_handle( args.teb->glCurrentRC ))) return;
+    if (!(table = get_object_table( ctx, OBJ_TYPE_SHADER, FALSE ))) return;
+
+    AcquireSRWLockShared( &table->lock );
+    for (UINT i = 0; i < max_count; ++i)
+    {
+        if (!obj[i] || !(object = find_object_id( table->client_ids, obj[i] ))) continue;
+        obj[i] = *object;
+    }
+    ReleaseSRWLockShared( &table->lock );
+}
+
+void WINAPI glGetAttachedShaders( GLuint program, GLsizei max_count, GLsizei *count, GLuint *shaders )
+{
+    struct glGetAttachedShaders_params args = { .teb = NtCurrentTeb(), .maxCount = max_count, .count = count };
+    struct object_table *table;
+    struct context *ctx;
+    NTSTATUS status;
+    GLuint *object;
+
+    TRACE( "program %d, max_count %d, count %p, shaders %p\n", program, max_count, count, shaders );
+
+    args.program = *map_context_objects( OBJ_TYPE_SHADER, 1, &program );
+    if ((status = UNIX_CALL( glGetAttachedShaders, &args ))) WARN( "glGetAttachedShaders returned %#lx\n", status );
+
+    if (!(ctx = context_from_handle( args.teb->glCurrentRC ))) return;
+    if (!(table = get_object_table( ctx, OBJ_TYPE_SHADER, FALSE ))) return;
+
+    AcquireSRWLockShared( &table->lock );
+    for (UINT i = 0; i < max_count; ++i)
+    {
+        if (!shaders[i] || !(object = find_object_id( table->client_ids, shaders[i] ))) continue;
+        shaders[i] = *object;
+    }
+    ReleaseSRWLockShared( &table->lock );
+}
+
 /***********************************************************************
  *              glDebugEntry (OPENGL32.@)
  */
@@ -2460,8 +2540,8 @@ static GLsync sync_from_handle( GLsync handle )
     struct handle_entry *ptr;
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return NULL;
-    if (!(ptr = get_handle_ptr( &ctx->syncs, handle ))) return NULL;
+    if (!(ctx = get_current_context())) return NULL;
+    if (!(ptr = get_handle_ptr( &ctx->lists->syncs, handle ))) return NULL;
     return ptr->user_data;
 }
 
@@ -2477,19 +2557,16 @@ static struct handle_entry *alloc_client_sync( struct context *ctx )
     GLsync sync;
 
     if (!(sync = calloc( 1, sizeof(*sync) ))) return NULL;
-    if (!(ptr = alloc_handle( &ctx->syncs, sync )))
-    {
-        free( sync );
-        return NULL;
-    }
-
+    if (!(ptr = alloc_handle( &ctx->lists->syncs, sync ))) free( sync );
+    else InterlockedExchange( &ctx->lists->modified, 1 );
     return ptr;
 }
 
 static void free_client_sync( struct context *ctx, struct handle_entry *ptr )
 {
     GLsync sync = ptr->user_data;
-    free_handle( &ctx->syncs, ptr );
+    InterlockedExchange( &ctx->lists->modified, 1 );
+    free_handle( &ctx->lists->syncs, ptr );
     free( sync );
 }
 
@@ -2526,7 +2603,7 @@ void WINAPI glDeleteSync( GLsync sync )
     TRACE( "sync %p\n", sync );
 
     if (!(ctx = context_from_handle( teb->glCurrentRC ))) return;
-    if (!(ptr = get_handle_ptr( &ctx->syncs, sync ))) return set_gl_error( GL_INVALID_VALUE );
+    if (!(ptr = get_handle_ptr( &ctx->lists->syncs, sync ))) return set_gl_error( GL_INVALID_VALUE );
     args.sync = ptr->user_data;
 
     if ((status = UNIX_CALL( glDeleteSync, &args ))) WARN( "glDeleteSync returned %#lx\n", status );
@@ -2581,10 +2658,13 @@ BOOL get_integer( GLenum name, GLuint index, GLint value, GLint *data )
 {
     struct context *ctx;
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return FALSE;
+    if (!(ctx = get_current_context())) return FALSE;
 
     switch (name)
     {
+    case GL_CONTEXT_FLAGS:
+        *data = ctx->base.context_flags;
+        return TRUE;
     case GL_CONTEXT_PROFILE_MASK:
         *data = ctx->base.profile_mask;
         return TRUE;
@@ -2618,7 +2698,7 @@ const GLubyte * WINAPI glGetStringi( GLenum name, GLuint index )
 
     TRACE( "name %d, index %d\n", name, index );
 
-    if (!(ctx = context_from_handle( NtCurrentTeb()->glCurrentRC ))) return NULL;
+    if (!(ctx = get_current_context())) return NULL;
 
     switch (name)
     {
@@ -2745,6 +2825,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
     {
         .call_gl_debug_message_callback = (UINT_PTR)call_gl_debug_message_callback,
     };
+    struct context *context;
     NTSTATUS status;
 
     switch(reason)
@@ -2774,6 +2855,7 @@ BOOL WINAPI DllMain( HINSTANCE hinst, DWORD reason, LPVOID reserved )
 #endif
         /* fallthrough */
     case DLL_THREAD_DETACH:
+        if ((context = get_current_context())) context->base.current_tid = 0;
         free( NtCurrentTeb()->glReserved1[WINE_GL_RESERVED_FORMATS_PTR] );
         return TRUE;
     }
diff --git a/dlls/resampledmo/Makefile.in b/dlls/resampledmo/Makefile.in
index 73c59999c023..2483d3b83e0d 100644
--- a/dlls/resampledmo/Makefile.in
+++ b/dlls/resampledmo/Makefile.in
@@ -1,6 +1,8 @@
 MODULE    = resampledmo.dll
-IMPORTS   = combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid
+IMPORTS   = $(FFMPEG_PE_LIBS) combase mfplat msdmo mfuuid dmoguids strmiids wmcodecdspuuid uuid
+EXTRAINCL = $(FFMPEG_PE_CFLAGS)
 
 SOURCES = \
 	resampledmo.c \
-	resampledmo.idl
+	resampledmo.idl \
+	resampler.c
diff --git a/dlls/resampledmo/resampledmo.c b/dlls/resampledmo/resampledmo.c
index 486a379b7de9..30d2b8f54109 100644
--- a/dlls/resampledmo/resampledmo.c
+++ b/dlls/resampledmo/resampledmo.c
@@ -33,41 +33,7 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(dmo);
 
-static HRESULT WINAPI resampler_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
-        REFIID riid, void **out)
-{
-    static const GUID CLSID_wg_resampler = {0x92f35e78,0x15a5,0x486b,{0x88,0x8e,0x57,0x5f,0x99,0x65,0x1c,0xe2}};
-    return CoCreateInstance(&CLSID_wg_resampler, outer, CLSCTX_INPROC_SERVER, riid, out);
-}
-
-static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
-{
-    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
-    return *out ? S_OK : E_NOINTERFACE;
-}
-static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
-{
-    return 2;
-}
-static ULONG WINAPI class_factory_Release(IClassFactory *iface)
-{
-    return 1;
-}
-static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
-{
-    return S_OK;
-}
-
-static const IClassFactoryVtbl resampler_factory_vtbl =
-{
-    class_factory_QueryInterface,
-    class_factory_AddRef,
-    class_factory_Release,
-    resampler_factory_CreateInstance,
-    class_factory_LockServer,
-};
-
-static IClassFactory resampler_factory = {&resampler_factory_vtbl};
+extern IClassFactory resampler_factory;
 
 /***********************************************************************
  *              DllGetClassObject (resampledmo.@)
diff --git a/dlls/resampledmo/resampler.c b/dlls/resampledmo/resampler.c
new file mode 100644
index 000000000000..5452e2d8c559
--- /dev/null
+++ b/dlls/resampledmo/resampler.c
@@ -0,0 +1,1356 @@
+/* Copyright 2022 Rémi Bernon for CodeWeavers
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#define COBJMACROS
+#include "windef.h"
+#include "winbase.h"
+
+#include "dmoreg.h"
+#include "dmort.h"
+#include "dshow.h"
+#include "mediaerr.h"
+#include "mfapi.h"
+#include "mferror.h"
+#include "mfobjects.h"
+#include "mftransform.h"
+#include "wmcodecdsp.h"
+
+#include <libavutil/avutil.h>
+#include <libavutil/opt.h>
+#include <libswresample/swresample.h>
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(dmo);
+
+static const AVRational USER_TIME_BASE_Q = {1, 10000000};
+
+static void clear_dmo_media_type(DMO_MEDIA_TYPE *mt)
+{
+    MoFreeMediaType(mt);
+    memset(mt, 0, sizeof(*mt));
+}
+
+static enum AVSampleFormat sample_format_from_wave_format_tag(UINT tag, UINT depth)
+{
+    switch (tag)
+    {
+    case WAVE_FORMAT_PCM:
+        if (depth == 32) return AV_SAMPLE_FMT_S32;
+        if (depth == 16) return AV_SAMPLE_FMT_S16;
+        if (depth == 8)  return AV_SAMPLE_FMT_U8;
+        break;
+    case WAVE_FORMAT_IEEE_FLOAT:
+        if (depth == 64) return AV_SAMPLE_FMT_DBL;
+        if (depth == 32) return AV_SAMPLE_FMT_FLT;
+        break;
+    }
+
+    FIXME("Format tag %#x depth %#x implemented\n", tag, depth);
+    return AV_SAMPLE_FMT_NONE;
+}
+
+static void audio_frame_init_from_format(AVFrame *frame, const WAVEFORMATEXTENSIBLE *format)
+{
+    if (format->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+    {
+        WAVEFORMATEXTENSIBLE *extensible = CONTAINING_RECORD(format, WAVEFORMATEXTENSIBLE, Format);
+        frame->format = sample_format_from_wave_format_tag(extensible->SubFormat.Data1, extensible->Format.wBitsPerSample);
+        av_channel_layout_from_mask(&frame->ch_layout, extensible->dwChannelMask);
+    }
+    else
+    {
+        frame->format = sample_format_from_wave_format_tag(format->Format.wFormatTag, format->Format.wBitsPerSample);
+        av_channel_layout_default(&frame->ch_layout, format->Format.nChannels);
+    }
+    frame->sample_rate = format->Format.nSamplesPerSec;
+}
+
+static const char *debugstr_avtime(INT64 time, AVRational time_base)
+{
+    time = av_rescale_q_rnd(time, time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX);
+    if (time == AV_NOPTS_VALUE)
+        return "(none)";
+    return wine_dbg_sprintf("%I64d", time);
+}
+
+static void media_buffer_release(void *opaque, uint8_t *data)
+{
+    IMediaBuffer *media_buffer = opaque;
+    IMediaBuffer_Release(media_buffer);
+}
+
+static AVBufferRef *buffer_from_media_buffer(IMediaBuffer *media_buffer, int flags)
+{
+    AVBufferRef *buffer;
+    HRESULT hr;
+    DWORD size;
+    BYTE *data;
+
+    if (FAILED(hr = IMediaBuffer_GetBufferAndLength(media_buffer, &data, &size)))
+        return NULL;
+    if (!flags && FAILED(hr = IMediaBuffer_GetMaxLength(media_buffer, &size)))
+        return NULL;
+
+    if (!(buffer = av_buffer_create(data, size, media_buffer_release, media_buffer, flags)))
+        return NULL;
+    IMediaBuffer_AddRef(media_buffer);
+    return buffer;
+}
+
+static int audio_frame_wrap_buffer(AVFrame *frame, const WAVEFORMATEXTENSIBLE *format, AVBufferRef *buffer)
+{
+    int size;
+
+    TRACE("frame %p, type %p, buffer %p\n", frame, format, buffer);
+
+    audio_frame_init_from_format(frame, format);
+    frame->nb_samples = buffer->size / format->Format.nBlockAlign;
+
+    size = av_samples_fill_arrays(frame->data, frame->linesize, buffer->data,
+            frame->ch_layout.nb_channels, frame->nb_samples, frame->format, 1);
+    if (size > buffer->size)
+        return -1;
+
+    frame->opaque = (void *)-1; /* avoid reusing frame */
+    frame->buf[0] = av_buffer_ref(buffer);
+    frame->extended_data = frame->data;
+    return size;
+}
+
+static int audio_frame_copy_from_buffer(AVFrame *frame, const WAVEFORMATEXTENSIBLE *format, AVBufferRef *buffer)
+{
+    UINT8 *input_planes[4];
+    int size;
+
+    ERR("frame %p, buffer %p\n", frame, buffer);
+
+    size = av_samples_fill_arrays(input_planes, NULL, buffer->data, frame->ch_layout.nb_channels,
+            frame->nb_samples, frame->format, 1);
+    av_samples_copy(frame->data, input_planes, 0, 0, buffer->size / format->Format.nBlockAlign,
+            frame->ch_layout.nb_channels, frame->format);
+    return size;
+}
+
+static int audio_frame_copy_to_buffer(AVFrame *frame, const WAVEFORMATEXTENSIBLE *format, AVBufferRef *buffer)
+{
+    UINT8 *output_planes[4];
+    int size;
+
+    ERR("frame %p, buffer %p\n", frame, buffer);
+
+    size = av_samples_fill_arrays(output_planes, NULL, buffer->data, frame->ch_layout.nb_channels,
+            frame->nb_samples, frame->format, 1);
+    av_samples_copy(output_planes, frame->data, 0, 0, frame->nb_samples,
+            frame->ch_layout.nb_channels, frame->format);
+    return size;
+}
+
+static HRESULT MF_RESULT_FROM_DMO(HRESULT hr)
+{
+    switch (hr)
+    {
+    case DMO_E_INVALIDSTREAMINDEX: return MF_E_INVALIDSTREAMNUMBER;
+    case DMO_E_INVALIDTYPE:        return MF_E_INVALIDMEDIATYPE;
+    case DMO_E_TYPE_NOT_SET:       return MF_E_TRANSFORM_TYPE_NOT_SET;
+    case DMO_E_NOTACCEPTING:       return MF_E_NOTACCEPTING;
+    case DMO_E_TYPE_NOT_ACCEPTED:  return MF_E_INVALIDMEDIATYPE;
+    case DMO_E_NO_MORE_ITEMS:      return MF_E_NO_MORE_TYPES;
+    case S_FALSE:                  return MF_E_TRANSFORM_NEED_MORE_INPUT;
+    }
+
+    return hr;
+}
+
+static const GUID *audio_formats[] =
+{
+    &MFAudioFormat_Float,
+    &MFAudioFormat_PCM,
+};
+
+struct resampler
+{
+    IUnknown IUnknown_inner;
+    IMFTransform IMFTransform_iface;
+    IMediaObject IMediaObject_iface;
+    IPropertyBag IPropertyBag_iface;
+    IPropertyStore IPropertyStore_iface;
+    IWMResamplerProps IWMResamplerProps_iface;
+    IUnknown *outer;
+    LONG refcount;
+
+    DMO_MEDIA_TYPE input_type;
+    WAVEFORMATEXTENSIBLE input_format;
+    MFT_INPUT_STREAM_INFO input_info;
+    DMO_MEDIA_TYPE output_type;
+    WAVEFORMATEXTENSIBLE output_format;
+    MFT_OUTPUT_STREAM_INFO output_info;
+
+    struct SwrContext *context;
+    AVFrame input_frame;
+    AVFrame output_frame;
+    AVFrame current_frame;
+    AVRational time_base;
+};
+
+static INT64 resampler_time_to_user(struct resampler *impl, INT64 time)
+{
+    return av_rescale_q_rnd(time, impl->time_base, USER_TIME_BASE_Q, AV_ROUND_PASS_MINMAX);
+}
+
+static INT64 resampler_time_from_user(struct resampler *impl, INT64 time)
+{
+    return av_rescale_q_rnd(time, USER_TIME_BASE_Q, impl->time_base, AV_ROUND_PASS_MINMAX);
+}
+
+static HRESULT resampler_process_frame(struct resampler *impl, AVFrame *input_frame, DMO_OUTPUT_DATA_BUFFER *output)
+{
+    INT64 pts, duration = INT64_MAX;
+    AVFrame output_frame = {0};
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    HRESULT hr;
+    int ret;
+
+    if (!(buffer = buffer_from_media_buffer(output->pBuffer, 0)))
+        return E_OUTOFMEMORY;
+    if ((ret = audio_frame_wrap_buffer(&output_frame, &impl->output_format, buffer)) < 0)
+        av_frame_move_ref(&output_frame, &impl->output_frame);
+
+    pts = swr_next_pts(impl->context, input_frame->pts);
+    if ((ret = swr_convert(impl->context, output_frame.data, buffer->size / impl->output_format.Format.nBlockAlign,
+            (const uint8_t **)input_frame->data, input_frame->nb_samples)) < 0)
+        ERR("error ret %d (%s)\n", -ret, av_err2str(ret));
+    else if ((output_frame.nb_samples = ret))
+    {
+        if (!output_frame.opaque)
+            ret = audio_frame_copy_to_buffer(&output_frame, &impl->output_format, buffer);
+        else
+            ret = output_frame.nb_samples * impl->output_format.Format.nBlockAlign;
+        duration = av_rescale(output_frame.nb_samples, 10000000, output_frame.sample_rate);
+    }
+
+    if (!output_frame.opaque)
+        av_frame_move_ref(&impl->output_frame, &output_frame);
+    else
+        av_frame_unref(&output_frame);
+    av_buffer_unref(&buffer);
+
+    output->dwStatus = 0;
+    IMediaBuffer_SetLength(output->pBuffer, ret >= 0 ? ret : 0);
+    if (ret < 0)
+        return E_FAIL;
+    if (!ret)
+        return S_FALSE;
+
+    output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
+    if (swr_get_out_samples(impl->context, 0))
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
+    output->rtTimestamp = resampler_time_to_user(impl, pts);
+    if (output->rtTimestamp != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME;
+    output->rtTimelength = duration;
+    if (output->rtTimelength != INT64_MIN)
+        output->dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(output->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (output->rtTimestamp != INT64_MIN)
+            IMFSample_SetSampleTime(sample, output->rtTimestamp);
+        if (output->rtTimelength != INT64_MIN)
+            IMFSample_SetSampleDuration(sample, output->rtTimelength);
+        if (output->dwStatus & DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT)
+            IMFSample_SetUINT32(sample, &MFSampleExtension_CleanPoint, 1);
+        IMFSample_Release(sample);
+    }
+
+    TRACE("returning output size %#x, pts %s, duration %s status %#lx\n", ret,
+            debugstr_avtime(output->rtTimestamp, USER_TIME_BASE_Q),
+            debugstr_avtime(output->rtTimelength, USER_TIME_BASE_Q), output->dwStatus);
+    return S_OK;
+}
+
+static HRESULT resampler_process_input(struct resampler *impl, const DMO_OUTPUT_DATA_BUFFER *input)
+{
+    LONGLONG pts = input->rtTimestamp, duration = input->rtTimelength;
+    AVBufferRef *buffer;
+    IMFSample *sample;
+    HRESULT hr;
+    int ret;
+
+    if (!impl->context)
+        return DMO_E_TYPE_NOT_SET;
+    if (impl->current_frame.nb_samples)
+        return DMO_E_NOTACCEPTING;
+
+    if (!(buffer = buffer_from_media_buffer(input->pBuffer, AV_BUFFER_FLAG_READONLY)))
+        return E_OUTOFMEMORY;
+    if ((ret = audio_frame_wrap_buffer(&impl->current_frame, &impl->input_format, buffer)) < 0)
+    {
+        ret = audio_frame_copy_from_buffer(&impl->input_frame, &impl->input_format, buffer);
+        av_frame_move_ref(&impl->current_frame, &impl->input_frame);
+    }
+    av_buffer_unref(&buffer);
+
+    if (SUCCEEDED(hr = IMediaBuffer_QueryInterface(input->pBuffer, &IID_IMFSample, (void **)&sample)))
+    {
+        if (FAILED(IMFSample_GetSampleTime(sample, &pts)))
+            pts = INT64_MIN;
+        if (FAILED(IMFSample_GetSampleDuration(sample, &duration)))
+            duration = INT64_MIN;
+        IMFSample_Release(sample);
+    }
+
+    impl->current_frame.pts = resampler_time_from_user(impl, pts);
+    impl->current_frame.duration = resampler_time_from_user(impl, duration);
+    TRACE("input samples %u, time %s, duration %s\n", impl->current_frame.nb_samples,
+            debugstr_avtime(impl->current_frame.pts, impl->time_base),
+            debugstr_avtime(impl->current_frame.duration, impl->time_base));
+    return S_OK;
+}
+
+static HRESULT resampler_process_output(struct resampler *impl, DMO_OUTPUT_DATA_BUFFER *output)
+{
+    HRESULT hr;
+
+    if (!impl->context)
+        return DMO_E_TYPE_NOT_SET;
+
+    hr = resampler_process_frame(impl, &impl->current_frame, output);
+    if (!impl->current_frame.opaque)
+        av_frame_move_ref(&impl->input_frame, &impl->current_frame);
+    else
+        av_frame_unref(&impl->current_frame);
+
+    return hr;
+}
+
+static void resampler_cleanup(struct resampler *impl)
+{
+    impl->time_base.num = impl->time_base.den = 1;
+    memset(&impl->input_format, 0, sizeof(impl->input_format));
+    memset(&impl->output_format, 0, sizeof(impl->output_format));
+    av_frame_unref(&impl->current_frame);
+    av_frame_unref(&impl->output_frame);
+    av_frame_unref(&impl->input_frame);
+    swr_free(&impl->context);
+}
+
+static HRESULT init_audio_format(const DMO_MEDIA_TYPE *type, WAVEFORMATEXTENSIBLE *format)
+{
+    if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
+    {
+        const WAVEFORMATEX *wfx = (WAVEFORMATEX *)type->pbFormat;
+        if (wfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE)
+            *format = *(WAVEFORMATEXTENSIBLE *)wfx;
+        else
+        {
+            memset(format, 0, sizeof(*format));
+            format->Format = *wfx;
+            format->dwChannelMask = 0;
+            format->SubFormat = type->subtype;
+        }
+        return S_OK;
+    }
+
+    FIXME("Format %s not implemented\n", debugstr_guid(&type->formattype));
+    return E_NOTIMPL;
+}
+
+static HRESULT resampler_init(struct resampler *impl)
+{
+    HRESULT hr;
+    int ret;
+
+    resampler_cleanup(impl);
+
+    if (!(impl->context = swr_alloc()))
+        return E_OUTOFMEMORY;
+    if (FAILED(hr = init_audio_format(&impl->input_type, &impl->input_format))
+            || FAILED(hr = init_audio_format(&impl->output_type, &impl->output_format)))
+    {
+        resampler_cleanup(impl);
+        return hr;
+    }
+
+    audio_frame_init_from_format(&impl->input_frame, &impl->input_format);
+    impl->input_frame.nb_samples = impl->input_format.Format.nSamplesPerSec;
+    if ((ret = av_frame_get_buffer(&impl->input_frame, 0)) < 0)
+        goto failed;
+    audio_frame_init_from_format(&impl->output_frame, &impl->output_format);
+    impl->output_frame.nb_samples = impl->output_format.Format.nSamplesPerSec;
+    if ((ret = av_frame_get_buffer(&impl->output_frame, 0)) < 0)
+        goto failed;
+
+    av_opt_set_chlayout(impl->context, "in_chlayout", &impl->input_frame.ch_layout, 0);
+    av_opt_set_int(impl->context, "in_sample_rate", impl->input_frame.sample_rate, 0);
+    av_opt_set_sample_fmt(impl->context, "in_sample_fmt", impl->input_frame.format, 0);
+    impl->time_base.den *= impl->input_frame.sample_rate;
+
+    av_opt_set_chlayout(impl->context, "out_chlayout", &impl->output_frame.ch_layout, 0);
+    av_opt_set_int(impl->context, "out_sample_rate", impl->output_frame.sample_rate, 0);
+    av_opt_set_sample_fmt(impl->context, "out_sample_fmt", impl->output_frame.format, 0);
+    impl->time_base.den *= impl->output_frame.sample_rate;
+
+    if ((ret = swr_init(impl->context)) < 0)
+        goto failed;
+    return S_OK;
+
+failed:
+    ERR("ret %d\n", ret);
+    resampler_cleanup(impl);
+    return E_FAIL;
+}
+
+static struct resampler *impl_from_IUnknown(IUnknown *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IUnknown_inner);
+}
+
+static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out)
+{
+    struct resampler *impl = impl_from_IUnknown(iface);
+
+    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
+
+    if (IsEqualGUID(iid, &IID_IUnknown))
+        *out = &impl->IUnknown_inner;
+    else if (IsEqualGUID(iid, &IID_IMFTransform))
+        *out = &impl->IMFTransform_iface;
+    else if (IsEqualGUID(iid, &IID_IMediaObject))
+        *out = &impl->IMediaObject_iface;
+    else if (IsEqualIID(iid, &IID_IPropertyBag))
+        *out = &impl->IPropertyBag_iface;
+    else if (IsEqualIID(iid, &IID_IPropertyStore))
+        *out = &impl->IPropertyStore_iface;
+    else if (IsEqualIID(iid, &IID_IWMResamplerProps))
+        *out = &impl->IWMResamplerProps_iface;
+    else
+    {
+        *out = NULL;
+        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef((IUnknown *)*out);
+    return S_OK;
+}
+
+static ULONG WINAPI unknown_AddRef(IUnknown *iface)
+{
+    struct resampler *impl = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedIncrement(&impl->refcount);
+
+    TRACE("iface %p increasing refcount to %lu.\n", iface, refcount);
+
+    return refcount;
+}
+
+static ULONG WINAPI unknown_Release(IUnknown *iface)
+{
+    struct resampler *impl = impl_from_IUnknown(iface);
+    ULONG refcount = InterlockedDecrement(&impl->refcount);
+
+    TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount);
+
+    if (!refcount)
+    {
+        MoFreeMediaType(&impl->input_type);
+        MoFreeMediaType(&impl->output_type);
+        resampler_cleanup(impl);
+        free(impl);
+    }
+
+    return refcount;
+}
+
+static const IUnknownVtbl unknown_vtbl =
+{
+    unknown_QueryInterface,
+    unknown_AddRef,
+    unknown_Release,
+};
+
+static struct resampler *impl_from_IMFTransform(IMFTransform *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IMFTransform_iface);
+}
+
+static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI transform_AddRef(IMFTransform *iface)
+{
+    return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer);
+}
+
+static ULONG WINAPI transform_Release(IMFTransform *iface)
+{
+    return IUnknown_Release(impl_from_IMFTransform(iface)->outer);
+}
+
+static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
+        DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
+{
+    TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
+            iface, input_minimum, input_maximum, output_minimum, output_maximum);
+    *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
+{
+    TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
+    *inputs = *outputs = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
+        DWORD output_size, DWORD *outputs)
+{
+    TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
+            input_size, inputs, output_size, outputs);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
+
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+    {
+        memset(info, 0, sizeof(*info));
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    }
+
+    *info = impl->input_info;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
+
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL) || IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+    {
+        memset(info, 0, sizeof(*info));
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    }
+
+    *info = impl->output_info;
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
+{
+    TRACE("iface %p, attributes %p.\n", iface, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
+{
+    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
+{
+    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
+{
+    TRACE("iface %p, id %#lx.\n", iface, id);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
+{
+    TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+        IMFMediaType **type)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE mt = {0};
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
+
+    if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetInputType(&impl->IMediaObject_iface, id, index, &mt))))
+        return hr;
+    hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &mt, type);
+    MoFreeMediaType(&mt);
+    return hr;
+}
+
+static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
+        IMFMediaType **type)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE mt = {0};
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
+
+    if (FAILED(hr = MF_RESULT_FROM_DMO(IMediaObject_GetOutputType(&impl->IMediaObject_iface, id, index, &mt))))
+        return hr;
+    hr = MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &mt, type);
+    MoFreeMediaType(&mt);
+    return hr;
+}
+
+static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+    DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0;
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL;
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
+
+    if (type && FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, FORMAT_WaveFormatEx, (AM_MEDIA_TYPE *)&tmp)))
+        return hr;
+    hr = MF_RESULT_FROM_DMO(IMediaObject_SetInputType(&impl->IMediaObject_iface, id, mt, dmo_flags));
+    MoFreeMediaType(&tmp);
+    return hr;
+}
+
+static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
+{
+    DWORD dmo_flags = flags & MFT_SET_TYPE_TEST_ONLY ? DMO_SET_TYPEF_TEST_ONLY : 0;
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    DMO_MEDIA_TYPE tmp = {0}, *mt = type ? &tmp : NULL;
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
+
+    if (type && FAILED(hr = MFInitAMMediaTypeFromMFMediaType(type, FORMAT_WaveFormatEx, (AM_MEDIA_TYPE *)&tmp)))
+        return hr;
+    hr = MF_RESULT_FROM_DMO(IMediaObject_SetOutputType(&impl->IMediaObject_iface, id, mt, dmo_flags));
+    MoFreeMediaType(&tmp);
+    return hr;
+}
+
+static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
+
+    if (id != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL))
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->input_type, type);
+}
+
+static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+
+    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
+
+    if (id != 0)
+        return MF_E_INVALIDSTREAMNUMBER;
+    if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+        return MF_E_TRANSFORM_TYPE_NOT_SET;
+    return MFCreateMediaTypeFromRepresentation(AM_MEDIA_TYPE_REPRESENTATION, &impl->output_type, type);
+}
+
+static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
+{
+    FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
+{
+    FIXME("iface %p, flags %p stub!\n", iface, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
+{
+    TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
+{
+    FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
+{
+    FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
+    return S_OK;
+}
+
+static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    IMediaBuffer *dmo_buffer;
+    IMFMediaBuffer *buffer;
+    HRESULT hr;
+
+    TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
+
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(sample, &buffer)))
+        return hr;
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(sample, buffer, 0, &dmo_buffer)))
+    {
+        hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessInput(&impl->IMediaObject_iface, id, dmo_buffer, 0, 0, 0));
+        IMediaBuffer_Release(dmo_buffer);
+    }
+    IMFMediaBuffer_Release(buffer);
+
+    return hr;
+}
+
+static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
+        MFT_OUTPUT_DATA_BUFFER *output, DWORD *output_status)
+{
+    struct resampler *impl = impl_from_IMFTransform(iface);
+    DMO_OUTPUT_DATA_BUFFER dmo_output = {0};
+    IMFMediaBuffer *buffer;
+    DWORD dmo_status;
+    HRESULT hr;
+
+    TRACE("iface %p, flags %#lx, count %lu, output %p, output_status %p.\n", iface, flags, count,
+            output, output_status);
+
+    if (count != 1)
+        return E_INVALIDARG;
+
+    if (FAILED(hr = IMFSample_ConvertToContiguousBuffer(output->pSample, &buffer)))
+        return hr;
+    if (SUCCEEDED(hr = MFCreateLegacyMediaBufferOnMFMediaBuffer(output->pSample, buffer, 0,
+                          &dmo_output.pBuffer)))
+    {
+        hr = MF_RESULT_FROM_DMO(IMediaObject_ProcessOutput(&impl->IMediaObject_iface, flags, 1,
+                &dmo_output, &dmo_status));
+        IMediaBuffer_Release(dmo_output.pBuffer);
+    }
+    IMFMediaBuffer_Release(buffer);
+
+    output->dwStatus = *output_status = 0;
+    if (hr == S_FALSE)
+        output->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
+    else if (dmo_output.dwStatus & DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE)
+        output->dwStatus = MFT_OUTPUT_DATA_BUFFER_INCOMPLETE;
+    return hr;
+}
+
+static const IMFTransformVtbl transform_vtbl =
+{
+    transform_QueryInterface,
+    transform_AddRef,
+    transform_Release,
+    transform_GetStreamLimits,
+    transform_GetStreamCount,
+    transform_GetStreamIDs,
+    transform_GetInputStreamInfo,
+    transform_GetOutputStreamInfo,
+    transform_GetAttributes,
+    transform_GetInputStreamAttributes,
+    transform_GetOutputStreamAttributes,
+    transform_DeleteInputStream,
+    transform_AddInputStreams,
+    transform_GetInputAvailableType,
+    transform_GetOutputAvailableType,
+    transform_SetInputType,
+    transform_SetOutputType,
+    transform_GetInputCurrentType,
+    transform_GetOutputCurrentType,
+    transform_GetInputStatus,
+    transform_GetOutputStatus,
+    transform_SetOutputBounds,
+    transform_ProcessEvent,
+    transform_ProcessMessage,
+    transform_ProcessInput,
+    transform_ProcessOutput,
+};
+
+static struct resampler *impl_from_IMediaObject(IMediaObject *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IMediaObject_iface);
+}
+
+static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj)
+{
+    return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj);
+}
+
+static ULONG WINAPI media_object_AddRef(IMediaObject *iface)
+{
+    return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer);
+}
+
+static ULONG WINAPI media_object_Release(IMediaObject *iface)
+{
+    return IUnknown_Release(impl_from_IMediaObject(iface)->outer);
+}
+
+static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output)
+{
+    TRACE("iface %p, input %p, output %p\n", iface, input, output);
+    *input = *output = 1;
+    return S_OK;
+}
+
+static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT get_available_dmo_media_type(DWORD index, DMO_MEDIA_TYPE *type, BOOL output)
+{
+    const GUID *subtype;
+    WAVEFORMATEX *wfx;
+
+    if (!(wfx = CoTaskMemAlloc(sizeof(*wfx))))
+        return E_OUTOFMEMORY;
+    subtype = audio_formats[index % ARRAY_SIZE(audio_formats)];
+
+    memset(wfx, 0, sizeof(*wfx));
+    wfx->wFormatTag = subtype->Data1;
+
+    memset(type, 0, sizeof(*type));
+    type->majortype = MFMediaType_Audio;
+    type->formattype = FORMAT_WaveFormatEx;
+    type->subtype = *subtype;
+    type->pbFormat = (BYTE *)wfx;
+    type->cbFormat = sizeof(*wfx);
+    if (index < ARRAY_SIZE(audio_formats))
+        return S_OK;
+
+    wfx->wBitsPerSample = IsEqualGUID(subtype, &MFAudioFormat_Float) ? 32 : 16;
+    wfx->nChannels = 2;
+    wfx->nSamplesPerSec = 48000;
+    wfx->nBlockAlign = wfx->wBitsPerSample * wfx->nChannels / 8;
+    wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
+    return S_OK;
+}
+
+static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index,
+        DMO_MEDIA_TYPE *type)
+{
+    TRACE("iface %p, index %lu, type_index %lu, type %p\n", impl_from_IMediaObject(iface), index,
+            type_index, type);
+
+    if (index > 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (type_index >= ARRAY_SIZE(audio_formats))
+        return DMO_E_NO_MORE_ITEMS;
+    return type ? get_available_dmo_media_type(type_index, type, FALSE) : S_OK;
+}
+
+static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index,
+        DMO_MEDIA_TYPE *type)
+{
+    TRACE("iface %p, index %lu, type_index %lu, type %p\n", impl_from_IMediaObject(iface), index,
+            type_index, type);
+
+    if (index > 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (type_index >= 2 * ARRAY_SIZE(audio_formats))
+        return DMO_E_NO_MORE_ITEMS;
+    return type ? get_available_dmo_media_type(type_index, type, TRUE) : S_OK;
+}
+
+static HRESULT check_dmo_media_type(const DMO_MEDIA_TYPE *type, UINT *block_alignment)
+{
+    WAVEFORMATEX *wfx;
+    ULONG i;
+
+    if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
+        return DMO_E_INVALIDTYPE;
+    if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx) || type->cbFormat < sizeof(*wfx))
+        return DMO_E_INVALIDTYPE;
+
+    for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
+        if (IsEqualGUID(&type->subtype, audio_formats[i]))
+            break;
+    if (i == ARRAY_SIZE(audio_formats))
+        return DMO_E_INVALIDTYPE;
+
+    wfx = (WAVEFORMATEX *)type->pbFormat;
+    if (!wfx->wBitsPerSample || !wfx->nAvgBytesPerSec || !wfx->nChannels || !wfx->nSamplesPerSec || !wfx->nBlockAlign)
+        return DMO_E_INVALIDTYPE;
+
+    *block_alignment = wfx->nBlockAlign;
+    return S_OK;
+}
+
+static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index,
+        const DMO_MEDIA_TYPE *type, DWORD flags)
+{
+    struct resampler *impl = impl_from_IMediaObject(iface);
+    UINT32 block_alignment;
+    HRESULT hr;
+
+    TRACE("iface %p, index %#lx, type %p, flags %#lx.\n", iface, index, type, flags);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (!type)
+    {
+        clear_dmo_media_type(&impl->input_type);
+        resampler_cleanup(impl);
+        return S_OK;
+    }
+
+    if (FAILED(hr = check_dmo_media_type(type, &block_alignment)))
+        return hr;
+    if (flags & DMO_SET_TYPEF_TEST_ONLY)
+        return S_OK;
+
+    MoFreeMediaType(&impl->input_type);
+    if (FAILED(hr = MoCopyMediaType(&impl->input_type, type)))
+        return hr;
+    impl->input_info.cbSize = block_alignment;
+
+    if (!IsEqualGUID(&impl->output_type.majortype, &GUID_NULL)
+            && FAILED(hr = resampler_init(impl)))
+    {
+        clear_dmo_media_type(&impl->input_type);
+        impl->input_info.cbSize = 0;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index,
+        const DMO_MEDIA_TYPE *type, DWORD flags)
+{
+    struct resampler *impl = impl_from_IMediaObject(iface);
+    UINT32 block_alignment;
+    HRESULT hr;
+
+    TRACE("iface %p, index %#lx, type %p, flags %#lx.\n", iface, index, type, flags);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (!type)
+    {
+        clear_dmo_media_type(&impl->output_type);
+        resampler_cleanup(impl);
+        return S_OK;
+    }
+
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL))
+        return DMO_E_TYPE_NOT_SET;
+    if (FAILED(hr = check_dmo_media_type(type, &block_alignment)))
+        return hr;
+    if (flags & DMO_SET_TYPEF_TEST_ONLY)
+        return S_OK;
+
+    MoFreeMediaType(&impl->output_type);
+    if (FAILED(hr = MoCopyMediaType(&impl->output_type, type)))
+        return hr;
+    impl->output_info.cbSize = block_alignment;
+
+    if (!IsEqualGUID(&impl->input_type.majortype, &GUID_NULL)
+            && FAILED(hr = resampler_init(impl)))
+    {
+        clear_dmo_media_type(&impl->output_type);
+        impl->output_info.cbSize = 0;
+    }
+
+    return hr;
+}
+
+static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
+{
+    struct resampler *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, index %#lx, type %p.\n", iface, index, type);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (IsEqualGUID(&impl->input_type.majortype, &GUID_NULL))
+        return DMO_E_TYPE_NOT_SET;
+    return MoCopyMediaType(type, &impl->input_type);
+}
+
+static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
+{
+    struct resampler *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, index %#lx, type %p.\n", iface, index, type);
+
+    if (index != 0)
+        return DMO_E_INVALIDSTREAMINDEX;
+    if (IsEqualGUID(&impl->output_type.majortype, &GUID_NULL))
+        return DMO_E_TYPE_NOT_SET;
+    return MoCopyMediaType(type, &impl->output_type);
+}
+
+static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size,
+        DWORD *lookahead, DWORD *alignment)
+{
+    FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size,
+            lookahead, alignment);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
+{
+    FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
+{
+    FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency)
+{
+    FIXME("iface %p, index %lu, latency %I64d stub!\n", iface, index, latency);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_Flush(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index)
+{
+    FIXME("iface %p, index %lu stub!\n", iface, index);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
+{
+    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index,
+        IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
+{
+    DMO_OUTPUT_DATA_BUFFER input = {.pBuffer = buffer, .dwStatus = flags, .rtTimestamp = timestamp,
+            .rtTimelength = timelength};
+    struct resampler *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, index %lu, buffer %p, flags %#lx, timestamp %I64d, timelength %I64d\n", iface,
+            index, buffer, flags, timestamp, timelength);
+
+    return resampler_process_input(impl, &input);
+}
+
+static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count,
+        DMO_OUTPUT_DATA_BUFFER *output, DWORD *output_status)
+{
+    struct resampler *impl = impl_from_IMediaObject(iface);
+
+    TRACE("iface %p, flags %#lx, count %lu, output %p, output_status %p\n", iface, flags, count,
+            output, output_status);
+
+    if (count != 1)
+        return E_INVALIDARG;
+    if (flags)
+        FIXME("Unimplemented flags %#lx\n", flags);
+
+    return resampler_process_output(impl, output);
+}
+
+static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
+{
+    FIXME("iface %p, lock %ld stub!\n", iface, lock);
+    return E_NOTIMPL;
+}
+
+static const IMediaObjectVtbl media_object_vtbl =
+{
+    media_object_QueryInterface,
+    media_object_AddRef,
+    media_object_Release,
+    media_object_GetStreamCount,
+    media_object_GetInputStreamInfo,
+    media_object_GetOutputStreamInfo,
+    media_object_GetInputType,
+    media_object_GetOutputType,
+    media_object_SetInputType,
+    media_object_SetOutputType,
+    media_object_GetInputCurrentType,
+    media_object_GetOutputCurrentType,
+    media_object_GetInputSizeInfo,
+    media_object_GetOutputSizeInfo,
+    media_object_GetInputMaxLatency,
+    media_object_SetInputMaxLatency,
+    media_object_Flush,
+    media_object_Discontinuity,
+    media_object_AllocateStreamingResources,
+    media_object_FreeStreamingResources,
+    media_object_GetInputStatus,
+    media_object_ProcessInput,
+    media_object_ProcessOutput,
+    media_object_Lock,
+};
+
+static struct resampler *impl_from_IPropertyBag(IPropertyBag *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IPropertyBag_iface);
+}
+
+static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface)
+{
+    return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer);
+}
+
+static ULONG WINAPI property_bag_Release(IPropertyBag *iface)
+{
+    return IUnknown_Release(impl_from_IPropertyBag(iface)->outer);
+}
+
+static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value,
+        IErrorLog *error_log)
+{
+    FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value)
+{
+    FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value);
+    return S_OK;
+}
+
+static const IPropertyBagVtbl property_bag_vtbl =
+{
+    property_bag_QueryInterface,
+    property_bag_AddRef,
+    property_bag_Release,
+    property_bag_Read,
+    property_bag_Write,
+};
+
+static struct resampler *impl_from_IPropertyStore(IPropertyStore *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IPropertyStore_iface);
+}
+
+static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI property_store_AddRef(IPropertyStore *iface)
+{
+    return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer);
+}
+
+static ULONG WINAPI property_store_Release(IPropertyStore *iface)
+{
+    return IUnknown_Release(impl_from_IPropertyStore(iface)->outer);
+}
+
+static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count)
+{
+    FIXME("iface %p, count %p stub!\n", iface, count);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key)
+{
+    FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
+{
+    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
+{
+    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI property_store_Commit(IPropertyStore *iface)
+{
+    FIXME("iface %p stub!\n", iface);
+    return E_NOTIMPL;
+}
+
+static const IPropertyStoreVtbl property_store_vtbl =
+{
+    property_store_QueryInterface,
+    property_store_AddRef,
+    property_store_Release,
+    property_store_GetCount,
+    property_store_GetAt,
+    property_store_GetValue,
+    property_store_SetValue,
+    property_store_Commit,
+};
+
+static struct resampler *impl_from_IWMResamplerProps(IWMResamplerProps *iface)
+{
+    return CONTAINING_RECORD(iface, struct resampler, IWMResamplerProps_iface);
+}
+
+static HRESULT WINAPI resampler_props_QueryInterface(IWMResamplerProps *iface, REFIID iid, void **out)
+{
+    return IUnknown_QueryInterface(impl_from_IWMResamplerProps(iface)->outer, iid, out);
+}
+
+static ULONG WINAPI resampler_props_AddRef(IWMResamplerProps *iface)
+{
+    return IUnknown_AddRef(impl_from_IWMResamplerProps(iface)->outer);
+}
+
+static ULONG WINAPI resampler_props_Release(IWMResamplerProps *iface)
+{
+    return IUnknown_Release(impl_from_IWMResamplerProps(iface)->outer);
+}
+
+static HRESULT WINAPI resampler_props_SetHalfFilterLength(IWMResamplerProps *iface, LONG length)
+{
+    FIXME("iface %p, count %lu stub!\n", iface, length);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI resampler_props_SetUserChannelMtx(IWMResamplerProps *iface, ChMtxType *conversion_matrix)
+{
+    FIXME("iface %p, userChannelMtx %p stub!\n", iface, conversion_matrix);
+    return E_NOTIMPL;
+}
+
+static const IWMResamplerPropsVtbl resampler_props_vtbl =
+{
+    resampler_props_QueryInterface,
+    resampler_props_AddRef,
+    resampler_props_Release,
+    resampler_props_SetHalfFilterLength,
+    resampler_props_SetUserChannelMtx,
+};
+
+static const char *debugstr_version(UINT version)
+{
+    return wine_dbg_sprintf("%u.%u.%u", AV_VERSION_MAJOR(version), AV_VERSION_MINOR(version),
+            AV_VERSION_MICRO(version));
+}
+
+static HRESULT WINAPI resampler_factory_CreateInstance(IClassFactory *iface, IUnknown *outer,
+        REFIID riid, void **out)
+{
+    struct resampler *impl;
+    HRESULT hr;
+
+    TRACE("outer %p, riid %s, out %p.\n", outer, debugstr_guid(riid), out);
+
+    if (outer && !IsEqualGUID(riid, &IID_IUnknown))
+        return E_NOINTERFACE;
+
+    TRACE("avutil version %s\n", debugstr_version(avutil_version()));
+    TRACE("swresample version %s\n", debugstr_version(swresample_version()));
+
+    if (!(impl = calloc(1, sizeof(*impl))))
+        return E_OUTOFMEMORY;
+    impl->IUnknown_inner.lpVtbl = &unknown_vtbl;
+    impl->IMFTransform_iface.lpVtbl = &transform_vtbl;
+    impl->IMediaObject_iface.lpVtbl = &media_object_vtbl;
+    impl->IPropertyBag_iface.lpVtbl = &property_bag_vtbl;
+    impl->IPropertyStore_iface.lpVtbl = &property_store_vtbl;
+    impl->IWMResamplerProps_iface.lpVtbl = &resampler_props_vtbl;
+    impl->refcount = 1;
+    impl->outer = outer ? outer : &impl->IUnknown_inner;
+
+    impl->input_info.cbAlignment = 1;
+    impl->output_info.cbAlignment = 1;
+
+    TRACE("Created resampler %p\n", impl);
+
+    hr = IUnknown_QueryInterface(&impl->IUnknown_inner, riid, out);
+    IUnknown_Release(&impl->IUnknown_inner);
+    return hr;
+}
+
+static HRESULT WINAPI class_factory_QueryInterface(IClassFactory *iface, REFIID riid, void **out)
+{
+    *out = IsEqualGUID(riid, &IID_IClassFactory) || IsEqualGUID(riid, &IID_IUnknown) ? iface : NULL;
+    return *out ? S_OK : E_NOINTERFACE;
+}
+static ULONG WINAPI class_factory_AddRef(IClassFactory *iface)
+{
+    return 2;
+}
+static ULONG WINAPI class_factory_Release(IClassFactory *iface)
+{
+    return 1;
+}
+static HRESULT WINAPI class_factory_LockServer(IClassFactory *iface, BOOL dolock)
+{
+    return S_OK;
+}
+
+static const IClassFactoryVtbl resampler_factory_vtbl =
+{
+    class_factory_QueryInterface,
+    class_factory_AddRef,
+    class_factory_Release,
+    resampler_factory_CreateInstance,
+    class_factory_LockServer,
+};
+
+IClassFactory resampler_factory = {&resampler_factory_vtbl};
diff --git a/dlls/riched20/tests/editor.c b/dlls/riched20/tests/editor.c
index 2d654641ab64..8309e3985507 100644
--- a/dlls/riched20/tests/editor.c
+++ b/dlls/riched20/tests/editor.c
@@ -2994,7 +2994,6 @@ static void test_EM_SCROLL(void)
 }
 
 static unsigned int recursionLevel = 0;
-static unsigned int WM_SIZE_recursionLevel = 0;
 static BOOL bailedOutOfRecursion = FALSE;
 static LRESULT (WINAPI *richeditProc)(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
 
@@ -3011,11 +3010,9 @@ static LRESULT WINAPI RicheditStupidOverrideProcA(HWND hwnd, UINT message, WPARA
     recursionLevel++;
     switch (message) {
     case WM_SIZE:
-        WM_SIZE_recursionLevel++;
         r = richeditProc(hwnd, message, wParam, lParam);
         /* Because, uhhhh... I never heard of ES_DISABLENOSCROLL */
         ShowScrollBar(hwnd, SB_VERT, TRUE);
-        WM_SIZE_recursionLevel--;
         break;
     default:
         r = richeditProc(hwnd, message, wParam, lParam);
@@ -3684,14 +3681,12 @@ static void test_scrollbar_visibility(void)
     if(!RegisterClassA(&cls)) assert(0);
 
     recursionLevel = 0;
-    WM_SIZE_recursionLevel = 0;
     bailedOutOfRecursion = FALSE;
     hwndRichEdit = new_window(cls.lpszClassName, ES_MULTILINE, NULL);
     ok(!bailedOutOfRecursion,
         "WM_SIZE/scrollbar mutual recursion detected, expected none!\n");
 
     recursionLevel = 0;
-    WM_SIZE_recursionLevel = 0;
     bailedOutOfRecursion = FALSE;
     MoveWindow(hwndRichEdit, 0, 0, 250, 100, TRUE);
     ok(!bailedOutOfRecursion,
@@ -3700,7 +3695,6 @@ static void test_scrollbar_visibility(void)
     /* Unblock window in order to process WM_DESTROY */
     recursionLevel = 0;
     bailedOutOfRecursion = FALSE;
-    WM_SIZE_recursionLevel = 0;
     DestroyWindow(hwndRichEdit);
   }
 }
diff --git a/dlls/rpcrt4/tests/cstub.c b/dlls/rpcrt4/tests/cstub.c
index 12ea13363b0b..1ec47c5c640c 100644
--- a/dlls/rpcrt4/tests/cstub.c
+++ b/dlls/rpcrt4/tests/cstub.c
@@ -56,18 +56,13 @@ static GUID IID_if3 = {0x1234567a, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
 static GUID IID_if4 = {0x1234567b, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
 static CLSID CLSID_psfact = {0x1234567c, 1234, 5678, {12,34,56,78,90,0xab,0xcd,0xef}};
 
-static int my_alloc_called;
-static int my_free_called;
-
 static void * CALLBACK my_alloc(SIZE_T size)
 {
-    my_alloc_called++;
     return malloc(size);
 }
 
 static void CALLBACK my_free(void *ptr)
 {
-    my_free_called++;
     free(ptr);
 }
 
diff --git a/dlls/rpcrt4/tests/server.c b/dlls/rpcrt4/tests/server.c
index c05df1505429..dcea3dcb01a1 100644
--- a/dlls/rpcrt4/tests/server.c
+++ b/dlls/rpcrt4/tests/server.c
@@ -53,7 +53,6 @@ static RPC_STATUS (WINAPI *pRpcServerRegisterIfEx)(RPC_IF_HANDLE,UUID*, RPC_MGR_
                    unsigned int,RPC_IF_CALLBACK_FN*);
 static RPC_STATUS (WINAPI *pRpcBindingSetAuthInfoExA)(RPC_BINDING_HANDLE, RPC_CSTR, ULONG, ULONG,
                                                       RPC_AUTH_IDENTITY_HANDLE, ULONG, RPC_SECURITY_QOS *);
-static RPC_STATUS (WINAPI *pRpcServerRegisterAuthInfoA)(RPC_CSTR, ULONG, RPC_AUTH_KEY_RETRIEVAL_FN, LPVOID);
 
 static char *domain_and_user;
 
@@ -299,7 +298,6 @@ static void InitFunctionPointers(void)
     pNDRSContextUnmarshall2 = (void *)GetProcAddress(hrpcrt4, "NDRSContextUnmarshall2");
     pRpcServerRegisterIfEx = (void *)GetProcAddress(hrpcrt4, "RpcServerRegisterIfEx");
     pRpcBindingSetAuthInfoExA = (void *)GetProcAddress(hrpcrt4, "RpcBindingSetAuthInfoExA");
-    pRpcServerRegisterAuthInfoA = (void *)GetProcAddress(hrpcrt4, "RpcServerRegisterAuthInfoA");
 
     if (!pNDRSContextMarshall2) old_windows_version = TRUE;
 }
diff --git a/dlls/rsaenh/rsaenh.c b/dlls/rsaenh/rsaenh.c
index 4de6a2d06175..bb2657896f32 100644
--- a/dlls/rsaenh/rsaenh.c
+++ b/dlls/rsaenh/rsaenh.c
@@ -4176,7 +4176,11 @@ BOOL WINAPI RSAENH_CPGetProvParam(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,
                               strlen(pKeyContainer->szProvName)+1);
 
         case PP_PROVTYPE:
-            dwTemp = PROV_RSA_FULL;
+            switch (pKeyContainer->dwPersonality) {
+            case RSAENH_PERSONALITY_SCHANNEL: dwTemp = PROV_RSA_SCHANNEL; break;
+            case RSAENH_PERSONALITY_AES:      dwTemp = PROV_RSA_AES; break;
+            default:                          dwTemp = PROV_RSA_FULL; break;
+            }
             return copy_param(pbData, pdwDataLen, (const BYTE*)&dwTemp, sizeof(dwTemp));
 
         case PP_KEYSPEC:
diff --git a/dlls/rsaenh/tests/rsaenh.c b/dlls/rsaenh/tests/rsaenh.c
index 099116fc8042..26f05cd08556 100644
--- a/dlls/rsaenh/tests/rsaenh.c
+++ b/dlls/rsaenh/tests/rsaenh.c
@@ -4190,6 +4190,94 @@ static void test_RC4_session_key(void)
     CryptReleaseContext(hprov, 0);
 }
 
+/* RSA key with public exponent 1 */
+static const BYTE rsa_blob[] =
+{
+    0x07, 0x02, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00, 0x02, 0x00, 0x00,
+    0x01, 0x00, 0x00, 0x00, 0xab, 0xef, 0xfa, 0xc6, 0x7d, 0xe8, 0xde, 0xfb, 0x68, 0x38, 0x09, 0x92,
+    0xd9, 0x42, 0x7e, 0x6b, 0x89, 0x9e, 0x21, 0xd7, 0x52, 0x1c, 0x99, 0x3c, 0x17, 0x48, 0x4e, 0x3a,
+    0x44, 0x02, 0xf2, 0xfa, 0x74, 0x57, 0xda, 0xe4, 0xd3, 0xc0, 0x35, 0x67, 0xfa, 0x6e, 0xdf, 0x78,
+    0x4c, 0x75, 0x35, 0x1c, 0xa0, 0x74, 0x49, 0xe3, 0x20, 0x13, 0x71, 0x35, 0x65, 0xdf, 0x12, 0x20,
+    0xf5, 0xf5, 0xf5, 0xc1, 0xed, 0x5c, 0x91, 0x36, 0x75, 0xb0, 0xa9, 0x9c, 0x04, 0xdb, 0x0c, 0x8c,
+    0xbf, 0x99, 0x75, 0x13, 0x7e, 0x87, 0x80, 0x4b, 0x71, 0x94, 0xb8, 0x00, 0xa0, 0x7d, 0xb7, 0x53,
+    0xdd, 0x20, 0x63, 0xee, 0xf7, 0x83, 0x41, 0xfe, 0x16, 0xa7, 0x6e, 0xdf, 0x21, 0x7d, 0x76, 0xc0,
+    0x85, 0xd5, 0x65, 0x7f, 0x00, 0x23, 0x57, 0x45, 0x52, 0x02, 0x9d, 0xea, 0x69, 0xac, 0x1f, 0xfd,
+    0x3f, 0x8c, 0x4a, 0xd0, 0x01, 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, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x01, 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, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x64, 0xd5, 0xaa, 0xb1, 0xa6, 0x03, 0x18, 0x92, 0x03, 0xaa, 0x31, 0x2e,
+    0x48, 0x4b, 0x65, 0x20, 0x99, 0xcd, 0xc6, 0x0c, 0x15, 0x0c, 0xbf, 0x3e, 0xff, 0x78, 0x95, 0x67,
+    0xb2, 0x74, 0x5b, 0x60, 0x01, 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, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00,
+};
+
+static void test_pubexp(void)
+{
+    BOOL ret;
+    HCRYPTPROV hprov;
+    HCRYPTKEY hkey;
+
+    ret = CryptAcquireContextA(&hprov, NULL, MS_DEF_PROV_A, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+    ok(ret, "got %#lx\n", GetLastError());
+
+    ret = CryptImportKey(hprov, rsa_blob, sizeof(rsa_blob), 0, 0, &hkey);
+    ok(ret, "got %#lx\n", GetLastError());
+
+    CryptDestroyKey(hkey);
+    CryptReleaseContext(hprov, 0);
+}
+
+static void test_pp_provtype(void)
+{
+    /* `PP_PROVTYPE` must return the provider type the caller opened the
+     * provider with. This matters because PFXImportCertStore reads
+     * `PP_PROVTYPE` and writes it into the cert's
+     * `CRYPT_KEY_PROV_INFO.dwProvType`; a later `CryptAcquireContext`
+     * using that value must find the same container. */
+    static const struct
+    {
+        const char *prov_name;
+        DWORD       prov_type;
+    } providers[] =
+    {
+        { MS_DEF_PROV_A,             PROV_RSA_FULL },
+        { MS_ENHANCED_PROV_A,        PROV_RSA_FULL },
+        { MS_STRONG_PROV_A,          PROV_RSA_FULL },
+        { MS_ENH_RSA_AES_PROV_A,     PROV_RSA_AES  },
+        { MS_DEF_RSA_SCHANNEL_PROV_A, PROV_RSA_SCHANNEL },
+    };
+    DWORD i;
+
+    for (i = 0; i < ARRAY_SIZE(providers); i++)
+    {
+        HCRYPTPROV hprov;
+        DWORD got, len = sizeof(got);
+        BOOL ret;
+
+        ret = CryptAcquireContextA(&hprov, NULL, providers[i].prov_name,
+                                   providers[i].prov_type, CRYPT_VERIFYCONTEXT);
+        ok(ret, "%s: CryptAcquireContextA failed: %#lx\n",
+           providers[i].prov_name, GetLastError());
+        if (!ret) continue;
+
+        got = 0;
+        ret = CryptGetProvParam(hprov, PP_PROVTYPE, (BYTE *)&got, &len, 0);
+        ok(ret, "%s: CryptGetProvParam(PP_PROVTYPE) failed: %#lx\n",
+           providers[i].prov_name, GetLastError());
+        ok(len == sizeof(got), "%s: wrong PP_PROVTYPE size %lu\n",
+           providers[i].prov_name, len);
+        ok(got == providers[i].prov_type,
+           "%s: PP_PROVTYPE = %lu, expected %lu\n",
+           providers[i].prov_name, got, providers[i].prov_type);
+
+        CryptReleaseContext(hprov, 0);
+    }
+}
+
 START_TEST(rsaenh)
 {
     test_RC4_salt();
@@ -4242,5 +4330,7 @@ START_TEST(rsaenh)
     test_sha2();
     test_key_derivation("AES");
     test_rc2_import();
+    test_pubexp();
+    test_pp_provtype();
     clean_up_aes_environment();
 }
diff --git a/dlls/rtscom/Makefile.in b/dlls/rtscom/Makefile.in
new file mode 100644
index 000000000000..e4ea85cc3873
--- /dev/null
+++ b/dlls/rtscom/Makefile.in
@@ -0,0 +1,5 @@
+MODULE    = rtscom.dll
+
+SOURCES = \
+	rtscom_main.c \
+	rtscom_reg.idl
diff --git a/dlls/rtscom/rtscom.spec b/dlls/rtscom/rtscom.spec
new file mode 100644
index 000000000000..b16365d0c9fc
--- /dev/null
+++ b/dlls/rtscom/rtscom.spec
@@ -0,0 +1,4 @@
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
diff --git a/dlls/rtscom/rtscom_main.c b/dlls/rtscom/rtscom_main.c
new file mode 100644
index 000000000000..c51799328e8b
--- /dev/null
+++ b/dlls/rtscom/rtscom_main.c
@@ -0,0 +1,438 @@
+/*
+* Copyright 2026 Alistair Leslie-Hughes
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include <initguid.h>
+#include "oleidl.h"
+#include "rpcproxy.h"
+#include "rtscom.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(rtscom);
+
+
+struct rtstylus
+{
+    IRealTimeStylus IRealTimeStylus_iface;
+    LONG ref;
+};
+
+static struct rtstylus *impl_from_IRealTimeStylus( IRealTimeStylus *iface )
+{
+    return CONTAINING_RECORD( iface, struct rtstylus, IRealTimeStylus_iface );
+}
+
+static HRESULT WINAPI rtstylus_QueryInterface(IRealTimeStylus *iface, REFIID iid, void **obj)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+
+    TRACE( "(%p)->(%s %p)\n", This, debugstr_guid( iid ), obj );
+
+    if (IsEqualIID( iid, &IID_IUnknown ) ||
+        IsEqualIID( iid, &IID_IRealTimeStylus ))
+    {
+        IRealTimeStylus_AddRef( iface );
+        *obj = &This->IRealTimeStylus_iface;
+        return S_OK;
+    }
+
+    FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI rtstylus_AddRef(IRealTimeStylus *iface)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    ULONG ref = InterlockedIncrement( &This->ref );
+
+    TRACE( "(%p) ref = %lu\n", This, ref );
+    return ref;
+}
+
+static ULONG WINAPI rtstylus_Release(IRealTimeStylus *iface)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    TRACE( "(%p) ref = %lu\n", This, ref );
+
+    if (!ref)
+    {
+        free( This );
+    }
+
+    return ref;
+}
+
+static HRESULT WINAPI rtstylus_get_Enabled(IRealTimeStylus *iface, BOOL *pfEnable)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, pfEnable);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_put_Enabled(IRealTimeStylus *iface, BOOL fEnable)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %d\n", This, fEnable);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_get_HWND(IRealTimeStylus *iface, HANDLE_PTR *phwnd)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, phwnd);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_put_HWND(IRealTimeStylus *iface, HANDLE_PTR hwnd)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %Ix\n", This, hwnd);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_get_WindowInputRectangle(IRealTimeStylus *iface, RECT *prcWndInputRect)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, prcWndInputRect);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_put_WindowInputRectangle(IRealTimeStylus *iface, const RECT *prcWndInputRect)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, prcWndInputRect);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_AddStylusSyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusSyncPlugin *piPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, piPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_RemoveStylusSyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusSyncPlugin **ppiPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, ppiPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_RemoveAllStylusSyncPlugins(IRealTimeStylus *iface)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStylusSyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusSyncPlugin **ppiPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, ppiPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStylusSyncPluginCount(IRealTimeStylus *iface, ULONG *pcPlugins)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, pcPlugins);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_AddStylusAsyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusAsyncPlugin *piPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, piPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_RemoveStylusAsyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusAsyncPlugin **ppiPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, ppiPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_RemoveAllStylusAsyncPlugins(IRealTimeStylus *iface)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStylusAsyncPlugin(IRealTimeStylus *iface, ULONG iIndex, IStylusAsyncPlugin **ppiPlugin)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, iIndex, ppiPlugin);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStylusAsyncPluginCount(IRealTimeStylus *iface, ULONG *pcPlugins)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, pcPlugins);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_get_ChildRealTimeStylusPlugin(IRealTimeStylus *iface, IRealTimeStylus **ppiRTS)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, ppiRTS);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_putref_ChildRealTimeStylusPlugin(IRealTimeStylus *iface, IRealTimeStylus *piRTS)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, piRTS);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_AddCustomStylusDataToQueue(IRealTimeStylus *iface, StylusQueue sq, const GUID *pGuidId,
+                ULONG cbData, BYTE *pbData)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %d, %p, %lu, %p\n", This, sq, pGuidId, cbData, pbData);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_ClearStylusQueues(IRealTimeStylus *iface)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p\n", This);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_SetAllTabletsMode(IRealTimeStylus *iface, BOOL fUseMouseForInput)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %d\n", This, fUseMouseForInput);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_SetSingleTabletMode(IRealTimeStylus *iface, IInkTablet *piTablet)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, piTablet);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetTablet(IRealTimeStylus *iface, IInkTablet **ppiSingleTablet)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, ppiSingleTablet);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetTabletContextIdFromTablet(IRealTimeStylus *iface, IInkTablet *piTablet, TABLET_CONTEXT_ID *ptcid)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p, %p\n", This, piTablet, ptcid);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetTabletFromTabletContextId(IRealTimeStylus *iface, TABLET_CONTEXT_ID tcid, IInkTablet **ppiTablet)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %ld, %p\n", This, tcid, ppiTablet);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetAllTabletContextIds(IRealTimeStylus *iface, ULONG *pcTcidCount, TABLET_CONTEXT_ID **ppTcids)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p, %p\n", This, pcTcidCount, ppTcids);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStyluses(IRealTimeStylus *iface, IInkCursors **ppiInkCursors)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p\n", This, ppiInkCursors);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetStylusForId(IRealTimeStylus *iface, STYLUS_ID sid, IInkCursor **ppiInkCursor)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %ld, %p\n", This, sid, ppiInkCursor);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_SetDesiredPacketDescription(IRealTimeStylus *iface, ULONG cProperties, const GUID *pPropertyGuids)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p\n", This, cProperties, pPropertyGuids);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetDesiredPacketDescription(IRealTimeStylus *iface, ULONG *pcProperties, GUID **ppPropertyGuids)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %p, %p\n", This, pcProperties, ppPropertyGuids);
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI rtstylus_GetPacketDescriptionData(IRealTimeStylus *iface, TABLET_CONTEXT_ID tcid, FLOAT *pfInkToDeviceScaleX,
+    FLOAT *pfInkToDeviceScaleY, ULONG *pcPacketProperties, PACKET_PROPERTY **ppPacketProperties)
+{
+    struct rtstylus *This = impl_from_IRealTimeStylus(iface);
+    FIXME("%p, %lu, %p, %p, %p, %p\n", This, tcid, pfInkToDeviceScaleX, pfInkToDeviceScaleY, pcPacketProperties, ppPacketProperties);
+    return E_NOTIMPL;
+}
+
+static const struct IRealTimeStylusVtbl realtime_stylus_vtbl =
+{
+    rtstylus_QueryInterface,
+    rtstylus_AddRef,
+    rtstylus_Release,
+    rtstylus_get_Enabled,
+    rtstylus_put_Enabled,
+    rtstylus_get_HWND,
+    rtstylus_put_HWND,
+    rtstylus_get_WindowInputRectangle,
+    rtstylus_put_WindowInputRectangle,
+    rtstylus_AddStylusSyncPlugin,
+    rtstylus_RemoveStylusSyncPlugin,
+    rtstylus_RemoveAllStylusSyncPlugins,
+    rtstylus_GetStylusSyncPlugin,
+    rtstylus_GetStylusSyncPluginCount,
+    rtstylus_AddStylusAsyncPlugin,
+    rtstylus_RemoveStylusAsyncPlugin,
+    rtstylus_RemoveAllStylusAsyncPlugins,
+    rtstylus_GetStylusAsyncPlugin,
+    rtstylus_GetStylusAsyncPluginCount,
+    rtstylus_get_ChildRealTimeStylusPlugin,
+    rtstylus_putref_ChildRealTimeStylusPlugin,
+    rtstylus_AddCustomStylusDataToQueue,
+    rtstylus_ClearStylusQueues,
+    rtstylus_SetAllTabletsMode,
+    rtstylus_SetSingleTabletMode,
+    rtstylus_GetTablet,
+    rtstylus_GetTabletContextIdFromTablet,
+    rtstylus_GetTabletFromTabletContextId,
+    rtstylus_GetAllTabletContextIds,
+    rtstylus_GetStyluses,
+    rtstylus_GetStylusForId,
+    rtstylus_SetDesiredPacketDescription,
+    rtstylus_GetDesiredPacketDescription,
+    rtstylus_GetPacketDescriptionData
+};
+
+static HRESULT realtime_stylus_create( IUnknown *outer, REFIID iid, void **obj )
+{
+    struct rtstylus *This = malloc( sizeof(*This) );
+    HRESULT hr = E_FAIL;
+
+    if (!This) return E_OUTOFMEMORY;
+    This->IRealTimeStylus_iface.lpVtbl = &realtime_stylus_vtbl;
+    This->ref = 1;
+
+    hr = IRealTimeStylus_QueryInterface( &This->IRealTimeStylus_iface, iid, obj );
+    IRealTimeStylus_Release( &This->IRealTimeStylus_iface );
+    return hr;
+}
+
+struct class_factory
+{
+    IClassFactory IClassFactory_iface;
+    HRESULT (*create_instance)(IUnknown *, REFIID, void **);
+};
+
+static inline struct class_factory *impl_from_IClassFactory( IClassFactory *iface )
+{
+    return CONTAINING_RECORD( iface, struct class_factory, IClassFactory_iface );
+}
+
+static HRESULT WINAPI class_factory_QueryInterface( IClassFactory *iface,
+                                                    REFIID iid, void **obj )
+{
+    if (IsEqualIID( iid, &IID_IUnknown ) ||
+        IsEqualIID( iid, &IID_IClassFactory ))
+    {
+        IClassFactory_AddRef( iface );
+        *obj = iface;
+        return S_OK;
+    }
+
+    FIXME( "interface %s not implemented\n", debugstr_guid( iid ) );
+    *obj = NULL;
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI class_factory_AddRef( IClassFactory *iface )
+{
+    return 2;
+}
+
+static ULONG WINAPI class_factory_Release( IClassFactory *iface )
+{
+    return 1;
+}
+
+static HRESULT WINAPI class_factory_CreateInstance( IClassFactory *iface,
+                                                    IUnknown *outer, REFIID iid,
+                                                    void **obj )
+{
+    struct class_factory *This = impl_from_IClassFactory( iface );
+
+    TRACE( "%p %s %p\n", outer, debugstr_guid( iid ), obj );
+
+    *obj = NULL;
+    return This->create_instance( outer, iid, obj );
+}
+
+static HRESULT WINAPI class_factory_LockServer( IClassFactory *iface, BOOL lock )
+{
+    FIXME( "%d: stub!\n", lock );
+    return S_OK;
+}
+
+static const struct IClassFactoryVtbl class_factory_vtbl =
+{
+    class_factory_QueryInterface,
+    class_factory_AddRef,
+    class_factory_Release,
+    class_factory_CreateInstance,
+    class_factory_LockServer
+};
+
+static struct class_factory runtime_styus_cf = { { &class_factory_vtbl }, realtime_stylus_create };
+
+HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, LPVOID *obj)
+{
+    IClassFactory *cf = NULL;
+
+    TRACE( "(%s %s %p)\n", debugstr_guid( clsid ), debugstr_guid( iid ), obj );
+
+    if (IsEqualCLSID( clsid, &CLSID_RealTimeStylus ))
+        cf = &runtime_styus_cf.IClassFactory_iface;
+    else
+        FIXME( "(%s %s %p) unsupported interface\n", debugstr_guid( clsid ), debugstr_guid( iid ), obj );
+
+    if (!cf) return CLASS_E_CLASSNOTAVAILABLE;
+
+    return IClassFactory_QueryInterface( cf, iid, obj );
+}
diff --git a/dlls/rtscom/rtscom_reg.idl b/dlls/rtscom/rtscom_reg.idl
new file mode 100644
index 000000000000..296cf4ee1bc3
--- /dev/null
+++ b/dlls/rtscom/rtscom_reg.idl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2026 Alistair Leslie-Hughes
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma makedep register
+
+import "unknwn.idl";
+import "objidl.idl";
+import "oaidl.idl";
+
+[
+    uuid(e26b366d-f998-43ce-836f-cb6d904432b0),
+    threading(both)
+]
+coclass RealTimeStylus
+{
+    [default] interface IRealTimeStylus;
+}
diff --git a/dlls/secur32/tests/ntlm.c b/dlls/secur32/tests/ntlm.c
index 2c4139ee2cd4..a5bb40ba2853 100644
--- a/dlls/secur32/tests/ntlm.c
+++ b/dlls/secur32/tests/ntlm.c
@@ -98,7 +98,21 @@ enum negotiate_flags
     NTLMSSP_NEGOTIATE_56                        = 0x80000000,
 };
 
-struct ntlm_server_challenge
+struct ntlm_negotiate
+{
+    char signature[8];
+    int message_type;
+    enum negotiate_flags negotiate_flags;
+    unsigned short target_name_len;
+    unsigned short target_name_max_len;
+    unsigned int target_name_off;
+    unsigned short workstation_name_len;
+    unsigned short workstation_name_max_len;
+    unsigned int workstation_name_off;
+    BYTE os_version[8];
+};
+
+struct ntlm_challenge
 {
     char signature[8];
     int message_type;
@@ -115,7 +129,7 @@ struct ntlm_server_challenge
 
 struct server_challenge
 {
-    struct ntlm_server_challenge challenge;
+    struct ntlm_challenge challenge;
     WCHAR name[8];
     WCHAR info[42];
 
@@ -534,12 +548,48 @@ static void communicate(SspiData *from, SspiData *to)
 /**********************************************************************/
 static void testInitializeSecurityContextFlags(void)
 {
+    static const struct
+    {
+        ULONG req_attr;
+        ULONG flags;
+        ULONG ctxt_attr;
+        ULONG ctxt_attr_chlg;
+        ULONG ctxt_attr_auth;
+        ULONG ctxt_attr_serv;
+    } test_data[] =
+    {
+        { 0, 0, 0, 0, 0 },
+        { ISC_REQ_CONNECTION, 0, ISC_RET_CONNECTION, 0, 0, 0 },
+        { ISC_REQ_EXTENDED_ERROR, 0, 0, 0, 0, 0 },
+        { ISC_REQ_MUTUAL_AUTH, 0, 0, 0, ISC_RET_MUTUAL_AUTH, 0 },
+        { ISC_REQ_USE_DCE_STYLE, 0, 0, 0, 0, 0 },
+        { ISC_REQ_DELEGATE, 0, 0, 0, 0, 0 },
+        { ISC_REQ_INTEGRITY, NTLMSSP_NEGOTIATE_SIGN, ISC_RET_INTEGRITY,
+            ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT,
+            ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT,
+            ASC_RET_INTEGRITY | ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT },
+        { ISC_REQ_REPLAY_DETECT, NTLMSSP_NEGOTIATE_SIGN, ISC_RET_REPLAY_DETECT,
+            ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT,
+            ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT,
+            ASC_RET_INTEGRITY | ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT },
+        { ISC_REQ_SEQUENCE_DETECT, NTLMSSP_NEGOTIATE_SIGN, ISC_RET_SEQUENCE_DETECT,
+            ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT,
+            ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT,
+            ASC_RET_INTEGRITY | ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT },
+        { ISC_REQ_CONFIDENTIALITY, NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL,
+            ISC_RET_CONFIDENTIALITY | ISC_RET_INTEGRITY,
+            ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT | ASC_RET_CONFIDENTIALITY,
+            ISC_RET_INTEGRITY | ISC_RET_SEQUENCE_DETECT | ISC_RET_REPLAY_DETECT | ISC_RET_CONFIDENTIALITY,
+            ASC_RET_INTEGRITY | ASC_RET_SEQUENCE_DETECT | ASC_RET_REPLAY_DETECT | ASC_RET_CONFIDENTIALITY }
+    };
+
     SECURITY_STATUS         sec_status;
     PSecPkgInfoA            pkg_info = NULL;
-    SspiData                client = {{0}};
-    ULONG                   req_attr, ctxt_attr;
+    SspiData                client = {{0}}, server = {{0}};
+    ULONG                   i, ctxt_attr;
     TimeStamp               ttl;
-    PBYTE                   packet;
+    struct ntlm_negotiate   *negotiate;
+    struct ntlm_challenge   *challenge;
 
     if(QuerySecurityPackageInfoA( sec_pkg_name, &pkg_info) != SEC_E_OK)
     {
@@ -555,186 +605,66 @@ static void testInitializeSecurityContextFlags(void)
                 getSecError(sec_status));
         return;
     }
+    sec_status = setupServer(&server, sec_pkg_name);
+    ok(sec_status == SEC_E_OK, "setupServer returned %s\n", getSecError(sec_status));
 
-    packet = client.out_buf->pBuffers[0].pvBuffer;
-
-    /* Due to how the requesting of the flags is implemented in ntlm_auth,
-     * the tests need to be in this order, as there is no way to specify
-     * "I request no special features" in ntlm_auth */
-
-    /* Without any flags, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = 0;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "With req_attr == 0, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_CONNECTION, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = ISC_REQ_CONNECTION;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "For ISC_REQ_CONNECTION, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_EXTENDED_ERROR, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = ISC_REQ_EXTENDED_ERROR;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "For ISC_REQ_EXTENDED_ERROR, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_MUTUAL_AUTH, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = ISC_REQ_MUTUAL_AUTH;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "For ISC_REQ_MUTUAL_AUTH, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_USE_DCE_STYLE, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = ISC_REQ_USE_DCE_STYLE;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "For ISC_REQ_USE_DCE_STYLE, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_DELEGATE, the lowest byte should not have bits 0x20 or 0x10 set*/
-    req_attr = ISC_REQ_DELEGATE;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok(((packet[12] & 0x10) == 0) && ((packet[12] & 0x20) == 0),
-            "For ISC_REQ_DELEGATE, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_INTEGRITY, the lowest byte should have bit 0x10 set */
-    req_attr = ISC_REQ_INTEGRITY;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok((packet[12] & 0x10) != 0,
-            "For ISC_REQ_INTEGRITY, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_REPLAY_DETECT, the lowest byte should have bit 0x10 set */
-    req_attr = ISC_REQ_REPLAY_DETECT;
+    negotiate = client.out_buf->pBuffers[0].pvBuffer;
+    challenge = server.out_buf->pBuffers[0].pvBuffer;
 
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
+    for(i = 0; i < ARRAY_SIZE(test_data); i++)
     {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
-    }
+        winetest_push_context("%lx", test_data[i].req_attr);
 
-    ok((packet[12] & 0x10) != 0,
-            "For ISC_REQ_REPLAY_DETECT, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-    /* With ISC_REQ_SEQUENCE_DETECT, the lowest byte should have bit 0x10 set */
-    req_attr = ISC_REQ_SEQUENCE_DETECT;
-
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
+        client.out_buf->pBuffers[0].cbBuffer = client.max_token;
+        ctxt_attr = 0xffffffff;
+        sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, test_data[i].req_attr, 0,
+                SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf, &ctxt_attr, &ttl);
+        ok(sec_status == SEC_I_CONTINUE_NEEDED, "InitializeSecurityContext returned %s\n",
+            getSecError(sec_status));
+        ok((negotiate->negotiate_flags & (NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL)) == test_data[i].flags,
+            "negotiate_flags = %08x\n", negotiate->negotiate_flags);
+        ok(ctxt_attr == test_data[i].ctxt_attr, "ctxt_attr = %lx\n", ctxt_attr);
+
+        server.out_buf->pBuffers[0].cbBuffer = server.max_token;
+        ctxt_attr = 0xffffffff;
+        sec_status = AcceptSecurityContext(&server.cred, NULL, client.out_buf, 0,
+                SECURITY_NETWORK_DREP, &server.ctxt, server.out_buf, &ctxt_attr, &ttl);
+        ok(sec_status == SEC_I_CONTINUE_NEEDED, "AcceptSecurityContext returned %s\n",
                 getSecError(sec_status));
-        goto tISCFend;
-    }
-
-    ok((packet[12] & 0x10) != 0,
-            "For ISC_REQ_SEQUENCE_DETECT, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
+        ok(server.out_buf->cBuffers == 1, "cBuffers = %lu\n", server.out_buf->cBuffers);
+        ok(server.out_buf->pBuffers[0].BufferType == SECBUFFER_TOKEN,
+                "BufferType = %ld\n", server.out_buf->pBuffers[0].BufferType);
+        ok(ctxt_attr == test_data[i].ctxt_attr_chlg, "ctxt_attr = %lx\n", ctxt_attr);
+
+        client.out_buf->pBuffers[0].cbBuffer = client.max_token;
+        ctxt_attr = 0xffffffff;
+        sec_status = InitializeSecurityContextA(NULL, &client.ctxt, NULL, 0, 0, SECURITY_NETWORK_DREP,
+                server.out_buf, 0, &client.ctxt, client.out_buf, &ctxt_attr, &ttl);
+        todo_wine_if(sec_status == SEC_E_INVALID_TOKEN)
+            ok(sec_status == SEC_E_OK, "InitializeSecurityContext returned %s\n", getSecError(sec_status));
+        if (sec_status == SEC_E_OK)
+        {
+            todo_wine_if(test_data[i].req_attr & ISC_REQ_MUTUAL_AUTH)
+            ok(ctxt_attr == test_data[i].ctxt_attr_auth, "ctxt_attr = %lx (negotiated flags: %x)\n",
+                    ctxt_attr, challenge->negotiate_flags);
+
+            ctxt_attr = 0xffffffff;
+            sec_status = AcceptSecurityContext(&server.cred, &server.ctxt, client.out_buf, 0,
+                    SECURITY_NETWORK_DREP, &server.ctxt, NULL, &ctxt_attr, &ttl);
+            ok(sec_status == SEC_E_OK, "AcceptSecurityContext returned %s\n", getSecError(sec_status));
+            ok(ctxt_attr == test_data[i].ctxt_attr_serv, "ctxt_attr = %lx\n", ctxt_attr);
+        }
 
-    /* With ISC_REQ_CONFIDENTIALITY, the lowest byte should have bit 0x20 set */
-    req_attr = ISC_REQ_CONFIDENTIALITY;
+        DeleteSecurityContext(&client.ctxt);
+        DeleteSecurityContext(&server.ctxt);
 
-    if((sec_status = InitializeSecurityContextA(&client.cred, NULL, NULL, req_attr,
-        0, SECURITY_NETWORK_DREP, NULL, 0, &client.ctxt, client.out_buf,
-        &ctxt_attr, &ttl)) != SEC_I_CONTINUE_NEEDED)
-    {
-        trace("InitializeSecurityContext returned %s not SEC_I_CONTINUE_NEEDED, aborting.\n",
-                getSecError(sec_status));
-        goto tISCFend;
+        winetest_pop_context();
     }
 
-    ok((packet[12] & 0x20) != 0,
-            "For ISC_REQ_CONFIDENTIALITY, flags are 0x%02x%02x%02x%02x.\n",
-            packet[15], packet[14], packet[13], packet[12]);
-    DeleteSecurityContext(&client.ctxt);
-
-tISCFend:
     cleanupBuffers(&client);
+    cleanupBuffers(&server);
     FreeCredentialsHandle(&client.cred);
+    FreeCredentialsHandle(&server.cred);
 }
 
 /**********************************************************************/
diff --git a/dlls/shell32/shlfileop.c b/dlls/shell32/shlfileop.c
index 3f4d4416254b..16074d51f208 100644
--- a/dlls/shell32/shlfileop.c
+++ b/dlls/shell32/shlfileop.c
@@ -377,9 +377,7 @@ static DWORD SHELL_DeleteDirectoryW(HWND hwnd, LPCWSTR pszDir, BOOL bShowUI)
     if (ret == ERROR_SUCCESS)
         ret = SHNotifyRemoveDirectoryW(pszDir);
 
-    return ret == ERROR_PATH_NOT_FOUND ?
-        0x7C: /* DE_INVALIDFILES (legacy Windows error) */
-        ret;
+    return ret == ERROR_PATH_NOT_FOUND ? DE_INVALIDFILES : ret;
 }
 
 /**************************************************************************
diff --git a/dlls/tiptsf/Makefile.in b/dlls/tiptsf/Makefile.in
new file mode 100644
index 000000000000..744360ef486e
--- /dev/null
+++ b/dlls/tiptsf/Makefile.in
@@ -0,0 +1,5 @@
+MODULE    = tiptsf.dll
+
+SOURCES = \
+	tiptsf.idl \
+	tiptsf_main.c
diff --git a/dlls/tiptsf/tiptsf.idl b/dlls/tiptsf/tiptsf.idl
new file mode 100644
index 000000000000..95060d45df04
--- /dev/null
+++ b/dlls/tiptsf/tiptsf.idl
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2025 Alistair Leslie-Hughes
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#pragma makedep register
+
+#include "peninputpanel.idl"
diff --git a/dlls/tiptsf/tiptsf.spec b/dlls/tiptsf/tiptsf.spec
new file mode 100644
index 000000000000..40feedd7dd33
--- /dev/null
+++ b/dlls/tiptsf/tiptsf.spec
@@ -0,0 +1,11 @@
+@ stub AdviseHook
+@ stub EndCaretTracking
+@ stub ProcessCaretEvents
+@ stub ProcessCiceroCaretEvent
+@ stub RestrictedModeMsgWndProc
+@ stub StartCaretTracking
+@ stub UnadviseHook
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
diff --git a/dlls/tiptsf/tiptsf_main.c b/dlls/tiptsf/tiptsf_main.c
new file mode 100644
index 000000000000..c7672470024e
--- /dev/null
+++ b/dlls/tiptsf/tiptsf_main.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2025 Alistair Leslie-Hughes
+ *
+ * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+#define COBJMACROS
+
+#include "initguid.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "objbase.h"
+#include "rpcproxy.h"
+
+#include "peninputpanel.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(inkobj);
+
+struct input_panel
+{
+    ITextInputPanel ITextInputPanel_iface;
+    LONG ref;
+};
+
+static inline struct input_panel *impl_from_ITextInputPanel( ITextInputPanel *iface )
+{
+    return CONTAINING_RECORD( iface, struct input_panel, ITextInputPanel_iface );
+}
+
+static HRESULT WINAPI input_panel_QueryInterface(ITextInputPanel *iface, REFIID riid, void **obj)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+    TRACE( "%p, %s, %p\n", iface, debugstr_guid(riid), obj );
+
+    *obj = NULL;
+
+    if (IsEqualIID(riid, &IID_IUnknown)    ||
+        IsEqualIID(riid, &IID_ITextInputPanel))
+    {
+        *obj = &input->ITextInputPanel_iface;
+    }
+    else
+    {
+        FIXME( "interface %s not implemented\n", debugstr_guid(riid) );
+        return E_NOINTERFACE;
+    }
+
+    IUnknown_AddRef( (IUnknown*)*obj );
+    return S_OK;
+}
+
+static ULONG WINAPI input_panel_AddRef(ITextInputPanel *iface)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+    return InterlockedIncrement( &input->ref );
+}
+
+static ULONG WINAPI input_panel_Release(ITextInputPanel *iface)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+    LONG ref = InterlockedDecrement( &input->ref );
+    if (!ref)
+    {
+        free( input );
+    }
+    return ref;
+}
+
+static HRESULT WINAPI input_panel_get_AttachedEditWindow(ITextInputPanel *iface, HWND *window)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, window);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_AttachedEditWindow(ITextInputPanel *iface, HWND window)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, window);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_CurrentInteractionMode(ITextInputPanel *iface, InteractionMode *mode)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_DefaultInPlaceState(ITextInputPanel *iface, InPlaceState *state)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, state);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_DefaultInPlaceState(ITextInputPanel *iface, InPlaceState state)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, state);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_CurrentInPlaceState(ITextInputPanel *iface, InPlaceState *state)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, state);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_DefaultInputArea(ITextInputPanel *iface, PanelInputArea *area)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, area);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_DefaultInputArea(ITextInputPanel *iface, PanelInputArea area)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, area);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_CurrentInputArea(ITextInputPanel *iface, PanelInputArea *area)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, area);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_CurrentCorrectionMode(ITextInputPanel *iface, CorrectionMode *mode)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, mode);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_PreferredInPlaceDirection(ITextInputPanel *iface, InPlaceDirection *direction)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, direction);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_PreferredInPlaceDirection(ITextInputPanel *iface, InPlaceDirection direction)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, direction);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_ExpandPostInsertionCorrection(ITextInputPanel *iface, BOOL *expand)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, expand);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_ExpandPostInsertionCorrection(ITextInputPanel *iface, BOOL expand)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, expand);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_InPlaceVisibleOnFocus(ITextInputPanel *iface, BOOL *visible)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, visible);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_put_InPlaceVisibleOnFocus(ITextInputPanel *iface, BOOL visible)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, visible);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_InPlaceBoundingRectangle(ITextInputPanel *iface, RECT *bounding_rect)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, bounding_rect);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_PopUpCorrectionHeight(ITextInputPanel *iface, int *height)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_get_PopDownCorrectionHeight(ITextInputPanel *iface, int *height)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, height);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_CommitPendingInput(ITextInputPanel *iface)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p\n", input);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_SetInPlaceVisibility(ITextInputPanel *iface, BOOL visible)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d\n", input, visible);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_SetInPlacePosition(ITextInputPanel *iface, int x, int y, CorrectionPosition position)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d, %d, %d\n", input, x, y, position);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_SetInPlaceHoverTargetPosition(ITextInputPanel *iface, int x, int y)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %d, %d\n", input, x, y);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_Advise( ITextInputPanel *iface, ITextInputPanelEventSink *sink, DWORD mask)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p 0x%lx\n", input, sink, mask);
+
+    return E_NOTIMPL;
+}
+
+static HRESULT WINAPI input_panel_Unadvise(ITextInputPanel *iface, ITextInputPanelEventSink *sink)
+{
+    struct input_panel *input = impl_from_ITextInputPanel( iface );
+
+    FIXME("%p, %p\n", input, sink);
+
+    return E_NOTIMPL;
+}
+
+static const struct ITextInputPanelVtbl text_panel_vtbl =
+{
+    input_panel_QueryInterface,
+    input_panel_AddRef,
+    input_panel_Release,
+    input_panel_get_AttachedEditWindow,
+    input_panel_put_AttachedEditWindow,
+    input_panel_get_CurrentInteractionMode,
+    input_panel_get_DefaultInPlaceState,
+    input_panel_put_DefaultInPlaceState,
+    input_panel_get_CurrentInPlaceState,
+    input_panel_get_DefaultInputArea,
+    input_panel_put_DefaultInputArea,
+    input_panel_get_CurrentInputArea,
+    input_panel_get_CurrentCorrectionMode,
+    input_panel_get_PreferredInPlaceDirection,
+    input_panel_put_PreferredInPlaceDirection,
+    input_panel_get_ExpandPostInsertionCorrection,
+    input_panel_put_ExpandPostInsertionCorrection,
+    input_panel_get_InPlaceVisibleOnFocus,
+    input_panel_put_InPlaceVisibleOnFocus,
+    input_panel_get_InPlaceBoundingRectangle,
+    input_panel_get_PopUpCorrectionHeight,
+    input_panel_get_PopDownCorrectionHeight,
+    input_panel_CommitPendingInput,
+    input_panel_SetInPlaceVisibility,
+    input_panel_SetInPlacePosition,
+    input_panel_SetInPlaceHoverTargetPosition,
+    input_panel_Advise,
+    input_panel_Unadvise
+};
+
+
+static HRESULT WINAPI ClassFactory_QueryInterface(IClassFactory *iface, REFIID riid, void **ppv)
+{
+    *ppv = NULL;
+
+    if(IsEqualGUID(&IID_IUnknown, riid)) {
+        TRACE("(%p)->(IID_IUnknown %p)\n", iface, ppv);
+        *ppv = iface;
+    }else if(IsEqualGUID(&IID_IClassFactory, riid)) {
+        TRACE("(%p)->(IID_IClassFactory %p)\n", iface, ppv);
+        *ppv = iface;
+    }
+
+    if(*ppv) {
+        IUnknown_AddRef((IUnknown*)*ppv);
+        return S_OK;
+    }
+
+    WARN("(%p)->(%s %p)\n", iface, debugstr_guid(riid), ppv);
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI ClassFactory_AddRef(IClassFactory *iface)
+{
+    TRACE("(%p)\n", iface);
+    return 2;
+}
+
+static ULONG WINAPI ClassFactory_Release(IClassFactory *iface)
+{
+    TRACE("(%p)\n", iface);
+    return 1;
+}
+
+HRESULT WINAPI panelinput_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv)
+{
+    struct input_panel *panel;
+
+    TRACE("(%p %s %p)\n", outer, debugstr_guid(riid), ppv);
+
+    if (!(panel = malloc( sizeof(*panel) ))) return E_OUTOFMEMORY;
+    panel->ITextInputPanel_iface.lpVtbl = &text_panel_vtbl;
+    panel->ref = 1;
+
+    *ppv = &panel->ITextInputPanel_iface;
+    TRACE( "returning iface %p\n", *ppv );
+    return S_OK;
+}
+
+static HRESULT WINAPI ClassFactory_LockServer(IClassFactory *iface, BOOL fLock)
+{
+    TRACE("(%p)->(%x)\n", iface, fLock);
+    return S_OK;
+}
+
+static const IClassFactoryVtbl cfpanelinputlVtbl = {
+    ClassFactory_QueryInterface,
+    ClassFactory_AddRef,
+    ClassFactory_Release,
+    panelinput_CreateInstance,
+    ClassFactory_LockServer
+};
+
+static IClassFactory cf_ink = { &cfpanelinputlVtbl };
+
+HRESULT WINAPI DllGetClassObject( REFCLSID rclsid, REFIID riid, void **ppv )
+{
+    TRACE("%s %s %p\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv);
+
+    if (IsEqualGUID(&CLSID_TextInputPanel, rclsid))
+    {
+        return IClassFactory_QueryInterface(&cf_ink, riid, ppv);
+    }
+
+    return CLASS_E_CLASSNOTAVAILABLE;
+}
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c
index 11472c69f482..050f1fbb5265 100644
--- a/dlls/ucrtbase/tests/misc.c
+++ b/dlls/ucrtbase/tests/misc.c
@@ -843,9 +843,6 @@ static void test_math_errors(void)
     __setusermatherr(matherr_callback);
     module = GetModuleHandleW(L"ucrtbase.dll");
 
-    /* necessary so that exp(1e100)==INFINITY on glibc, we can remove this if we change our implementation */
-    fesetround(FE_TONEAREST);
-
     for(i = 0; i < ARRAY_SIZE(testsd); i++) {
         p_funcd = (void*)GetProcAddress(module, testsd[i].func);
         errno = -1;
@@ -2110,6 +2107,26 @@ static void test_cargf(void)
     __setusermatherr(NULL);
 }
 
+static void test_rint(void)
+{
+    int rounding_mode = fegetround();
+    double ret;
+
+    ok(!fesetround(FE_DOWNWARD), "fesetround failed\n");
+    ret = rint(-3.3);
+    ok(ret == -4.0, "ret = %lf\n", ret);
+    ret = rint(3.3);
+    ok(ret == 3.0, "ret = %lf\n", ret);
+
+    ok(!fesetround(FE_UPWARD), "fesetround failed\n");
+    ret = rint(-3.3);
+    ok(ret == -3.0, "ret = %lf\n", ret);
+    ret = rint(3.3);
+    ok(ret == 4.0, "ret = %lf\n", ret);
+
+    fesetround(rounding_mode);
+}
+
 START_TEST(misc)
 {
     int arg_c;
@@ -2162,4 +2179,5 @@ START_TEST(misc)
     test_cexp();
     test_carg();
     test_cargf();
+    test_rint();
 }
diff --git a/dlls/user32/combo.c b/dlls/user32/combo.c
index b251402602c9..cb9273412224 100644
--- a/dlls/user32/combo.c
+++ b/dlls/user32/combo.c
@@ -1672,11 +1672,17 @@ static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
    }
 }
 
-static LRESULT COMBO_GetComboBoxInfo(const HEADCOMBO *lphc, COMBOBOXINFO *pcbi)
+
+/*************************************************************************
+ *           GetComboBoxInfo   (USER32.@)
+ */
+BOOL WINAPI GetComboBoxInfo( HWND hwnd, COMBOBOXINFO *pcbi )
 {
-    if (!pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
-        return FALSE;
+    HEADCOMBO *lphc = get_control_state( hwnd );
 
+    if (!lphc || !pcbi || (pcbi->cbSize < sizeof(COMBOBOXINFO)))
+        return FALSE;
+    TRACE("(%p, %p)\n", hwnd, pcbi);
     pcbi->rcItem = lphc->textRect;
     pcbi->rcButton = lphc->buttonRect;
     pcbi->stateButton = 0;
@@ -2078,7 +2084,7 @@ LRESULT ComboWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM lPar
 	case CB_GETEXTENDEDUI:
 		return (lphc->wState & CBF_EUI) != 0;
 	case CB_GETCOMBOBOXINFO:
-		return COMBO_GetComboBoxInfo(lphc, (COMBOBOXINFO *)lParam);
+		return GetComboBoxInfo(hwnd, (COMBOBOXINFO *)lParam);
 	case CB_LIMITTEXT:
 		if( lphc->wState & CBF_EDIT )
 			return SendMessageW(lphc->hWndEdit, EM_LIMITTEXT, wParam, lParam);
@@ -2092,13 +2098,3 @@ LRESULT ComboWndProc_common( HWND hwnd, UINT message, WPARAM wParam, LPARAM lPar
       return unicode ? DefWindowProcW(hwnd, message, wParam, lParam) :
                        DefWindowProcA(hwnd, message, wParam, lParam);
 }
-
-/*************************************************************************
- *           GetComboBoxInfo   (USER32.@)
- */
-BOOL WINAPI GetComboBoxInfo(HWND hwndCombo,      /* [in] handle to combo box */
-			    PCOMBOBOXINFO pcbi   /* [in/out] combo box information */)
-{
-    TRACE("(%p, %p)\n", hwndCombo, pcbi);
-    return SendMessageW(hwndCombo, CB_GETCOMBOBOXINFO, 0, (LPARAM)pcbi);
-}
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 48b38166b75e..623fab14d113 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -750,14 +750,6 @@ BOOL WINAPI GetPointerDeviceProperties( HANDLE device, UINT32 *count,
     return FALSE;
 }
 
-BOOL WINAPI GetPointerDeviceRects( HANDLE device, RECT *device_rect, RECT *display_rect )
-{
-    FIXME( "device %p, device_rect %p, display_rect %p stub!\n",
-           device, device_rect, display_rect );
-    SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
-    return FALSE;
-}
-
 BOOL WINAPI GetPointerPenInfo( UINT32 id, POINTER_PEN_INFO *info )
 {
     FIXME( "id %u, info %p stub!\n", id, info );
diff --git a/dlls/user32/misc.c b/dlls/user32/misc.c
index 6333fcb48b4e..5e26601d2342 100644
--- a/dlls/user32/misc.c
+++ b/dlls/user32/misc.c
@@ -440,6 +440,15 @@ BOOL WINAPI UnregisterSuspendResumeNotification(HPOWERNOTIFY handle)
     return TRUE;
 }
 
+/**********************************************************************
+ * IsImmersiveProcess [USER32.@]
+ */
+BOOL WINAPI IsImmersiveProcess( HANDLE process )
+{
+    FIXME("(%p): stub\n", process);
+    return FALSE;
+}
+
 /**********************************************************************
  * IsWindowRedirectedForPrint [USER32.@]
  */
diff --git a/dlls/user32/tests/class.c b/dlls/user32/tests/class.c
index aa9a8e5003ef..9455f4ed9ebc 100644
--- a/dlls/user32/tests/class.c
+++ b/dlls/user32/tests/class.c
@@ -38,7 +38,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
@@ -2450,9 +2450,9 @@ static void test_class_name(void)
     todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "got error %lu\n", GetLastError());
 
     nameA = (const char *)GetClassLongPtrA(hwnd, GCLP_MENUNAME);
-    todo_wine ok(!nameA, "unexpected class name %s\n", debugstr_a(nameA));
+    todo_wine ok(!nameA || broken(nameA == (LPCSTR)MAKEINTATOM(2)) /* <= Win10 1709 */, "unexpected class name %s\n", debugstr_a(nameA));
     nameW = (const WCHAR *)GetClassLongPtrW(hwnd, GCLP_MENUNAME);
-    todo_wine ok(!nameW, "unexpected class name %s\n", debugstr_w(nameW));
+    todo_wine ok(!nameW || broken(nameW == (LPCWSTR)MAKEINTATOM(2)) /* <= Win10 1709 */, "unexpected class name %s\n", debugstr_w(nameW));
 
     DestroyWindow(hwnd);
     UnregisterClassW(wcex.lpszClassName, hinst);
diff --git a/dlls/user32/tests/combo.c b/dlls/user32/tests/combo.c
index 8d93369d79a6..cb190e32ae21 100644
--- a/dlls/user32/tests/combo.c
+++ b/dlls/user32/tests/combo.c
@@ -1026,6 +1026,56 @@ static void test_combo_measureitem(DWORD style)
     winetest_pop_context();
 }
 
+static int got_info;
+static WNDPROC old_combo_proc;
+
+static LRESULT CALLBACK combo_wnd_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam )
+{
+    if (msg == CB_GETCOMBOBOXINFO) got_info++;
+    return CallWindowProcA( old_combo_proc, hwnd, msg, wparam, lparam );
+}
+
+static DWORD CALLBACK combo_thread( void *arg )
+{
+    unsigned int ret;
+    COMBOBOXINFO info = { .cbSize = sizeof(COMBOBOXINFO) };
+    HWND combo = arg;
+
+    got_info = 0;
+    ret = GetComboBoxInfo(combo, &info);
+    ok( ret, "Failed to get combobox info structure.\n" );
+    ok( !got_info, "CB_GETCOMBOBOXINFO was sent from other thread\n" );
+    return 0;
+}
+
+static void test_combo_info(void)
+{
+    unsigned int ret;
+    COMBOBOXINFO info = { .cbSize = sizeof(COMBOBOXINFO) };
+    HWND combo;
+    HANDLE thread;
+    DWORD id;
+
+    combo = build_combo(CBS_DROPDOWN);
+    ok(!!combo, "Failed to create combo window.\n");
+
+    old_combo_proc = (void *)SetWindowLongPtrA( combo, GWLP_WNDPROC, (ULONG_PTR)combo_wnd_proc );
+
+    got_info = 0;
+    ret = GetComboBoxInfo( combo, &info );
+    ok( ret, "Failed to get combobox info structure.\n" );
+    ok( !got_info, "CB_GETCOMBOBOXINFO was sent\n" );
+    thread = CreateThread( NULL, 0, combo_thread, combo, 0, &id );
+    while (MsgWaitForMultipleObjects( 1, &thread, FALSE, INFINITE, MWMO_WAITALL ) != WAIT_OBJECT_0)
+    {
+        MSG msg;
+        while (PeekMessageA( &msg, 0, 0, 0, PM_REMOVE )) DispatchMessageA( &msg );
+    }
+    CloseHandle( thread );
+    SetWindowLongPtrA( combo, GWLP_WNDPROC, (ULONG_PTR)old_combo_proc );
+    DestroyWindow( combo );
+}
+
 START_TEST(combo)
 {
     brush_red = CreateSolidBrush(RGB(255, 0, 0));
@@ -1054,6 +1104,7 @@ START_TEST(combo)
     test_combo_measureitem(CBS_DROPDOWNLIST | CBS_OWNERDRAWVARIABLE);
     test_combo_measureitem(CBS_DROPDOWNLIST);
     test_combo_measureitem(CBS_DROPDOWN | CBS_OWNERDRAWFIXED);
+    test_combo_info();
 
     DestroyWindow(hMainWnd);
     DeleteObject(brush_red);
diff --git a/dlls/user32/tests/monitor.c b/dlls/user32/tests/monitor.c
index 69a46faba28a..b5c8f5bc6298 100644
--- a/dlls/user32/tests/monitor.c
+++ b/dlls/user32/tests/monitor.c
@@ -38,6 +38,8 @@
 #include <stdio.h>
 #include <math.h>
 
+#define HIMETRIC_PER_INCH 2540
+
 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_GPU_LUID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 1);
 DEFINE_DEVPROPKEY(DEVPROPKEY_MONITOR_OUTPUT_ID, 0xca085853, 0x16ce, 0x48aa, 0xb1, 0x14, 0xde, 0x9c, 0x72, 0x33, 0x42, 0x23, 2);
 
@@ -3217,7 +3219,7 @@ static void test_monitor_dpi_awareness( const struct monitor_info *infos, UINT c
         DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED,
         (DPI_AWARENESS_CONTEXT)0x7811,
     };
-    RECT virtual = {0}, scaled_virtual = {0}, monitor = {0}, scaled = {0}, primary = {0}, rect, expect_rect;
+    RECT virtual = {0}, scaled_virtual = {0}, monitor = {0}, scaled = {0}, primary = {0}, rect, expect_rect, device, scaled_device, expect_device;
     struct monitor_info tmp_info = {.handle = info->handle};
     UINT ret, i, x, y, expect_width, expect_height;
     HWND unaware_hwnd, aware_hwnd, primary_hwnd;
@@ -3233,16 +3235,26 @@ static void test_monitor_dpi_awareness( const struct monitor_info *infos, UINT c
     {
         if (infos[i].rect.left == 0 && infos[i].rect.top == 0) primary = infos[i].rect;
 
-        if (info != infos + i) UnionRect( &scaled_virtual, &scaled_virtual, &infos[i].rect );
+        SetRect( &device, infos[i].rect.left * HIMETRIC_PER_INCH / system_dpi, infos[i].rect.top * HIMETRIC_PER_INCH / system_dpi,
+                 infos[i].rect.right * HIMETRIC_PER_INCH / system_dpi, infos[i].rect.bottom * HIMETRIC_PER_INCH / system_dpi );
+        UnionRect( &virtual, &virtual, &infos[i].rect );
+        UnionRect( &expect_device, &expect_device, &device );
+
+        if (info != infos + i)
+        {
+            UnionRect( &scaled_virtual, &scaled_virtual, &infos[i].rect );
+            UnionRect( &scaled_device, &scaled_device, &device );
+        }
         else
         {
             scaled = monitor = infos[i].rect;
             scaled.right = scaled.left + MulDiv( scaled.right - scaled.left, 100, scale );
             scaled.bottom = scaled.top + MulDiv( scaled.bottom - scaled.top, 100, scale );
             UnionRect( &scaled_virtual, &scaled_virtual, &scaled );
+            SetRect( &device, scaled.left * HIMETRIC_PER_INCH / system_dpi, scaled.top * HIMETRIC_PER_INCH / system_dpi,
+                     scaled.right * HIMETRIC_PER_INCH / system_dpi, scaled.bottom * HIMETRIC_PER_INCH / system_dpi );
+            UnionRect( &scaled_device, &scaled_device, &device );
         }
-
-        UnionRect( &virtual, &virtual, &infos[i].rect );
     }
 
     unaware_hwnd = CreateWindowW( L"static", NULL, WS_POPUP | WS_VISIBLE, monitor.left + 100,
@@ -3279,6 +3291,12 @@ static void test_monitor_dpi_awareness( const struct monitor_info *infos, UINT c
     check_logical_physical_dpi( unaware_hwnd, monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1,
                                 monitor.left + 2 * scale + 1, monitor.top + 2 * scale + 1, FALSE );
 
+    ret = GetPointerDeviceRects( INVALID_HANDLE_VALUE, &device, &rect );
+    ok( ret, "GetPointerDeviceRects failed, error %lu.\n", GetLastError() );
+    ok( EqualRect( &rect, &scaled_virtual ), "got %s\n", wine_dbgstr_rect(&rect) );
+    ok( EqualRect( &device, &expect_device ) /* w10 */ || EqualRect( &device, &scaled_device ) /* w11 */,
+        "got %s vs %s / %s\n", wine_dbgstr_rect(&device), wine_dbgstr_rect(&expect_device), wine_dbgstr_rect(&scaled_device) );
+
     for (i = 0; i < ARRAY_SIZE(tests); i++)
     {
         BOOL monitor_aware = tests[i] == DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE ||
@@ -3565,6 +3583,12 @@ static void test_monitor_dpi_awareness( const struct monitor_info *infos, UINT c
         check_logical_physical_dpi( primary_hwnd, primary.left + 4 * scale + 1, primary.top + 4 * scale + 1,
                                     primary.left + 4 * scale + 1, primary.top + 4 * scale + 1, FALSE );
 
+        ret = GetPointerDeviceRects( INVALID_HANDLE_VALUE, &device, &rect );
+        ok( ret, "GetPointerDeviceRects failed, error %lu.\n", GetLastError() );
+        ok( EqualRect( &rect, monitor_aware ? &virtual : &scaled_virtual ), "got %s\n", wine_dbgstr_rect(&rect) );
+        ok( EqualRect( &device, &expect_device ) /* w10 */ || EqualRect( &device, &scaled_device ) /* w11 */,
+            "got %s vs %s / %s\n", wine_dbgstr_rect(&device), wine_dbgstr_rect(&expect_device), wine_dbgstr_rect(&scaled_device) );
+
         DestroyWindow( primary_hwnd );
         DestroyWindow( aware_hwnd );
 
@@ -3630,6 +3654,7 @@ static void test_monitor_dpi(void)
         {1024, 768},
     };
     UINT i, j, count, system_dpi, dpi_x, dpi_y;
+    RECT expect_rect, device, display;
     DPI_AWARENESS_CONTEXT old_ctx;
     float scale_x, scale_y;
     BOOL ret, is_virtual;
@@ -3660,11 +3685,14 @@ static void test_monitor_dpi(void)
     {
         for (j = 0; j < ARRAY_SIZE(tests); j++)
         {
+            RECT virtual = {0};
+
             if (tests[j].width && tests[j].height && !set_display_settings( infos[i].handle, tests[j].width, tests[j].height )) continue;
 
             get_monitor_infos( infos ); /* refresh infos as changing display settings may invalidate HMONITOR */
             scale_x = (infos[i].rect.right - infos[i].rect.left) / (float)(phys_infos[i].rect.right - phys_infos[i].rect.left);
             scale_y = (infos[i].rect.bottom - infos[i].rect.top) / (float)(phys_infos[i].rect.bottom - phys_infos[i].rect.top);
+            for (UINT i = 0; i < count; i++) UnionRect( &virtual, &virtual, &infos[i].rect );
 
             ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y );
             ok( ret, "GetDpiForMonitorInternal failed, error %lu\n", GetLastError() );
@@ -3704,6 +3732,13 @@ static void test_monitor_dpi(void)
                 ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", dpi_y );
             }
 
+            ret = GetPointerDeviceRects( INVALID_HANDLE_VALUE, &device, &display );
+            ok( ret, "GetPointerDeviceRects failed, error %lu.\n", GetLastError() );
+            ok( EqualRect( &display, &virtual ), "got %s\n", wine_dbgstr_rect( &display ) );
+            SetRect( &expect_rect, 0, 0, virtual.right * HIMETRIC_PER_INCH / system_dpi,
+                     virtual.bottom * HIMETRIC_PER_INCH / system_dpi );
+            ok( EqualRect( &device, &expect_rect ), "got %s\n", wine_dbgstr_rect( &device ) );
+
             pSetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 );
 
             ret = pGetDpiForMonitorInternal( infos[i].handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y );
@@ -3744,6 +3779,13 @@ static void test_monitor_dpi(void)
                 ok( fabs( dpi_y - system_dpi * scale_y ) < system_dpi * 0.05, "got MDT_RAW_DPI y %u\n", dpi_y );
             }
 
+            ret = GetPointerDeviceRects( INVALID_HANDLE_VALUE, &device, &display );
+            ok( ret, "GetPointerDeviceRects failed, error %lu.\n", GetLastError() );
+            ok( EqualRect( &display, &virtual ), "got %s\n", wine_dbgstr_rect( &display ) );
+            SetRect( &expect_rect, 0, 0, virtual.right * HIMETRIC_PER_INCH / system_dpi,
+                     virtual.bottom * HIMETRIC_PER_INCH / system_dpi );
+            ok( EqualRect( &device, &expect_rect ), "got %s\n", wine_dbgstr_rect( &device ) );
+
             pSetThreadDpiAwarenessContext( old_ctx );
         }
     }
@@ -3755,7 +3797,10 @@ static void test_monitor_dpi(void)
     {
         int min = 0, max = 0, cur = 0;
 
-        set_display_settings( infos[i].handle, 800, 600 );
+        /* native disables DPI scaling when resolution is below 1024x768, but Wine default CI resolution is 1024x768 */
+        if (winetest_platform_is_wine) set_display_settings( infos[i].handle, 800, 600 );
+        else set_display_settings( infos[i].handle, 1024, 768 );
+
         get_monitor_infos( infos ); /* refresh infos as changing display settings may invalidate HMONITOR */
 
         get_monitor_dpi_scale( infos[i].handle, &min, &cur, &max );
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index 6fd76d285330..6fa3a3b6ce74 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -63,7 +63,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec
index fe41f9cb2e70..e60331864902 100644
--- a/dlls/user32/user32.spec
+++ b/dlls/user32/user32.spec
@@ -630,7 +630,7 @@
 # @ stub GetPointerDeviceInputSpace
 # @ stub GetPointerDeviceOrientation
 @ stdcall GetPointerDeviceProperties(ptr ptr ptr)
-@ stdcall GetPointerDeviceRects(ptr ptr ptr)
+@ stdcall GetPointerDeviceRects(ptr ptr ptr) NtUserGetPointerDeviceRects
 @ stdcall GetPointerDevices(ptr ptr)
 # @ stub GetPointerFrameInfo
 # @ stub GetPointerFrameInfoHistory
@@ -785,7 +785,7 @@
 @ stdcall IsGUIThread(long)
 @ stdcall IsHungAppWindow(long)
 @ stdcall IsIconic(long)
-# @ stub IsImmersiveProcess
+@ stdcall IsImmersiveProcess(ptr)
 # @ stub IsInDesktopWindowBand
 @ stdcall IsMenu(long)
 @ stdcall IsMouseInPointerEnabled() NtUserIsMouseInPointerEnabled
diff --git a/dlls/uxtheme/tests/v6util.h b/dlls/uxtheme/tests/v6util.h
index a4e928f51bff..c88223ef4b92 100644
--- a/dlls/uxtheme/tests/v6util.h
+++ b/dlls/uxtheme/tests/v6util.h
@@ -22,7 +22,7 @@
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined __x86_64__
 #define ARCH "amd64"
diff --git a/dlls/vbscript/interp.c b/dlls/vbscript/interp.c
index c57b28ab90e4..a5f970be0339 100644
--- a/dlls/vbscript/interp.c
+++ b/dlls/vbscript/interp.c
@@ -97,34 +97,41 @@ static BOOL lookup_dynamic_vars(dynamic_var_t *var, const WCHAR *name, ref_t *re
     return FALSE;
 }
 
-static BOOL lookup_global_vars(ScriptDisp *script, const WCHAR *name, ref_t *ref)
+static void ref_from_entry(scriptdisp_entry_t *member, ref_t *ref)
 {
-    dynamic_var_t *var = script_disp_find_var(script, name);
-
-    if(!var)
-        return FALSE;
-
-    ref->type = var->is_const ? REF_CONST : REF_VAR;
-    ref->u.v = &var->v;
-    return TRUE;
+    switch(member->type) {
+    case SCRIPTDISP_VAR:
+        ref->type = member->u.var->is_const ? REF_CONST : REF_VAR;
+        ref->u.v = &member->u.var->v;
+        break;
+    case SCRIPTDISP_FUNC:
+        ref->type = REF_FUNC;
+        ref->u.f = member->u.func;
+        break;
+    case SCRIPTDISP_HOSTPROP:
+    case SCRIPTDISP_BUILTIN:
+        ref->type = REF_DISP;
+        ref->u.d.disp = member->u.host.disp;
+        ref->u.d.id = member->u.host.id;
+        break;
+    }
 }
 
-static BOOL lookup_global_funcs(ScriptDisp *script, const WCHAR *name, ref_t *ref)
+/* A global name maps to a single member, so one lookup covers variables,
+   functions and host properties cached through a named item's dispatch. */
+static scriptdisp_entry_t *lookup_global_member(ScriptDisp *script, const WCHAR *name, ref_t *ref)
 {
-    function_t *func = script_disp_find_func(script, name);
+    scriptdisp_entry_t *member = script_disp_find_member(script, name);
 
-    if(func) {
-        ref->type = REF_FUNC;
-        ref->u.f = func;
-        return TRUE;
-    }
-
-    return FALSE;
+    if(member)
+        ref_from_entry(member, ref);
+    return member;
 }
 
 static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_t invoke_type, ref_t *ref)
 {
     ScriptDisp *script_obj = ctx->script->script_obj;
+    scriptdisp_entry_t *member;
     named_item_t *item;
     unsigned i;
     DISPID id;
@@ -202,9 +209,7 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
     }
 
     if(ctx->code->named_item) {
-        if(lookup_global_vars(ctx->code->named_item->script_obj, name, ref))
-            return S_OK;
-        if(lookup_global_funcs(ctx->code->named_item->script_obj, name, ref))
+        if(lookup_global_member(ctx->code->named_item->script_obj, name, ref))
             return S_OK;
     }
 
@@ -213,6 +218,10 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
     {
         hres = disp_get_id(ctx->func->code_ctx->named_item->disp, name, invoke_type, TRUE, &id);
         if(SUCCEEDED(hres)) {
+            /* Cache the host property in the item's tree; subsequent lookups
+               find it directly and never query the host dispatch again. */
+            script_disp_add_hostprop(ctx->code->named_item->script_obj, name,
+                    ctx->func->code_ctx->named_item->disp, id);
             ref->type = REF_DISP;
             ref->u.d.disp = ctx->func->code_ctx->named_item->disp;
             ref->u.d.id = id;
@@ -220,30 +229,42 @@ static HRESULT lookup_identifier(exec_ctx_t *ctx, BSTR name, vbdisp_invoke_type_
         }
     }
 
-    if(lookup_global_vars(script_obj, name, ref))
+    if(lookup_global_member(script_obj, name, ref))
         return S_OK;
-    if(lookup_global_funcs(script_obj, name, ref))
+
+    /* A visible named item shadows a builtin function of the same name (global
+       members of host objects do not), so it is resolved first. */
+    item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE);
+    if(item && item->disp) {
+        ref->type = REF_OBJ;
+        ref->u.obj = item->disp;
         return S_OK;
+    }
 
     hres = get_builtin_id(ctx->script->global_obj, name, &id);
     if(SUCCEEDED(hres)) {
+        /* Cache the builtin in the global tree; subsequent lookups find it
+           there and skip the named item and builtin lookups entirely. */
+        script_disp_add_builtin(script_obj, name, &ctx->script->global_obj->IDispatch_iface, id);
         ref->type = REF_DISP;
         ref->u.d.disp = &ctx->script->global_obj->IDispatch_iface;
         ref->u.d.id = id;
         return S_OK;
     }
 
-    item = lookup_named_item(ctx->script, name, SCRIPTITEM_ISVISIBLE);
-    if(item && item->disp) {
-        ref->type = REF_OBJ;
-        ref->u.obj = item->disp;
-        return S_OK;
-    }
-
     LIST_FOR_EACH_ENTRY(item, &ctx->script->named_items, named_item_t, entry) {
         if((item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
+            if(item->script_obj && (member = script_disp_find_member(item->script_obj, name))
+               && member->type == SCRIPTDISP_HOSTPROP) {
+                ref->type = REF_DISP;
+                ref->u.d.disp = member->u.host.disp;
+                ref->u.d.id = member->u.host.id;
+                return S_OK;
+            }
             hres = disp_get_id(item->disp, name, invoke_type, FALSE, &id);
             if(SUCCEEDED(hres)) {
+                if(item->script_obj)
+                    script_disp_add_hostprop(item->script_obj, name, item->disp, id);
                 ref->type = REF_DISP;
                 ref->u.d.disp = item->disp;
                 ref->u.d.id = id;
@@ -296,7 +317,8 @@ static HRESULT add_dynamic_var(exec_ctx_t *ctx, const WCHAR *name,
         }
         {
             new_var->index = script_obj->global_vars_cnt;
-            rb_put(&script_obj->var_tree, new_var->name, &new_var->entry);
+            if(!script_disp_add_var(script_obj, new_var))
+                return E_OUTOFMEMORY;
         }
         script_obj->global_vars[script_obj->global_vars_cnt++] = new_var;
     }else {
@@ -2469,6 +2491,11 @@ static HRESULT var_cmp(exec_ctx_t *ctx, VARIANT *l, VARIANT *r, unsigned flags)
 
     TRACE("%s %s\n", debugstr_variant(l), debugstr_variant(r));
 
+    /* Comparing an array raises type mismatch on native; VarCmp would instead
+     * fail with DISP_E_BADVARTYPE (the unsupported-type error 458). */
+    if((V_VT(l) & VT_ARRAY) || (V_VT(r) & VT_ARRAY))
+        return MAKE_VBSERROR(VBSE_TYPE_MISMATCH);
+
     if(is_unsupported_script_vt(lvt) || is_unsupported_script_vt(rvt))
         return MAKE_VBSERROR(VBSE_INVALID_TYPELIB_VARIABLE);
 
diff --git a/dlls/vbscript/lex.c b/dlls/vbscript/lex.c
index ef20604c8dbf..5273a88bdbbc 100644
--- a/dlls/vbscript/lex.c
+++ b/dlls/vbscript/lex.c
@@ -434,6 +434,10 @@ static int parse_oct_literal(parser_ctx_t *ctx, LONG *ret)
         }
     }
 
+    /* A decimal digit (8 or 9) ends the octal run: it is an invalid octal digit. */
+    if(*ctx->ptr == '8' || *ctx->ptr == '9')
+        return lex_error(ctx, MAKE_VBSERROR(VBSE_SYNTAX_ERROR));
+
     if(*ctx->ptr == '&') {
         ctx->ptr++;
         *ret = (LONG)l;
@@ -590,6 +594,11 @@ static int parse_next_token(void *lval, unsigned *loc, parser_ctx_t *ctx)
             return parse_hex_literal(ctx, lval);
         if((*ctx->ptr == 'o' || *ctx->ptr == 'O') && oct_to_int(ctx->ptr[1]) != -1)
             return parse_oct_literal(ctx, lval);
+        if(oct_to_int(*ctx->ptr) != -1) {
+            /* A bare '&' followed by octal digits (no 'o'/'O') is also octal. */
+            ctx->ptr--;
+            return parse_oct_literal(ctx, lval);
+        }
         return '&';
     case '=':
         switch(*++ctx->ptr) {
diff --git a/dlls/vbscript/tests/lang.vbs b/dlls/vbscript/tests/lang.vbs
index 6c9628d7e69e..bba209dfa925 100644
--- a/dlls/vbscript/tests/lang.vbs
+++ b/dlls/vbscript/tests/lang.vbs
@@ -103,10 +103,19 @@ Call ok(getVT(&O77) = "VT_I2", "getVT(&O77) is not VT_I2")
 Call ok(getVT(&O200000) = "VT_I4", "getVT(&O200000) is not VT_I4")
 Call ok(getVT(&O177777&) = "VT_I4", "getVT(&O177777&) is not VT_I4")
 
+' Bare '&' followed by octal digits (no 'o'/'O') is octal too
+Call ok(&100 = 64, "&100 <> 64")
+Call ok(&777 = 511, "&777 <> 511")
+Call ok(&10000000 = 2097152, "&10000000 <> 2097152")
+Call ok(&010 = 8, "&010 <> 8")
+Call ok(&32 = 26, "&32 <> 26")
+Call ok(&17& = 15, "&17& <> 15")
+
 sub testOctalLiteralErrors()
     Dim oct
     on error resume next
     Err.Clear : oct = Eval("&O8") : call ok(Err.number = 1002, "&O8 should be syntax error, got err=" & Err.number)
+    Err.Clear : oct = Eval("&19") : call ok(Err.number = 1002, "&19 should be syntax error, got err=" & Err.number)
 end sub
 call testOctalLiteralErrors()
 
@@ -229,6 +238,26 @@ Call ok(err.number = 13, """"" > 0 err.number = " & err.number)
 err.clear
 x = (5 > "abc")
 Call ok(err.number = 13, "5 > ""abc"" err.number = " & err.number)
+' Comparing an array raises type mismatch (error 13), not the unsupported-type
+' error 458. Holds for every comparison operator and every other operand type,
+' including Empty and Null (the array type mismatch wins over Null propagation).
+Dim arrcmp, arrcmp2, arrmd(2,2)
+arrcmp = Array(1,2,3)
+arrcmp2 = Array(1,2,3)
+err.clear : x = (arrcmp <> "")     : Call ok(err.number = 13, "array <> empty string err=" & err.number)
+err.clear : x = (arrcmp = "")      : Call ok(err.number = 13, "array = empty string err=" & err.number)
+err.clear : x = ("" <> arrcmp)     : Call ok(err.number = 13, "empty string <> array err=" & err.number)
+err.clear : x = (arrcmp <> 0)      : Call ok(err.number = 13, "array <> 0 err=" & err.number)
+err.clear : x = (arrcmp < 5)       : Call ok(err.number = 13, "array < 5 err=" & err.number)
+err.clear : x = (arrcmp > 5)       : Call ok(err.number = 13, "array > 5 err=" & err.number)
+err.clear : x = (arrcmp >= 5)      : Call ok(err.number = 13, "array >= 5 err=" & err.number)
+err.clear : x = (arrcmp <= 5)      : Call ok(err.number = 13, "array <= 5 err=" & err.number)
+err.clear : x = (arrcmp = arrcmp2) : Call ok(err.number = 13, "array = array err=" & err.number)
+err.clear : x = (arrcmp = arrcmp)  : Call ok(err.number = 13, "array = same array err=" & err.number)
+err.clear : x = (arrcmp = Empty)   : Call ok(err.number = 13, "array = Empty err=" & err.number)
+err.clear : x = (arrcmp = Null)    : Call ok(err.number = 13, "array = Null err=" & err.number)
+err.clear : x = (arrcmp <> Null)   : Call ok(err.number = 13, "array <> Null err=" & err.number)
+err.clear : x = (arrmd = "")       : Call ok(err.number = 13, "multidim array = empty string err=" & err.number)
 on error goto 0
 
 ' BSTR coerces to numeric for comparison even when it carries VT_BYREF
diff --git a/dlls/vbscript/tests/run.c b/dlls/vbscript/tests/run.c
index bee738d236c4..20a835f77025 100644
--- a/dlls/vbscript/tests/run.c
+++ b/dlls/vbscript/tests/run.c
@@ -1242,6 +1242,8 @@ static HRESULT WINAPI Global_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD
         { L"invokeDisp",      DISPID_GLOBAL_INVOKEDISP },
         { L"invokeMethod",    DISPID_GLOBAL_INVOKEMETHOD },
         { L"testObj",         DISPID_GLOBAL_TESTOBJ },
+        /* host property sharing its name with a builtin function */
+        { L"InputBox",        DISPID_GLOBAL_TESTOBJ },
         { L"collectionObj" ,  DISPID_GLOBAL_COLLOBJ },
         { L"vbvar",           DISPID_GLOBAL_VBVAR, REF_EXPECT(global_vbvar_d) },
         { L"letobj",          DISPID_GLOBAL_LETOBJ },
@@ -2079,6 +2081,8 @@ static HRESULT WINAPI ActiveScriptSite_GetItemInfo(IActiveScriptSite *iface, LPC
         *ppiunkItem = (IUnknown*)&Global;
     }else if(!lstrcmpW(pstrName, L"indexedObj")) {
         *ppiunkItem = (IUnknown*)&indexedObj;
+    }else if(!lstrcmpW(pstrName, L"Trim")) {
+        *ppiunkItem = (IUnknown*)&testObj;
     }else {
         ok(0, "unexpected pstrName %s\n", wine_dbgstr_w(pstrName));
         *ppiunkItem = NULL;
@@ -3745,6 +3749,39 @@ static void test_sub_decl_scope(void)
     }
 }
 
+static void test_named_item_builtin_shadowing(void)
+{
+    IActiveScriptParse *parser;
+    IActiveScript *engine;
+    BSTR str;
+    HRESULT hres;
+
+    strict_dispid_check = FALSE;
+
+    engine = create_and_init_script(SCRIPTITEM_GLOBALMEMBERS, TRUE);
+    if(!engine)
+        return;
+
+    hres = IActiveScript_QueryInterface(engine, &IID_IActiveScriptParse, (void**)&parser);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres);
+
+    hres = IActiveScript_AddNamedItem(engine, L"Trim", SCRIPTITEM_ISVISIBLE);
+    ok(hres == S_OK, "AddNamedItem failed: %08lx\n", hres);
+
+    str = SysAllocString(L"Call ok(getVT(Trim) = \"VT_DISPATCH\", \"getVT(Trim) = \" & getVT(Trim))\n"
+                         L"Trim.propput = 1\n");
+    SET_EXPECT(testobj_propput_d);
+    SET_EXPECT(testobj_propput_i);
+    hres = IActiveScriptParse_ParseScriptText(parser, str, NULL, NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres);
+    CHECK_CALLED(testobj_propput_d);
+    CHECK_CALLED(testobj_propput_i);
+    SysFreeString(str);
+
+    IActiveScriptParse_Release(parser);
+    close_script(engine);
+}
+
 static void test_msgbox(void)
 {
     HRESULT hres;
@@ -4240,6 +4277,12 @@ static void run_tests(void)
     CHECK_CALLED(testobj_propput_d);
     CHECK_CALLED(testobj_propput_i);
 
+    /* the builtin function wins over a global-members host property of the same name */
+    SET_EXPECT(OnScriptError);
+    hres = parse_script_wr(L"InputBox.propput = 1");
+    ok(hres == MAKE_VBSERROR(450), "InputBox.propput = 1 returned: %08lx\n", hres);
+    CHECK_CALLED(OnScriptError);
+
     SET_EXPECT(global_propargput_d);
     SET_EXPECT(global_propargput_i);
     parse_script_w(L"propargput(counter(), counter()) = counter()");
@@ -4438,6 +4481,7 @@ static void run_tests(void)
     test_procedures();
     test_gc();
     test_msgbox();
+    test_named_item_builtin_shadowing();
     test_isexpression();
     test_option_explicit_errors();
     test_parse_errors();
diff --git a/dlls/vbscript/tests/vbscript.c b/dlls/vbscript/tests/vbscript.c
index 6fe7893d3b00..9162435c7b8e 100644
--- a/dlls/vbscript/tests/vbscript.c
+++ b/dlls/vbscript/tests/vbscript.c
@@ -304,15 +304,19 @@ static const IDispatchVtbl persistent_named_item_vtbl = {
 
 static IDispatch persistent_named_item = { &persistent_named_item_vtbl };
 
+static int shadow_method_dispid_queries, shadow_prop_dispid_queries;
+
 static HRESULT WINAPI shadowing_GetIDsOfNames(IDispatch *iface, REFIID riid, LPOLESTR *names, UINT name_cnt,
                                               LCID lcid, DISPID *ids)
 {
     ok(name_cnt == 1, "name_cnt = %u\n", name_cnt);
     if(!wcscmp(names[0], L"shadowMethod")) {
+        shadow_method_dispid_queries++;
         *ids = 1;
         return S_OK;
     }
     if(!wcscmp(names[0], L"shadowProp")) {
+        shadow_prop_dispid_queries++;
         *ids = 2;
         return S_OK;
     }
@@ -3080,6 +3084,91 @@ static void test_named_item_no_dim_routes_to_host(void)
     ok(!ref, "ref = %ld\n", ref);
 }
 
+static void test_named_item_dispid_caching(void)
+{
+    IActiveScriptParse *parse;
+    IActiveScript *script;
+    HRESULT hres;
+    LONG ref;
+
+    /* The engine resolves a host member name through GetIDsOfNames once and
+     * reuses the DISPID for subsequent lookups, within and across script
+     * chunks. */
+
+    script = create_vbscript();
+    hres = IActiveScript_QueryInterface(script, &IID_IActiveScriptParse, (void**)&parse);
+    ok(hres == S_OK, "Could not get IActiveScriptParse: %08lx\n", hres);
+
+    SET_EXPECT(GetLCID);
+    hres = IActiveScript_SetScriptSite(script, &ActiveScriptSite);
+    ok(hres == S_OK, "SetScriptSite failed: %08lx\n", hres);
+    CHECK_CALLED(GetLCID);
+
+    hres = IActiveScript_AddNamedItem(script, L"shadowingItem", SCRIPTITEM_ISVISIBLE);
+    ok(hres == S_OK, "AddNamedItem failed: %08lx\n", hres);
+
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    hres = IActiveScriptParse_InitNew(parse);
+    ok(hres == S_OK, "InitNew failed: %08lx\n", hres);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+
+    SET_EXPECT(OnStateChange_CONNECTED);
+    hres = IActiveScript_SetScriptState(script, SCRIPTSTATE_CONNECTED);
+    ok(hres == S_OK, "SetScriptState failed: %08lx\n", hres);
+    CHECK_CALLED(OnStateChange_CONNECTED);
+
+    shadow_method_dispid_queries = 0;
+    shadow_prop_dispid_queries = 0;
+
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(host_shadow_propput);
+    SET_EXPECT(host_shadow_propget);
+    SET_EXPECT(host_shadow_method);
+    hres = IActiveScriptParse_ParseScriptText(parse, L"shadowProp = 5\nx = shadowProp\nshadowMethod\n",
+            L"shadowingItem", NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(host_shadow_propput);
+    CHECK_CALLED(host_shadow_propget);
+    CHECK_CALLED(host_shadow_method);
+
+    ok(shadow_prop_dispid_queries == 1, "shadowProp resolved %d times, expected 1\n", shadow_prop_dispid_queries);
+    ok(shadow_method_dispid_queries == 1, "shadowMethod resolved %d times, expected 1\n", shadow_method_dispid_queries);
+
+    /* a later script chunk reuses the cached ids too */
+    SET_EXPECT(OnEnterScript);
+    SET_EXPECT(OnLeaveScript);
+    SET_EXPECT(host_shadow_propput);
+    SET_EXPECT(host_shadow_method);
+    hres = IActiveScriptParse_ParseScriptText(parse, L"shadowProp = 6\nshadowMethod\n",
+            L"shadowingItem", NULL, NULL, 0, 0, 0, NULL, NULL);
+    ok(hres == S_OK, "ParseScriptText failed: %08lx\n", hres);
+    CHECK_CALLED(OnEnterScript);
+    CHECK_CALLED(OnLeaveScript);
+    CHECK_CALLED(host_shadow_propput);
+    CHECK_CALLED(host_shadow_method);
+
+    ok(shadow_prop_dispid_queries == 1, "shadowProp resolved %d times after second chunk, expected 1\n",
+       shadow_prop_dispid_queries);
+    ok(shadow_method_dispid_queries == 1, "shadowMethod resolved %d times after second chunk, expected 1\n",
+       shadow_method_dispid_queries);
+
+    SET_EXPECT(OnStateChange_DISCONNECTED);
+    SET_EXPECT(OnStateChange_INITIALIZED);
+    SET_EXPECT(OnStateChange_CLOSED);
+    hres = IActiveScript_Close(script);
+    ok(hres == S_OK, "Close failed: %08lx\n", hres);
+    CHECK_CALLED(OnStateChange_DISCONNECTED);
+    CHECK_CALLED(OnStateChange_INITIALIZED);
+    CHECK_CALLED(OnStateChange_CLOSED);
+
+    IActiveScriptParse_Release(parse);
+    ref = IActiveScript_Release(script);
+    ok(!ref, "ref = %ld\n", ref);
+}
+
 static void test_const_at_top_level(void)
 {
     IActiveScriptParse *parse;
@@ -3521,6 +3610,7 @@ START_TEST(vbscript)
         test_named_item_sub_shadowing();
         test_named_item_dim_shadowing();
         test_named_item_no_dim_routes_to_host();
+        test_named_item_dispid_caching();
         test_const_at_top_level();
         test_cross_parse_name_redef();
         test_scriptdisp();
diff --git a/dlls/vbscript/vbdisp.c b/dlls/vbscript/vbdisp.c
index d953c19bb304..487aa3c3b963 100644
--- a/dlls/vbscript/vbdisp.c
+++ b/dlls/vbscript/vbdisp.c
@@ -29,36 +29,134 @@ static const GUID GUID_VBScriptTypeInfo = {0xc59c6b12,0xf6c1,0x11cf,{0x88,0x35,0
 #define DISPID_FUNCTION_MASK 0x20000000
 #define FDEX_VERSION_MASK 0xf0000000
 
-static int func_name_cmp(const void *key, const struct rb_entry *entry)
+static int scriptdisp_member_cmp(const void *key, const struct rb_entry *entry)
 {
-    function_t *func = RB_ENTRY_VALUE(entry, function_t, entry);
-    return vbs_wcsicmp(key, func->name);
+    scriptdisp_entry_t *member = RB_ENTRY_VALUE(entry, scriptdisp_entry_t, entry);
+    return vbs_wcsicmp(key, member->name);
 }
 
-static int var_name_cmp(const void *key, const struct rb_entry *entry)
+scriptdisp_entry_t *script_disp_find_member(ScriptDisp *disp, const WCHAR *name)
 {
-    dynamic_var_t *var = RB_ENTRY_VALUE(entry, dynamic_var_t, entry);
-    return vbs_wcsicmp(key, var->name);
+    struct rb_entry *entry = rb_get(&disp->members, name);
+    return entry ? RB_ENTRY_VALUE(entry, scriptdisp_entry_t, entry) : NULL;
+}
+
+/* Insert name into the member tree, or return the existing entry for it; the
+   caller fills in the type and payload. The name string must stay valid for
+   the lifetime of the entry. */
+static scriptdisp_entry_t *script_disp_add_member(ScriptDisp *disp, const WCHAR *name)
+{
+    scriptdisp_entry_t *member = script_disp_find_member(disp, name);
+
+    if (member) {
+        member->name = name;
+        return member;
+    }
+
+    if (!(member = heap_pool_alloc(&disp->heap, sizeof(*member))))
+        return NULL;
+    member->name = name;
+    rb_put(&disp->members, name, &member->entry);
+    return member;
+}
+
+scriptdisp_entry_t *script_disp_add_var(ScriptDisp *disp, dynamic_var_t *var)
+{
+    scriptdisp_entry_t *member = script_disp_add_member(disp, var->name);
+
+    if (member) {
+        member->type = SCRIPTDISP_VAR;
+        member->u.var = var;
+    }
+    return member;
+}
+
+scriptdisp_entry_t *script_disp_add_func(ScriptDisp *disp, function_t *func)
+{
+    scriptdisp_entry_t *member = script_disp_add_member(disp, func->name);
+
+    if (member) {
+        member->type = SCRIPTDISP_FUNC;
+        member->u.func = func;
+    }
+    return member;
+}
+
+/* Cache a host property resolved through a named item's dispatch. Returns NULL
+   without caching when a real variable or function already owns the name, so a
+   later script declaration is never shadowed by a stale host entry. */
+scriptdisp_entry_t *script_disp_add_hostprop(ScriptDisp *disp, const WCHAR *name, IDispatch *disp_obj, DISPID id)
+{
+    scriptdisp_entry_t *member = script_disp_find_member(disp, name);
+
+    if (member) {
+        if (member->type != SCRIPTDISP_HOSTPROP)
+            return NULL;
+    } else {
+        WCHAR *str;
+        size_t size = (lstrlenW(name) + 1) * sizeof(WCHAR);
+
+        /* The name must outlive the entry; the caller's bytecode string may not,
+           so keep a copy in the dispatch's own pool. */
+        if (!(str = heap_pool_alloc(&disp->heap, size)))
+            return NULL;
+        memcpy(str, name, size);
+
+        if (!(member = script_disp_add_member(disp, str)))
+            return NULL;
+    }
+
+    member->type = SCRIPTDISP_HOSTPROP;
+    member->u.host.disp = disp_obj;
+    member->u.host.id = id;
+    return member;
+}
+
+/* Cache a builtin function resolved through the global object, so subsequent
+   lookups find it in the tree instead of querying the builtins again. */
+scriptdisp_entry_t *script_disp_add_builtin(ScriptDisp *disp, const WCHAR *name, IDispatch *disp_obj, DISPID id)
+{
+    scriptdisp_entry_t *member = script_disp_find_member(disp, name);
+
+    if (member) {
+        if (member->type != SCRIPTDISP_BUILTIN)
+            return NULL;
+    } else {
+        WCHAR *str;
+        size_t size = (lstrlenW(name) + 1) * sizeof(WCHAR);
+
+        if (!(str = heap_pool_alloc(&disp->heap, size)))
+            return NULL;
+        memcpy(str, name, size);
+
+        if (!(member = script_disp_add_member(disp, str)))
+            return NULL;
+    }
+
+    member->type = SCRIPTDISP_BUILTIN;
+    member->u.host.disp = disp_obj;
+    member->u.host.id = id;
+    return member;
 }
 
 function_t *script_disp_find_func(ScriptDisp *disp, const WCHAR *name)
 {
-    struct rb_entry *entry = rb_get(&disp->func_tree, name);
+    scriptdisp_entry_t *member = script_disp_find_member(disp, name);
 
-    if (!entry)
+    if (!member || member->type != SCRIPTDISP_FUNC)
         return NULL;
 
-    return RB_ENTRY_VALUE(entry, function_t, entry);
+    return member->u.func;
 }
 
 dynamic_var_t *script_disp_find_var(ScriptDisp *disp, const WCHAR *name)
 {
-    struct rb_entry *entry = rb_get(&disp->var_tree, name);
+    scriptdisp_entry_t *member = script_disp_find_member(disp, name);
 
-    if (!entry)
+    if (!member || member->type != SCRIPTDISP_VAR)
         return NULL;
 
-    return RB_ENTRY_VALUE(entry, dynamic_var_t, entry);
+    return member->u.var;
 }
 
 static inline BOOL is_func_id(vbdisp_t *This, DISPID id)
@@ -1209,10 +1307,10 @@ static HRESULT WINAPI ScriptTypeInfo_GetIDsOfNames(ITypeInfo *iface, LPOLESTR *r
     }
 
     {
-        struct rb_entry *entry = rb_get(&This->disp->var_tree, name);
-        if (entry)
+        dynamic_var_t *var = script_disp_find_var(This->disp, name);
+        if (var)
         {
-            pMemId[0] = RB_ENTRY_VALUE(entry, dynamic_var_t, entry)->index + 1;
+            pMemId[0] = var->index + 1;
             return S_OK;
         }
     }
@@ -1513,10 +1611,9 @@ static HRESULT WINAPI ScriptTypeComp_Bind(ITypeComp *iface, LPOLESTR szName, ULO
     }
 
     {
-        struct rb_entry *entry = rb_get(&This->disp->var_tree, szName);
-        if (entry)
+        dynamic_var_t *var = script_disp_find_var(This->disp, szName);
+        if (var)
         {
-            dynamic_var_t *var = RB_ENTRY_VALUE(entry, dynamic_var_t, entry);
             if (!(flags & INVOKE_PROPERTYGET)) return TYPE_E_TYPEMISMATCH;
 
             hr = ITypeInfo_GetVarDesc(&This->ITypeInfo_iface, var->index, &pBindPtr->lpvardesc);
@@ -1736,24 +1833,24 @@ static HRESULT WINAPI ScriptDisp_Invoke(IDispatchEx *iface, DISPID dispIdMember,
 static HRESULT WINAPI ScriptDisp_GetDispID(IDispatchEx *iface, BSTR bstrName, DWORD grfdex, DISPID *pid)
 {
     ScriptDisp *This = ScriptDisp_from_IDispatchEx(iface);
-    struct rb_entry *entry;
+    scriptdisp_entry_t *member;
 
     TRACE("(%p)->(%s %lx %p)\n", This, debugstr_w(bstrName), grfdex, pid);
 
     if(!This->ctx)
         return E_UNEXPECTED;
 
-    entry = rb_get(&This->var_tree, bstrName);
-    if(entry) {
-        *pid = RB_ENTRY_VALUE(entry, dynamic_var_t, entry)->index + 1;
-        return S_OK;
-    }
-
-    entry = rb_get(&This->func_tree, bstrName);
-    if(entry) {
-        function_t *func = RB_ENTRY_VALUE(entry, function_t, entry);
-        *pid = func->index + 1 + DISPID_FUNCTION_MASK;
-        return S_OK;
+    member = script_disp_find_member(This, bstrName);
+    if(member) {
+        /* Host properties cached on this dispatch are not script members. */
+        if(member->type == SCRIPTDISP_FUNC) {
+            *pid = member->u.func->index + 1 + DISPID_FUNCTION_MASK;
+            return S_OK;
+        }
+        if(member->type == SCRIPTDISP_VAR) {
+            *pid = member->u.var->index + 1;
+            return S_OK;
+        }
     }
 
     *pid = -1;
@@ -1892,8 +1989,7 @@ HRESULT create_script_disp(script_ctx_t *ctx, ScriptDisp **ret)
     script_disp->ref = 1;
     script_disp->ctx = ctx;
     heap_pool_init(&script_disp->heap);
-    rb_init(&script_disp->func_tree, func_name_cmp);
-    rb_init(&script_disp->var_tree, var_name_cmp);
+    rb_init(&script_disp->members, scriptdisp_member_cmp);
     script_disp->rnd = 0x50000;
 
     *ret = script_disp;
diff --git a/dlls/vbscript/vbscript.c b/dlls/vbscript/vbscript.c
index 43f8dd2fdd5d..a4cfeea9eab4 100644
--- a/dlls/vbscript/vbscript.c
+++ b/dlls/vbscript/vbscript.c
@@ -140,12 +140,17 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL
 
     for (i = 0; i < code->main_code.var_cnt; i++)
     {
-        dynamic_var_t *existing = script_disp_find_var(obj, code->main_code.vars[i].name);
-
-        /* A Dim may shadow a const from a previous compile unit: it creates a
-           fresh variable that name lookups resolve to from now on, while the
-           defining compile unit keeps using the inlined const value. */
-        if (existing && !existing->is_const)
+        scriptdisp_entry_t *existing = script_disp_find_member(obj, code->main_code.vars[i].name);
+
+        /* Dim is permissive: it keeps an existing variable or function of the
+           same name. A const from a previous compile unit is the exception: it
+           is shadowed by a fresh variable that name lookups resolve to from now
+           on, while the defining compile unit keeps using the inlined value. A
+           cached host property is likewise shadowed by the fresh variable, which
+           outranks the host dispatch in the named item scope. */
+        if (existing && existing->type == SCRIPTDISP_FUNC)
+            continue;
+        if (existing && existing->type == SCRIPTDISP_VAR && !existing->u.var->is_const)
             continue;
 
         if (!(var = heap_pool_alloc(&obj->heap, sizeof(*var))))
@@ -158,33 +163,26 @@ HRESULT exec_global_code(script_ctx_t *ctx, vbscode_t *code, VARIANT *res, BOOL
         var->is_const = FALSE;
         var->array = NULL;
         var->index = obj->global_vars_cnt;
-        if (existing)
-            rb_remove(&obj->var_tree, &existing->entry);
-        rb_put(&obj->var_tree, var->name, &var->entry);
+        if (!script_disp_add_var(obj, var))
+            return E_OUTOFMEMORY;
 
         obj->global_vars[obj->global_vars_cnt++] = var;
     }
 
     for (func_iter = code->funcs; func_iter; func_iter = func_iter->next)
     {
-        struct rb_entry *entry = rb_get(&obj->func_tree, func_iter->name);
+        scriptdisp_entry_t *existing = script_disp_find_member(obj, func_iter->name);
 
-        if (entry)
-        {
-            function_t *old_func = RB_ENTRY_VALUE(entry, function_t, entry);
-            size_t old_index = old_func->index;
-            /* global function already exists, replace it */
-            rb_remove(&obj->func_tree, &old_func->entry);
-            func_iter->index = old_index;
-            obj->global_funcs[old_index] = func_iter;
-            rb_put(&obj->func_tree, func_iter->name, &func_iter->entry);
-        }
+        if (existing && existing->type == SCRIPTDISP_FUNC)
+            /* global function already exists, replace it in its slot */
+            func_iter->index = existing->u.func->index;
         else
-        {
-            func_iter->index = obj->global_funcs_cnt;
-            obj->global_funcs[obj->global_funcs_cnt++] = func_iter;
-            rb_put(&obj->func_tree, func_iter->name, &func_iter->entry);
-        }
+            /* a new function, or one re-declaring a variable of the same name */
+            func_iter->index = obj->global_funcs_cnt++;
+
+        obj->global_funcs[func_iter->index] = func_iter;
+        if (!script_disp_add_func(obj, func_iter))
+            return E_OUTOFMEMORY;
     }
 
     if (code->classes)
@@ -244,13 +242,64 @@ static HRESULT retrieve_named_item_disp(IActiveScriptSite *site, named_item_t *i
     return S_OK;
 }
 
+typedef struct {
+    struct rb_entry entry;
+    struct list items;
+} named_item_bucket_t;
+
+static int named_item_bucket_cmp(const void *key, const struct rb_entry *entry)
+{
+    named_item_bucket_t *bucket = RB_ENTRY_VALUE(entry, named_item_bucket_t, entry);
+    named_item_t *item = LIST_ENTRY(list_head(&bucket->items), named_item_t, bucket_entry);
+    return vbs_wcsicmp(key, item->name);
+}
+
+static HRESULT insert_named_item(script_ctx_t *ctx, named_item_t *item)
+{
+    struct rb_entry *entry = rb_get(&ctx->named_item_tree, item->name);
+    named_item_bucket_t *bucket;
+
+    if(entry) {
+        bucket = RB_ENTRY_VALUE(entry, named_item_bucket_t, entry);
+        list_add_tail(&bucket->items, &item->bucket_entry);
+    }else {
+        if(!(bucket = malloc(sizeof(*bucket))))
+            return E_OUTOFMEMORY;
+        list_init(&bucket->items);
+        list_add_tail(&bucket->items, &item->bucket_entry);
+        rb_put(&ctx->named_item_tree, item->name, &bucket->entry);
+    }
+
+    list_add_tail(&ctx->named_items, &item->entry);
+    return S_OK;
+}
+
+static void unlink_named_item(script_ctx_t *ctx, named_item_t *item)
+{
+    struct rb_entry *entry = rb_get(&ctx->named_item_tree, item->name);
+    named_item_bucket_t *bucket = RB_ENTRY_VALUE(entry, named_item_bucket_t, entry);
+
+    list_remove(&item->bucket_entry);
+    if(list_empty(&bucket->items)) {
+        rb_remove(&ctx->named_item_tree, &bucket->entry);
+        free(bucket);
+    }
+    list_remove(&item->entry);
+}
+
 named_item_t *lookup_named_item(script_ctx_t *ctx, const WCHAR *name, unsigned flags)
 {
+    struct rb_entry *entry = rb_get(&ctx->named_item_tree, name);
+    named_item_bucket_t *bucket;
     named_item_t *item;
     HRESULT hres;
 
-    LIST_FOR_EACH_ENTRY(item, &ctx->named_items, named_item_t, entry) {
-        if((item->flags & flags) == flags && !vbs_wcsicmp(item->name, name)) {
+    if(!entry)
+        return NULL;
+
+    bucket = RB_ENTRY_VALUE(entry, named_item_bucket_t, entry);
+    LIST_FOR_EACH_ENTRY(item, &bucket->items, named_item_t, bucket_entry) {
+        if((item->flags & flags) == flags) {
             if(!item->script_obj && !(item->flags & SCRIPTITEM_GLOBALMEMBERS)) {
                 hres = create_script_disp(ctx, &item->script_obj);
                 if(FAILED(hres)) return NULL;
@@ -318,7 +367,7 @@ static void release_script(script_ctx_t *ctx)
         release_named_item_script_obj(item);
         if(!(item->flags & SCRIPTITEM_ISPERSISTENT))
         {
-            list_remove(&item->entry);
+            unlink_named_item(ctx, item);
             release_named_item(item);
         }
     }
@@ -356,7 +405,7 @@ static void release_named_item_list(script_ctx_t *ctx)
 {
     while(!list_empty(&ctx->named_items)) {
         named_item_t *iter = LIST_ENTRY(list_head(&ctx->named_items), named_item_t, entry);
-        list_remove(&iter->entry);
+        unlink_named_item(ctx, iter);
         release_named_item(iter);
     }
 }
@@ -906,7 +955,14 @@ static HRESULT WINAPI VBScript_AddNamedItem(IActiveScript *iface, LPCOLESTR pstr
         return E_OUTOFMEMORY;
     }
 
-    list_add_tail(&This->ctx->named_items, &item->entry);
+    hres = insert_named_item(This->ctx, item);
+    if(FAILED(hres)) {
+        if(disp)
+            IDispatch_Release(disp);
+        free(item->name);
+        free(item);
+        return hres;
+    }
     return S_OK;
 }
 
@@ -1325,6 +1381,7 @@ HRESULT WINAPI VBScriptFactory_CreateInstance(IClassFactory *iface, IUnknown *pU
     list_init(&ctx->objects);
     list_init(&ctx->code_list);
     list_init(&ctx->named_items);
+    rb_init(&ctx->named_item_tree, named_item_bucket_cmp);
 
     hres = init_global(ctx);
     if(FAILED(hres)) {
diff --git a/dlls/vbscript/vbscript.h b/dlls/vbscript/vbscript.h
index 9450851e4a4a..8d8f05e85e7f 100644
--- a/dlls/vbscript/vbscript.h
+++ b/dlls/vbscript/vbscript.h
@@ -119,10 +119,34 @@ typedef struct _dynamic_var_t {
     const WCHAR *name;
     BOOL is_const;
     SAFEARRAY *array;
-    struct rb_entry entry;
     size_t index;
 } dynamic_var_t;
 
+typedef enum {
+    SCRIPTDISP_VAR,
+    SCRIPTDISP_FUNC,
+    SCRIPTDISP_HOSTPROP,
+    SCRIPTDISP_BUILTIN,
+} scriptdisp_entry_type_t;
+
+/* A single named member of a ScriptDisp. A global name resolves to exactly
+   one member, so variables and functions share one tree; the payload selected
+   by type also caches a host property resolved through a named item's
+   dispatch, so a name found on the host is looked up only once. */
+typedef struct {
+    struct rb_entry entry;
+    const WCHAR *name;
+    scriptdisp_entry_type_t type;
+    union {
+        dynamic_var_t *var;
+        function_t *func;
+        struct {
+            IDispatch *disp;
+            DISPID id;
+        } host;
+    } u;
+} scriptdisp_entry_t;
+
 typedef struct {
     IDispatchEx IDispatchEx_iface;
     LONG ref;
@@ -130,12 +154,13 @@ typedef struct {
     dynamic_var_t **global_vars;
     size_t global_vars_cnt;
     size_t global_vars_size;
-    struct rb_tree var_tree;
 
     function_t **global_funcs;
     size_t global_funcs_cnt;
     size_t global_funcs_size;
-    struct rb_tree func_tree;
+
+    /* maps a global name to its scriptdisp_entry_t */
+    struct rb_tree members;
 
     class_desc_t *classes;
 
@@ -145,6 +170,11 @@ typedef struct {
     unsigned int rnd;
 } ScriptDisp;
 
+scriptdisp_entry_t *script_disp_find_member(ScriptDisp *disp, const WCHAR *name);
+scriptdisp_entry_t *script_disp_add_var(ScriptDisp *disp, dynamic_var_t *var);
+scriptdisp_entry_t *script_disp_add_func(ScriptDisp *disp, function_t *func);
+scriptdisp_entry_t *script_disp_add_hostprop(ScriptDisp *disp, const WCHAR *name, IDispatch *disp_obj, DISPID id);
+scriptdisp_entry_t *script_disp_add_builtin(ScriptDisp *disp, const WCHAR *name, IDispatch *disp_obj, DISPID id);
 dynamic_var_t *script_disp_find_var(ScriptDisp *disp, const WCHAR *name);
 
 typedef struct _builtin_prop_t builtin_prop_t;
@@ -165,6 +195,7 @@ typedef struct named_item_t {
     LPWSTR name;
 
     struct list entry;
+    struct list bucket_entry;
 } named_item_t;
 
 HRESULT create_vbdisp(const class_desc_t*,vbdisp_t**);
@@ -232,6 +263,10 @@ struct _script_ctx_t {
     struct list objects;
     struct list code_list;
     struct list named_items;
+
+    /* named items indexed by name, each tree entry listing the items
+       sharing that name in registration order */
+    struct rb_tree named_item_tree;
 };
 
 HRESULT init_global(script_ctx_t*);
@@ -391,7 +426,6 @@ struct _function_t {
     unsigned code_off;
     vbscode_t *code_ctx;
     function_t *next;
-    struct rb_entry entry;
     size_t index;
 };
 
diff --git a/dlls/vcomp/tests/vcomp.c b/dlls/vcomp/tests/vcomp.c
index 3542581a565e..ed4322bb099d 100644
--- a/dlls/vcomp/tests/vcomp.c
+++ b/dlls/vcomp/tests/vcomp.c
@@ -153,7 +153,7 @@ static void  (CDECL   *pomp_unset_nest_lock)(omp_nest_lock_t *lock);
 
 #ifdef __i386__
 #define ARCH "x86"
-#elif defined __aarch64__ || defined__arm64ec__
+#elif defined __aarch64__ || defined __arm64ec__
 #define ARCH "arm64"
 #elif defined(__x86_64__)
 #define ARCH "amd64"
diff --git a/dlls/wbemprox/builtin.c b/dlls/wbemprox/builtin.c
index 9e1036cdc26a..e073c7a78952 100644
--- a/dlls/wbemprox/builtin.c
+++ b/dlls/wbemprox/builtin.c
@@ -4681,15 +4681,23 @@ static struct display_adapter *get_display_adapters( UINT *count )
 
     while(SetupDiEnumDeviceInfo( devs, idx_devinfo++, &dev_info ))
     {
-        WCHAR *driver, *hw_ids;
+        WCHAR *driver, *instance_id;
         UINT key_len;
         WCHAR *key_path;
         HKEY key_instance;
+        DWORD size;
 
-        if (!(driver = get_string_devprop( devs, &dev_info, &DEVPKEY_Device_Driver ))) continue;
-        if (!(hw_ids = get_string_devprop( devs, &dev_info, &DEVPKEY_Device_HardwareIds )))
+        SetupDiGetDeviceInstanceIdW( devs, &dev_info, NULL, 0, &size );
+        if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) continue;
+        if (!(instance_id = malloc( size * sizeof(*instance_id) ))) continue;
+        if (!SetupDiGetDeviceInstanceIdW( devs, &dev_info, instance_id, size, NULL ))
         {
-            free( driver );
+            free( instance_id );
+            continue;
+        }
+        if (!(driver = get_string_devprop( devs, &dev_info, &DEVPKEY_Device_Driver )))
+        {
+            free( instance_id );
             continue;
         }
 
@@ -4697,7 +4705,7 @@ static struct display_adapter *get_display_adapters( UINT *count )
         if (!(key_path = calloc( sizeof(WCHAR), key_len )))
         {
             free( driver );
-            free( hw_ids );
+            free( instance_id );
             continue;
         }
 
@@ -4706,7 +4714,7 @@ static struct display_adapter *get_display_adapters( UINT *count )
 
         if (RegOpenKeyExW( HKEY_LOCAL_MACHINE, key_path, 0, KEY_QUERY_VALUE, &key_instance ))
         {
-            free( hw_ids );
+            free( instance_id );
             free( key_path );
             continue;
         }
@@ -4716,9 +4724,7 @@ static struct display_adapter *get_display_adapters( UINT *count )
         ret[i].driver_date = get_reg_value( key_instance, L"DriverDate" );
         ret[i].driver_desc = get_reg_value( key_instance, L"DriverDesc" );
         ret[i].driver_version = get_reg_value( key_instance, L"DriverVersion" );
-        /* DEVPKEY_Device_HardwareIds is actually an array of null-terminated
-           strings, so consumers will only see the first one. */
-        ret[i].pnpdevice_id = hw_ids;
+        ret[i].pnpdevice_id = instance_id;
         ret[i].dac_type = get_reg_value( key_instance, L"HardwareInformation.DacType" );
         ret[i].memory_size = get_reg_value_dword( key_instance, L"HardwareInformation.MemorySize" );
         if (++i >= nb_allocated)
diff --git a/dlls/wbemprox/main.c b/dlls/wbemprox/main.c
index bc081ce1e348..97f859b09701 100644
--- a/dlls/wbemprox/main.c
+++ b/dlls/wbemprox/main.c
@@ -33,8 +33,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wbemprox);
 
-static HINSTANCE instance;
-
 struct list *table_list[WBEMPROX_NAMESPACE_LAST];
 
 typedef HRESULT (*fnCreateInstance)( LPVOID *ppObj, REFIID riid );
@@ -112,7 +110,6 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
     switch (fdwReason)
     {
     case DLL_PROCESS_ATTACH:
-        instance = hinstDLL;
         DisableThreadLibraryCalls(hinstDLL);
         init_table_list();
         break;
diff --git a/dlls/wbemprox/tests/query.c b/dlls/wbemprox/tests/query.c
index 62532f841ad9..0b3db5662e47 100644
--- a/dlls/wbemprox/tests/query.c
+++ b/dlls/wbemprox/tests/query.c
@@ -1972,6 +1972,7 @@ static void test_Win32_VideoController( IWbemServices *services )
         check_property( obj, L"DriverDate", VT_BSTR, CIM_DATETIME );
         check_property( obj, L"DriverVersion", VT_BSTR, CIM_STRING );
         check_property_nullable( obj, L"InstalledDisplayDrivers", VT_BSTR, CIM_STRING );
+        check_property( obj, L"PNPDeviceID", VT_BSTR, CIM_STRING );
         check_property( obj, L"Status", VT_BSTR, CIM_STRING );
 
         IWbemClassObject_Release( obj );
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c
index c7a78cd327d1..27259fd85063 100644
--- a/dlls/win32u/driver.c
+++ b/dlls/win32u/driver.c
@@ -809,7 +809,7 @@ static BOOL nulldrv_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update )
                         hdc, rect.left - dx, rect.top - dy, SRCCOPY, 0, 0 );
 }
 
-static void nulldrv_SetCapture( HWND hwnd, UINT flags )
+static void nulldrv_SetCapture( HWND hwnd, UINT flags, HWND previous )
 {
 }
 
@@ -879,6 +879,35 @@ static BOOL nulldrv_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp
     return FALSE;
 }
 
+static void nulldrv_surface_destroy( struct client_surface *client )
+{
+}
+
+static void nulldrv_surface_detach( struct client_surface *client )
+{
+}
+
+static void nulldrv_surface_update( struct client_surface *client )
+{
+}
+
+static void nulldrv_surface_present( struct client_surface *client, HDC hdc )
+{
+}
+
+static const struct client_surface_funcs nulldrv_surface_funcs =
+{
+    .destroy = nulldrv_surface_destroy,
+    .detach = nulldrv_surface_detach,
+    .update = nulldrv_surface_update,
+    .present = nulldrv_surface_present,
+};
+
+static struct client_surface *nulldrv_CreateClientSurface( HWND hwnd, int pixel_format )
+{
+    return client_surface_create( sizeof(struct client_surface), &nulldrv_surface_funcs, hwnd );
+}
+
 static BOOL nulldrv_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface )
 {
     return FALSE;
@@ -1302,6 +1331,7 @@ static const struct user_driver_funcs lazy_load_driver =
     nulldrv_WindowPosChanging,
     nulldrv_GetWindowStyleMasks,
     nulldrv_GetWindowStateUpdates,
+    nulldrv_CreateClientSurface,
     nulldrv_CreateWindowSurface,
     nulldrv_MoveWindowBits,
     nulldrv_WindowPosChanged,
@@ -1401,6 +1431,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version
     SET_USER_FUNC(WindowPosChanging);
     SET_USER_FUNC(GetWindowStyleMasks);
     SET_USER_FUNC(GetWindowStateUpdates);
+    SET_USER_FUNC(CreateClientSurface);
     SET_USER_FUNC(CreateWindowSurface);
     SET_USER_FUNC(MoveWindowBits);
     SET_USER_FUNC(WindowPosChanged);
@@ -1439,32 +1470,3 @@ INT WINAPI NtGdiExtEscape( HDC hdc, WCHAR *driver, int driver_id, INT escape, IN
     release_dc_ptr( dc );
     return ret;
 }
-
-static void nulldrv_surface_destroy( struct client_surface *client )
-{
-}
-
-static void nulldrv_surface_detach( struct client_surface *client )
-{
-}
-
-static void nulldrv_surface_update( struct client_surface *client )
-{
-}
-
-static void nulldrv_surface_present( struct client_surface *client, HDC hdc )
-{
-}
-
-static const struct client_surface_funcs nulldrv_surface_funcs =
-{
-    .destroy = nulldrv_surface_destroy,
-    .detach = nulldrv_surface_detach,
-    .update = nulldrv_surface_update,
-    .present = nulldrv_surface_present,
-};
-
-struct client_surface *nulldrv_client_surface_create( HWND hwnd )
-{
-    return client_surface_create( sizeof(struct client_surface), &nulldrv_surface_funcs, hwnd );
-}
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c
index 733eb604fdcc..ce7d0d4de580 100644
--- a/dlls/win32u/input.c
+++ b/dlls/win32u/input.c
@@ -40,6 +40,8 @@
 WINE_DEFAULT_DEBUG_CHANNEL(win);
 WINE_DECLARE_DEBUG_CHANNEL(keyboard);
 
+#define HIMETRIC_PER_INCH 2540
+
 static const WCHAR keyboard_layouts_keyW[] =
 {
     '\\','R','e','g','i','s','t','r','y',
@@ -1918,7 +1920,7 @@ BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
 
     if (ret)
     {
-        user_driver->pSetCapture( hwnd, gui_flags );
+        user_driver->pSetCapture( NtUserGetAncestor( hwnd, GA_ROOT ), gui_flags, NtUserGetAncestor( previous, GA_ROOT ) );
 
         if (previous)
             NtUserNotifyWinEvent( EVENT_SYSTEM_CAPTUREEND, previous, OBJID_WINDOW, 0 );
@@ -2876,3 +2878,36 @@ BOOL WINAPI NtUserInitializeTouchInjection( UINT max_count, UINT mode )
     FIXME( "max_count %u, mode %#x stub!\n", max_count, mode );
     return TRUE;
 }
+
+/**********************************************************************
+ *       NtUserGetPointerType    (win32u.@)
+ */
+BOOL WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type )
+{
+    FIXME( "id %u, type %p stub!\n", id, type );
+    RtlSetLastWin32Error( ERROR_CALL_NOT_IMPLEMENTED );
+    return FALSE;
+}
+
+/**********************************************************************
+ *       NtUserGetPointerDeviceRects    (win32u.@)
+ */
+BOOL WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT *display_rect )
+{
+    RECT rect;
+
+    if (handle != INVALID_HANDLE_VALUE)
+    {
+        FIXME( "Pointer devices are not implemented!\n" );
+        RtlSetLastWin32Error( ERROR_NO_DATA );
+        return FALSE;
+    }
+
+    rect = get_virtual_screen_rect( 0, MDT_DEFAULT );
+    SetRect( device_rect, 0, 0, (rect.right - rect.left) * HIMETRIC_PER_INCH / get_system_dpi(),
+             (rect.bottom - rect.top) * HIMETRIC_PER_INCH / get_system_dpi() );
+    *display_rect = get_virtual_screen_rect( get_thread_dpi(), MDT_DEFAULT );
+
+    TRACE( "returning device %s, display %s\n", wine_dbgstr_rect(device_rect), wine_dbgstr_rect(display_rect) );
+    return TRUE;
+}
diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c
index edb1d98b3f0a..22e5368b132b 100644
--- a/dlls/win32u/main.c
+++ b/dlls/win32u/main.c
@@ -1748,6 +1748,16 @@ BOOL SYSCALL_API NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, U
     SYSCALL_FUNC( NtUserGetPointerInfoList );
 }
 
+BOOL SYSCALL_API NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type )
+{
+    SYSCALL_FUNC( NtUserGetPointerType );
+}
+
+BOOL SYSCALL_API NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT *display_rect )
+{
+    SYSCALL_FUNC( NtUserGetPointerDeviceRects );
+}
+
 INT SYSCALL_API NtUserGetPriorityClipboardFormat( UINT *list, INT count )
 {
     SYSCALL_FUNC( NtUserGetPriorityClipboardFormat );
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h
index 978700a37aaa..dc14811ce865 100644
--- a/dlls/win32u/ntuser_private.h
+++ b/dlls/win32u/ntuser_private.h
@@ -127,6 +127,7 @@ struct user_thread_info
     DWORD                         clipping_reset;         /* time when clipping was last reset */
     struct session_thread_data   *session_data;           /* shared session thread data */
     struct mouse_tracking_info   *mouse_tracking_info;    /* NtUserTrackMouseEvent handling */
+    struct opengl_thread_data    *opengl_data;            /* OpenGL private thread data */
 };
 
 extern struct user_thread_info *get_user_thread_info(void);
diff --git a/dlls/win32u/opengl.c b/dlls/win32u/opengl.c
index 3d03b41fc244..d666705b17b0 100644
--- a/dlls/win32u/opengl.c
+++ b/dlls/win32u/opengl.c
@@ -39,6 +39,21 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(wgl);
 
+struct opengl_thread_data
+{
+    void                   *null_context;  /* dummy context when no client context is active */
+    struct opengl_drawable *null_surface;  /* dummy surface when no client context is active */
+};
+
+static struct opengl_thread_data *get_opengl_thread_data(void)
+{
+    struct user_thread_info *info = get_user_thread_info();
+    struct opengl_thread_data *data;
+
+    if ((data = info->opengl_data)) return data;
+    return (info->opengl_data = calloc( 1, sizeof(*data) ));
+}
+
 struct pbuffer
 {
     struct opengl_drawable *drawable;
@@ -62,6 +77,7 @@ static const struct opengl_driver_funcs nulldrv_funcs, *driver_funcs = &nulldrv_
 static struct list devices_egl = LIST_INIT( devices_egl );
 static struct egl_platform display_egl;
 static struct opengl_funcs display_funcs;
+static void *global_context;
 
 static BOOLEAN global_extensions[GL_EXTENSION_COUNT];
 static struct wgl_pixel_format *pixel_formats;
@@ -156,12 +172,6 @@ void opengl_drawable_release( struct opengl_drawable *drawable )
     }
 }
 
-static void opengl_drawable_set_context( struct opengl_drawable *drawable, struct opengl_context *context )
-{
-    if (!drawable->funcs->set_context) return;
-    drawable->funcs->set_context( drawable, context ? context->driver_private : NULL );
-}
-
 static void opengl_drawable_flush( struct opengl_drawable *drawable, int interval, UINT flags )
 {
     if (!is_client_surface_window( drawable->client, 0 )) return;
@@ -183,6 +193,38 @@ static BOOL opengl_drawable_swap( struct opengl_drawable *drawable )
     return drawable->funcs->swap( drawable );
 }
 
+static BOOL make_null_context_current( struct opengl_drawable *drawable )
+{
+    struct opengl_thread_data *data = get_opengl_thread_data();
+    int format;
+
+    if (!data->null_context)
+    {
+        for (format = 1; format <= formats_count; format++)
+        {
+            struct wgl_pixel_format *desc = pixel_formats + format - 1;
+            if (!(desc->pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue;
+            if (desc->pfd.iPixelType != PFD_TYPE_RGBA) continue;
+            if (desc->pfd.cColorBits < 24) continue;
+            break;
+        }
+
+        if (format > formats_count) return FALSE;
+        driver_funcs->p_context_create( format, global_context, NULL, &data->null_context );
+        if (driver_funcs->p_null_surface_create) driver_funcs->p_null_surface_create( format, &data->null_surface );
+    }
+
+    if (!drawable) drawable = data->null_surface;
+    return driver_funcs->p_make_current( drawable, drawable, data->null_context );
+}
+
+static void make_client_context_current(void)
+{
+    struct opengl_context *context;
+    if (!(context = NtCurrentTeb()->glContext)) return;
+    driver_funcs->p_make_current( context->draw, context->read, context->driver_private );
+}
+
 #ifdef SONAME_LIBEGL
 
 struct framebuffer_surface
@@ -341,7 +383,18 @@ static void destroy_framebuffer( struct opengl_drawable *drawable, const struct
 
 static void framebuffer_surface_destroy( struct opengl_drawable *drawable )
 {
+    struct wgl_pixel_format draw_desc = pixel_formats[drawable->format - 1], read_desc = draw_desc;
+    read_desc.samples = read_desc.sample_buffers = 0;
+
     TRACE( "%s\n", debugstr_opengl_drawable( drawable ) );
+
+    make_null_context_current( NULL );
+
+    if (drawable->draw_fbo != drawable->read_fbo)
+        destroy_framebuffer( drawable, &draw_desc, drawable->draw_fbo );
+    destroy_framebuffer( drawable, &read_desc, drawable->read_fbo );
+
+    make_client_context_current();
 }
 
 static void framebuffer_surface_resize( struct opengl_drawable *drawable )
@@ -349,6 +402,8 @@ static void framebuffer_surface_resize( struct opengl_drawable *drawable )
     struct wgl_pixel_format draw_desc = pixel_formats[drawable->format - 1], read_desc = draw_desc;
     RECT rect;
 
+    make_null_context_current( NULL );
+
     NtUserGetClientRect( drawable->client->hwnd, &rect, NtUserGetDpiForWindow( drawable->client->hwnd ) );
     if (!rect.right) rect.right = 1;
     if (!rect.bottom) rect.bottom = 1;
@@ -363,36 +418,8 @@ static void framebuffer_surface_resize( struct opengl_drawable *drawable )
         TRACE( "Resizing drawable %p/%u to %ux%u\n", drawable, drawable->draw_fbo, rect.right, rect.bottom );
         resize_framebuffer( drawable, &draw_desc, drawable->draw_fbo, rect.right, rect.bottom );
     }
-}
 
-static void framebuffer_surface_set_context( struct opengl_drawable *drawable, void *private )
-{
-    struct wgl_pixel_format draw_desc = pixel_formats[drawable->format - 1], read_desc = draw_desc;
-    read_desc.samples = read_desc.sample_buffers = 0;
-
-    TRACE( "%s, private %p\n", debugstr_opengl_drawable( drawable ), private );
-
-    if (!private)
-    {
-        if (drawable->draw_fbo != drawable->read_fbo)
-        {
-            destroy_framebuffer( drawable, &draw_desc, drawable->draw_fbo );
-            drawable->draw_fbo = 0;
-        }
-        destroy_framebuffer( drawable, &read_desc, drawable->read_fbo );
-        drawable->read_fbo = 0;
-    }
-    else
-    {
-        drawable->read_fbo = create_framebuffer( drawable, &read_desc );
-        if (!drawable->read_fbo) ERR( "Failed to create read framebuffer object\n" );
-
-        if (!draw_desc.sample_buffers) drawable->draw_fbo = drawable->read_fbo;
-        else drawable->draw_fbo = create_framebuffer( drawable, &draw_desc );
-        if (!drawable->draw_fbo) ERR( "Failed to create draw framebuffer object\n" );
-
-        framebuffer_surface_resize( drawable );
-    }
+    make_client_context_current();
 }
 
 static void framebuffer_surface_flush( struct opengl_drawable *drawable, UINT flags )
@@ -412,12 +439,13 @@ static const struct opengl_drawable_funcs framebuffer_surface_funcs =
     .destroy = framebuffer_surface_destroy,
     .flush = framebuffer_surface_flush,
     .swap = framebuffer_surface_swap,
-    .set_context = framebuffer_surface_set_context,
 };
 
 static struct opengl_drawable *framebuffer_surface_create( int format, struct client_surface *client )
 {
+    struct wgl_pixel_format draw_desc = pixel_formats[format - 1], read_desc = draw_desc;
     struct framebuffer_surface *surface;
+
     if (!(surface = opengl_drawable_create( sizeof(*surface), &framebuffer_surface_funcs, format, client ))) return NULL;
 
     opengl_drawable_map_buffer( &surface->base, GL_FRONT_LEFT, GL_COLOR_ATTACHMENT0 );
@@ -438,6 +466,19 @@ static struct opengl_drawable *framebuffer_surface_create( int format, struct cl
         if (surface->base.doublebuffer) opengl_drawable_map_buffer( &surface->base, GL_BACK_RIGHT, GL_COLOR_ATTACHMENT3 );
     }
 
+    make_null_context_current( NULL );
+
+    read_desc.samples = read_desc.sample_buffers = 0;
+    surface->base.read_fbo = create_framebuffer( &surface->base, &read_desc );
+    if (!surface->base.read_fbo) ERR( "Failed to create read framebuffer object\n" );
+
+    if (!draw_desc.sample_buffers) surface->base.draw_fbo = surface->base.read_fbo;
+    else surface->base.draw_fbo = create_framebuffer( &surface->base, &draw_desc );
+    if (!surface->base.draw_fbo) ERR( "Failed to create draw framebuffer object\n" );
+
+    make_client_context_current();
+
+    framebuffer_surface_resize( &surface->base );
     return &surface->base;
 }
 
@@ -660,14 +701,9 @@ static void egldrv_init_extensions( struct opengl_funcs *funcs, BOOLEAN extensio
 {
 }
 
-static BOOL egldrv_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
+static BOOL egldrv_surface_create( struct client_surface *client, int format, struct opengl_drawable **drawable )
 {
-    struct client_surface *client;
-
-    if (!(client = nulldrv_client_surface_create( hwnd ))) return FALSE;
     *drawable = framebuffer_surface_create( format, client );
-    client_surface_release( client );
-
     return !!*drawable;
 }
 
@@ -847,7 +883,8 @@ static BOOL egldrv_make_current( struct opengl_drawable *draw, struct opengl_dra
 
     TRACE( "draw %s, read %s, context %p\n", debugstr_opengl_drawable( draw ), debugstr_opengl_drawable( read ), context );
 
-    return funcs->p_eglMakeCurrent( egl->display, context ? draw->surface : EGL_NO_SURFACE, context ? read->surface : EGL_NO_SURFACE, context );
+    if (!context) return funcs->p_eglMakeCurrent( egl->display, EGL_NO_SURFACE, EGL_NO_SURFACE, NULL );
+    return funcs->p_eglMakeCurrent( egl->display, draw ? draw->surface : EGL_NO_SURFACE, read ? read->surface : EGL_NO_SURFACE, context );
 }
 
 static void egldrv_pbuffer_destroy( struct opengl_drawable *drawable )
@@ -1198,6 +1235,11 @@ static void init_device_info( struct egl_platform *egl, const struct opengl_func
     TRACE( "  - device_uuid: %s\n", debugstr_guid(&egl->device_uuid) );
     TRACE( "  - driver_uuid: %s\n", debugstr_guid(&egl->driver_uuid) );
 
+    if (egl == &display_egl)
+    {
+        if (core_context) core_context = InterlockedExchangePointer( &global_context, core_context );
+        else if (compat_context) compat_context = InterlockedExchangePointer( &global_context, compat_context );
+    }
     if (compat_context) funcs->p_eglDestroyContext( egl->display, compat_context );
     if (core_context) funcs->p_eglDestroyContext( egl->display, core_context );
 
@@ -1276,7 +1318,7 @@ static void nulldrv_init_extensions( struct opengl_funcs *funcs, BOOLEAN extensi
 {
 }
 
-static BOOL nulldrv_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
+static BOOL nulldrv_surface_create( struct client_surface *client, int format, struct opengl_drawable **drawable )
 {
     return TRUE;
 }
@@ -1407,7 +1449,17 @@ static struct opengl_drawable *get_window_unused_drawable( HWND hwnd, int format
      */
     if (!drawable)
     {
-        driver_funcs->p_surface_create( hwnd, format, &drawable );
+        struct client_surface *client;
+
+        if (!(client = user_driver->pCreateClientSurface( hwnd, format )))
+            WARN( "Failed to create a surface for window %p, format %d\n", hwnd, format );
+        else
+        {
+            if (!(driver_funcs->p_surface_create( client, format, &drawable )))
+                WARN( "Failed to create a drawable for window %p, format %d\n", hwnd, format );
+            client_surface_release( client );
+        }
+
         if (drawable && drawable->client) add_window_client_surface( hwnd, drawable->client );
     }
 
@@ -1771,21 +1823,6 @@ static void context_exchange_drawables( struct opengl_context *context, struct o
     *read = old_read;
 }
 
-static BOOL context_unset_current( struct opengl_context *context )
-{
-    struct opengl_drawable *old_draw = context->draw, *old_read = context->read;
-
-    TRACE( "context %p\n", context );
-
-    opengl_drawable_set_context( old_read, NULL );
-    if (old_read != old_draw) opengl_drawable_set_context( old_draw, NULL );
-    if (driver_funcs->p_make_current( NULL, NULL, NULL )) return TRUE;
-    opengl_drawable_set_context( old_read, context );
-    if (old_read != old_draw) opengl_drawable_set_context( old_draw, context );
-
-    return FALSE;
-}
-
 /* return an updated drawable, recreating one if the window drawables have been invalidated (mostly wineandroid) */
 static struct opengl_drawable *get_updated_drawable( HDC hdc, int format, struct opengl_drawable *drawable )
 {
@@ -1831,12 +1868,7 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc
     }
 
     if (previous == context && new_draw == context->draw && new_read == context->read) ret = TRUE;
-    else if (previous)
-    {
-        context_exchange_drawables( previous, &old_draw, &old_read ); /* take ownership of the previous context drawables */
-        opengl_drawable_set_context( old_read, NULL );
-        if (old_read != old_draw) opengl_drawable_set_context( old_draw, NULL );
-    }
+    else if (previous) context_exchange_drawables( previous, &old_draw, &old_read ); /* take ownership of the previous context drawables */
 
     if (!ret && (ret = driver_funcs->p_make_current( new_draw, new_read, context->driver_private )))
     {
@@ -1851,9 +1883,6 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc
         if (old_draw) opengl_drawable_release( old_draw );
         if (old_read) opengl_drawable_release( old_read );
 
-        opengl_drawable_set_context( new_read, context );
-        if (new_read != new_draw) opengl_drawable_set_context( new_draw, context );
-
         opengl_drawable_flush( new_read, new_read->interval, 0 );
         opengl_drawable_flush( new_draw, new_draw->interval, 0 );
     }
@@ -1866,8 +1895,6 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc
     }
     else if (previous)
     {
-        opengl_drawable_set_context( old_read, context );
-        if (old_read != old_draw) opengl_drawable_set_context( old_draw, context );
         context_exchange_drawables( previous, &old_draw, &old_read ); /* give back ownership of the previous drawables */
         assert( !old_draw && !old_read );
     }
@@ -1877,25 +1904,6 @@ static BOOL context_sync_drawables( struct opengl_context *context, HDC draw_hdc
     return ret;
 }
 
-static void push_internal_context( struct opengl_context *context, struct opengl_drawable *drawable, int format )
-{
-    TRACE( "context %p, drawable %s\n", context, debugstr_opengl_drawable( drawable ));
-
-    if (!context->internal_context)
-    {
-        driver_funcs->p_context_create( format, context->driver_private, NULL, &context->internal_context );
-        if (!context->internal_context) ERR( "Failed to create internal context\n" );
-    }
-
-    driver_funcs->p_make_current( drawable, drawable, context->internal_context );
-}
-
-static void pop_internal_context( struct opengl_context *context )
-{
-    TRACE( "context %p\n", context );
-    driver_funcs->p_make_current( context->draw, context->read, context->driver_private );
-}
-
 static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC client_context )
 {
     struct opengl_context *context = opengl_context_from_handle( client_context );
@@ -1909,8 +1917,8 @@ static BOOL win32u_wglMakeContextCurrentARB( HDC draw_hdc, HDC read_hdc, HGLRC c
     {
         struct opengl_drawable *draw = NULL, *read = NULL;
 
+        if (!make_null_context_current( NULL )) return FALSE;
         if (!(context = prev_context)) return TRUE;
-        if (!context_unset_current( context )) return FALSE;
         NtCurrentTeb()->glContext = NULL;
 
         context_exchange_drawables( context, &draw, &read );
@@ -2162,7 +2170,8 @@ static BOOL win32u_wglBindTexImageARB( HPBUFFERARB client_pbuffer, int buffer )
         return ret;
 
     funcs->p_glGetIntegerv( binding_from_target( pbuffer->texture_target ), &prev_texture );
-    push_internal_context( NtCurrentTeb()->glContext, pbuffer->drawable, format );
+
+    make_null_context_current( pbuffer->drawable );
 
     /* Make sure that the prev_texture is set as the current texture state isn't shared
      * between contexts. After that copy the pbuffer texture data. */
@@ -2171,7 +2180,7 @@ static BOOL win32u_wglBindTexImageARB( HPBUFFERARB client_pbuffer, int buffer )
     funcs->p_glCopyTexImage2D( pbuffer->texture_target, 0, pbuffer->texture_format, 0, 0,
                                         pbuffer->width, pbuffer->height, 0 );
 
-    pop_internal_context( NtCurrentTeb()->glContext );
+    make_client_context_current();
     return GL_TRUE;
 }
 
@@ -2263,12 +2272,11 @@ static int get_window_swap_interval( HWND hwnd )
     return interval;
 }
 
-static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, struct opengl_context *share, const int *attribs )
+static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, const int *attribs )
 {
-    void *share_private = share ? share->driver_private : NULL;
     int format;
 
-    TRACE( "context %p, hdc %p, share %p, attribs %p\n", context, hdc, share, attribs );
+    TRACE( "context %p, hdc %p, attribs %p\n", context, hdc, attribs );
 
     if ((format = get_dc_pixel_format( hdc )) <= 0 &&
         (format = get_window_pixel_format( NtUserWindowFromDC( hdc ) )) <= 0)
@@ -2277,7 +2285,7 @@ static BOOL win32u_context_create( struct opengl_context *context, HDC hdc, stru
         else RtlSetLastWin32Error( ERROR_INVALID_HANDLE );
         return FALSE;
     }
-    if (!driver_funcs->p_context_create( format, share_private, attribs, &context->driver_private ))
+    if (!driver_funcs->p_context_create( format, global_context, attribs, &context->driver_private ))
     {
         WARN( "Failed to create driver context for context %p\n", context );
         return FALSE;
@@ -2292,11 +2300,6 @@ static BOOL win32u_context_destroy( struct opengl_context *context )
 {
     TRACE( "context %p\n", context );
 
-    if (context->internal_context)
-    {
-        driver_funcs->p_context_destroy( context->internal_context );
-        context->internal_context = NULL;
-    }
     if (context->driver_private && !driver_funcs->p_context_destroy( context->driver_private ))
     {
         WARN( "Failed to destroy driver context %p\n", context->driver_private );
@@ -2307,16 +2310,6 @@ static BOOL win32u_context_destroy( struct opengl_context *context )
     return TRUE;
 }
 
-static BOOL win32u_context_reset( struct opengl_context *context, struct opengl_context *share, const int *attribs )
-{
-    void *share_private = share ? share->driver_private : NULL;
-
-    TRACE( "context %p, share %p, attribs %p\n", context, share, attribs );
-
-    if (!win32u_context_destroy( context )) return FALSE;
-    return driver_funcs->p_context_create( context->format, share_private, attribs, &context->driver_private );
-}
-
 static BOOL flush_memory_pbuffer( void (*flush)(void) )
 {
     HDC draw_hdc = NtCurrentTeb()->glReserved1[0], read_hdc = NtCurrentTeb()->glReserved1[1];
@@ -2713,7 +2706,6 @@ static void display_funcs_init(void)
     display_funcs.p_context_flush = win32u_context_flush;
     display_funcs.p_context_create = win32u_context_create;
     display_funcs.p_context_destroy = win32u_context_destroy;
-    display_funcs.p_context_reset = win32u_context_reset;
 
     global_extensions[WGL_ARB_multisample] = 1;
 
@@ -2789,6 +2781,18 @@ static void display_funcs_init(void)
         LIST_FOR_EACH_ENTRY_SAFE( egl, next, &devices_egl, struct egl_platform, entry )
             init_device_info( egl, &display_funcs );
     }
+
+    if (!global_context)
+    {
+        for (int format = 1; format <= formats_count; format++)
+        {
+            struct wgl_pixel_format *desc = pixel_formats + format - 1;
+            if (!(desc->pfd.dwFlags & PFD_SUPPORT_OPENGL)) continue;
+            if (desc->pfd.iPixelType != PFD_TYPE_RGBA) continue;
+            if (desc->pfd.cColorBits < 24) continue;
+            if (driver_funcs->p_context_create( format, NULL, NULL, &global_context )) break;
+        }
+    }
 }
 
 /***********************************************************************
@@ -2830,3 +2834,27 @@ BOOL get_opengl_gpus( struct list *gpus )
 
     return TRUE;
 }
+
+void cleanup_opengl_thread(void)
+{
+    struct opengl_context *context = NtCurrentTeb()->glContext;
+    struct user_thread_info *info = get_user_thread_info();
+    struct opengl_thread_data *data;
+
+    /* unset current context, this is sometimes missing from host drivers and leaks memory */
+    if (driver_funcs->p_make_current( NULL, NULL, NULL ) && context)
+    {
+        struct opengl_drawable *draw = NULL, *read = NULL;
+
+        context_exchange_drawables( context, &draw, &read );
+        if (draw->client) set_window_opengl_drawable( draw->client->hwnd, draw, FALSE );
+        opengl_drawable_release( draw );
+        if (read->client) set_window_opengl_drawable( read->client->hwnd, read, FALSE );
+        opengl_drawable_release( read );
+    }
+
+    if (!(data = info->opengl_data)) return;
+    if (data->null_context) driver_funcs->p_context_destroy( data->null_context );
+    if (data->null_surface) opengl_drawable_release( data->null_surface );
+    free( data );
+}
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c
index f0cff127b26c..239d13df6cc9 100644
--- a/dlls/win32u/sysparams.c
+++ b/dlls/win32u/sysparams.c
@@ -7467,6 +7467,7 @@ static void thread_detach(void)
     free( thread_info->rawinput );
 
     cleanup_imm_thread();
+    cleanup_opengl_thread();
     NtClose( thread_info->server_queue );
     if (thread_info->idle_event) NtClose( thread_info->idle_event );
     free( thread_info->session_data );
diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c
index 4481ffa1b320..a67b918626d1 100644
--- a/dlls/win32u/tests/win32u.c
+++ b/dlls/win32u/tests/win32u.c
@@ -3004,6 +3004,56 @@ static void test_NtUserRegisterWindowMessage(void)
     ok( !wcscmp( buf, L"#0xabc" ), "buf = %s\n", debugstr_w(buf) );
 }
 
+static BOOL CALLBACK get_virtual_screen_proc( HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM lp )
+{
+    RECT *virtual_rect = (RECT *)lp;
+    UnionRect( virtual_rect, virtual_rect, rect );
+    return TRUE;
+}
+
+static RECT get_virtual_screen_rect(void)
+{
+    RECT rect = {0};
+    EnumDisplayMonitors( 0, NULL, get_virtual_screen_proc, (LPARAM)&rect );
+    return rect;
+}
+
+void test_NtUserGetPointerDeviceRects( const char *arg )
+{
+    RECT screen, himetric_dev = {0}, device = {0}, display = {0};
+    DPI_AWARENESS_CONTEXT ctx = 0;
+    const UINT himetric = 2540;
+    UINT ret, dpi;
+
+    if (!strcmp( arg, "unaware" )) ctx = DPI_AWARENESS_CONTEXT_UNAWARE;
+    else if (!strcmp( arg, "system" )) ctx = DPI_AWARENESS_CONTEXT_SYSTEM_AWARE;
+    else if (!strcmp( arg, "monitor" )) ctx = DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE;
+
+    if (ctx)
+    {
+        ret = SetProcessDpiAwarenessContext( ctx );
+        ok( ret, "SetProcessDpiAwarenessContext failed, error %lu.\n", GetLastError() );
+    }
+
+    screen = get_virtual_screen_rect();
+
+    /* operating on unaware scaled values returns wrong values */
+    ctx = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_SYSTEM_AWARE );
+
+    dpi = GetDpiForSystem();
+    himetric_dev.right = GetSystemMetrics( SM_CXVIRTUALSCREEN ) * himetric / dpi;
+    himetric_dev.bottom = GetSystemMetrics( SM_CYVIRTUALSCREEN ) * himetric / dpi;
+
+    SetThreadDpiAwarenessContext( ctx );
+
+    ret = NtUserGetPointerDeviceRects( INVALID_HANDLE_VALUE, &device, &display );
+    ok( ret, "NtUserGetPointerDeviceRects failed, error %lu.\n", GetLastError() );
+    ok( EqualRect( &device, &himetric_dev ), "device %s, expected %s\n",
+        wine_dbgstr_rect( &device ), wine_dbgstr_rect( &himetric_dev ) );
+    ok( EqualRect( &display, &screen ), "display %s, expected %s\n",
+        wine_dbgstr_rect( &display ), wine_dbgstr_rect( &screen ) );
+}
+
 START_TEST(win32u)
 {
     char **argv;
@@ -3033,6 +3083,14 @@ START_TEST(win32u)
         return;
     }
 
+    if (argc > 3 && !strcmp( argv[2], "NtUserGetPointerDeviceRects" ))
+    {
+        winetest_push_context( "dpi context %s", argv[3] );
+        test_NtUserGetPointerDeviceRects( argv[3] );
+        winetest_pop_context();
+        return;
+    }
+
     test_NtUserEnumDisplayDevices();
     test_window_props();
     test_class();
@@ -3059,6 +3117,10 @@ START_TEST(win32u)
     run_in_process( argv, "NtUserEnableMouseInPointer 0" );
     run_in_process( argv, "NtUserEnableMouseInPointer 1" );
 
+    run_in_process( argv, "NtUserGetPointerDeviceRects unaware" );
+    run_in_process( argv, "NtUserGetPointerDeviceRects system" );
+    run_in_process( argv, "NtUserGetPointerDeviceRects monitor" );
+
     run_in_process( argv, "NtUserSetProcessDpiAwarenessContext 0x6010" );
     run_in_process( argv, "NtUserSetProcessDpiAwarenessContext 0x11" );
     run_in_process( argv, "NtUserSetProcessDpiAwarenessContext 0x12" );
diff --git a/dlls/win32u/vulkan.c b/dlls/win32u/vulkan.c
index bf8f6f1daba4..310ce8923c95 100644
--- a/dlls/win32u/vulkan.c
+++ b/dlls/win32u/vulkan.c
@@ -1533,8 +1533,11 @@ static VkResult win32u_vkCreateWin32SurfaceKHR( VkInstance client_instance, cons
         surface->hwnd = dummy;
     }
 
-    if ((res = driver_funcs->p_vulkan_surface_create( surface->hwnd, instance, &host_surface, &surface->client )))
+    if (!(surface->client = user_driver->pCreateClientSurface( surface->hwnd, 0 ))) res = VK_ERROR_OUT_OF_HOST_MEMORY;
+    else res = driver_funcs->p_vulkan_surface_create( surface->client, instance, &host_surface );
+    if (res)
     {
+        if (surface->client) client_surface_release( surface->client );
         if (dummy) NtUserDestroyWindow( dummy );
         free( surface );
         return res;
@@ -2193,9 +2196,18 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons
             switch ((*next)->sType)
             {
             case VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR:
-                FIXME( "VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR not implemented!\n" );
+            {
+                VkD3D12FenceSubmitInfoKHR *info = (VkD3D12FenceSubmitInfoKHR *)*next;
+
+                if (timeline->sType) ERR( "Duplicated timeline sync info.\n" );
+                timeline->sType = info->sType;
+                timeline->waitSemaphoreValueCount = info->waitSemaphoreValuesCount;
+                timeline->pWaitSemaphoreValues = info->pWaitSemaphoreValues;
+                timeline->signalSemaphoreValueCount = info->signalSemaphoreValuesCount;
+                timeline->pSignalSemaphoreValues = info->pSignalSemaphoreValues;
                 *next = (*next)->pNext; next = &prev;
                 break;
+            }
             case VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO:
                 device_group = (VkDeviceGroupSubmitInfo *)*next;
                 break;
@@ -2205,7 +2217,7 @@ static VkResult win32u_vkQueueSubmit( VkQueue client_queue, uint32_t count, cons
             case VK_STRUCTURE_TYPE_PERFORMANCE_QUERY_SUBMIT_INFO_KHR: break;
             case VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO: break;
             case VK_STRUCTURE_TYPE_TIMELINE_SEMAPHORE_SUBMIT_INFO:
-                if (timeline->sType) ERR( "Duplicated timeline semaphore submit info!\n" );
+                if (timeline->sType) ERR( "Duplicated timeline sync info.\n" );
                 *timeline = *(VkTimelineSemaphoreSubmitInfo *)*next;
                 *next = (*next)->pNext; next = &prev; /* remove it from the chain, we'll add it back below */
                 break;
@@ -2547,6 +2559,7 @@ static VkResult win32u_vkImportSemaphoreWin32HandleKHR( VkDevice client_device,
     VkImportSemaphoreFdInfoKHR fd_info = {.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR};
     struct vulkan_device *device = vulkan_device_from_handle( client_device );
     struct semaphore *semaphore = semaphore_from_handle( handle_info->semaphore );
+    struct vulkan_instance *instance = device->physical_device->instance;
     D3DKMT_HANDLE local, global = 0;
     VkResult res = VK_SUCCESS;
     HANDLE shared = NULL;
@@ -2579,7 +2592,35 @@ static VkResult win32u_vkImportSemaphoreWin32HandleKHR( VkDevice client_device,
     }
 
     if ((fd_info.fd = d3dkmt_object_get_fd( local )) < 0) res = VK_ERROR_INVALID_EXTERNAL_HANDLE;
-    else
+    if (!res && handle_info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT)
+    {
+        /* Recreate semaphore to make sure it has timeline type. */
+        VkSemaphoreTypeCreateInfo type_info =
+        {
+            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_TYPE_CREATE_INFO,
+            .semaphoreType = VK_SEMAPHORE_TYPE_TIMELINE,
+        };
+        VkSemaphoreCreateInfo create_info =
+        {
+            .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO,
+            .pNext = &type_info,
+        };
+        VkSemaphore new_semaphore;
+
+        if ((res = device->p_vkCreateSemaphore( device->host.device, &create_info, NULL, &new_semaphore )))
+        {
+            ERR( "Failed to create timeline semaphore, vr %d.\n", res );
+        }
+        else
+        {
+            instance->p_remove_object( instance, &semaphore->obj.obj );
+            device->p_vkDestroySemaphore( device->host.device, semaphore->obj.host.semaphore, NULL );
+            vulkan_object_init( &semaphore->obj.obj, new_semaphore );
+            instance->p_insert_object( instance, &semaphore->obj.obj );
+        }
+    }
+
+    if (!res)
     {
         fd_info.handleType = get_host_external_semaphore_type();
         fd_info.semaphore = semaphore->obj.host.semaphore;
@@ -2924,20 +2965,10 @@ static struct vulkan_funcs vulkan_funcs =
     .p_vkUnmapMemory2KHR = win32u_vkUnmapMemory2KHR,
 };
 
-static VkResult nulldrv_vulkan_surface_create( HWND hwnd, const struct vulkan_instance *instance, VkSurfaceKHR *surface,
-                                               struct client_surface **client )
+static VkResult nulldrv_vulkan_surface_create( struct client_surface *client, const struct vulkan_instance *instance, VkSurfaceKHR *surface )
 {
     VkHeadlessSurfaceCreateInfoEXT create_info = {.sType = VK_STRUCTURE_TYPE_HEADLESS_SURFACE_CREATE_INFO_EXT};
-    VkResult res;
-
-    if (!(*client = nulldrv_client_surface_create( hwnd ))) return VK_ERROR_OUT_OF_HOST_MEMORY;
-    if ((res = instance->p_vkCreateHeadlessSurfaceEXT( instance->host.instance, &create_info, NULL, surface )))
-    {
-        client_surface_release(*client);
-        *client = NULL;
-    }
-
-    return res;
+    return instance->p_vkCreateHeadlessSurfaceEXT( instance->host.instance, &create_info, NULL, surface );
 }
 
 static VkBool32 nulldrv_get_physical_device_presentation_support( struct vulkan_physical_device *physical_device, uint32_t queue )
@@ -2989,11 +3020,10 @@ static void vulkan_driver_load(void)
     pthread_once( &init_once, vulkan_driver_init );
 }
 
-static VkResult lazydrv_vulkan_surface_create( HWND hwnd, const struct vulkan_instance *instance, VkSurfaceKHR *surface,
-                                               struct client_surface **client )
+static VkResult lazydrv_vulkan_surface_create( struct client_surface *client, const struct vulkan_instance *instance, VkSurfaceKHR *surface )
 {
     vulkan_driver_load();
-    return driver_funcs->p_vulkan_surface_create( hwnd, instance, surface, client );
+    return driver_funcs->p_vulkan_surface_create( client, instance, surface );
 }
 
 static VkBool32 lazydrv_get_physical_device_presentation_support( struct vulkan_physical_device *physical_device, uint32_t queue )
diff --git a/dlls/win32u/win32syscalls.h b/dlls/win32u/win32syscalls.h
index 3e631c74da1e..132ac47836bf 100644
--- a/dlls/win32u/win32syscalls.h
+++ b/dlls/win32u/win32syscalls.h
@@ -1068,13 +1068,13 @@
     SYSCALL_ENTRY( 0x1428, NtUserGetPointerDeviceInputSpace, 0 ) \
     SYSCALL_ENTRY( 0x1429, NtUserGetPointerDeviceOrientation, 0 ) \
     SYSCALL_ENTRY( 0x142a, NtUserGetPointerDeviceProperties, 0 ) \
-    SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 0 ) \
+    SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 12 ) \
     SYSCALL_ENTRY( 0x142c, NtUserGetPointerDevices, 0 ) \
     SYSCALL_ENTRY( 0x142d, NtUserGetPointerFrameTimes, 0 ) \
     SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 32 ) \
     SYSCALL_ENTRY( 0x142f, NtUserGetPointerInputTransform, 0 ) \
     SYSCALL_ENTRY( 0x1430, NtUserGetPointerProprietaryId, 0 ) \
-    SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 0 ) \
+    SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 8 ) \
     SYSCALL_ENTRY( 0x1432, NtUserGetPrecisionTouchPadConfiguration, 0 ) \
     SYSCALL_ENTRY( 0x1433, NtUserGetPriorityClipboardFormat, 8 ) \
     SYSCALL_ENTRY( 0x1434, NtUserGetProcessDefaultLayout, 4 ) \
@@ -2610,13 +2610,13 @@
     SYSCALL_ENTRY( 0x1428, NtUserGetPointerDeviceInputSpace, 0 ) \
     SYSCALL_ENTRY( 0x1429, NtUserGetPointerDeviceOrientation, 0 ) \
     SYSCALL_ENTRY( 0x142a, NtUserGetPointerDeviceProperties, 0 ) \
-    SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 0 ) \
+    SYSCALL_ENTRY( 0x142b, NtUserGetPointerDeviceRects, 24 ) \
     SYSCALL_ENTRY( 0x142c, NtUserGetPointerDevices, 0 ) \
     SYSCALL_ENTRY( 0x142d, NtUserGetPointerFrameTimes, 0 ) \
     SYSCALL_ENTRY( 0x142e, NtUserGetPointerInfoList, 64 ) \
     SYSCALL_ENTRY( 0x142f, NtUserGetPointerInputTransform, 0 ) \
     SYSCALL_ENTRY( 0x1430, NtUserGetPointerProprietaryId, 0 ) \
-    SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 0 ) \
+    SYSCALL_ENTRY( 0x1431, NtUserGetPointerType, 16 ) \
     SYSCALL_ENTRY( 0x1432, NtUserGetPrecisionTouchPadConfiguration, 0 ) \
     SYSCALL_ENTRY( 0x1433, NtUserGetPriorityClipboardFormat, 16 ) \
     SYSCALL_ENTRY( 0x1434, NtUserGetProcessDefaultLayout, 8 ) \
@@ -3831,12 +3831,10 @@
     SYSCALL_STUB( NtUserGetPointerDeviceInputSpace ) \
     SYSCALL_STUB( NtUserGetPointerDeviceOrientation ) \
     SYSCALL_STUB( NtUserGetPointerDeviceProperties ) \
-    SYSCALL_STUB( NtUserGetPointerDeviceRects ) \
     SYSCALL_STUB( NtUserGetPointerDevices ) \
     SYSCALL_STUB( NtUserGetPointerFrameTimes ) \
     SYSCALL_STUB( NtUserGetPointerInputTransform ) \
     SYSCALL_STUB( NtUserGetPointerProprietaryId ) \
-    SYSCALL_STUB( NtUserGetPointerType ) \
     SYSCALL_STUB( NtUserGetPrecisionTouchPadConfiguration ) \
     SYSCALL_STUB( NtUserGetProcessUIContextInformation ) \
     SYSCALL_STUB( NtUserGetProp2 ) \
diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec
index a58fda6af9c2..2c409010cd21 100644
--- a/dlls/win32u/win32u.spec
+++ b/dlls/win32u/win32u.spec
@@ -1066,13 +1066,13 @@
 @ stub -syscall NtUserGetPointerDeviceInputSpace
 @ stub -syscall NtUserGetPointerDeviceOrientation
 @ stub -syscall NtUserGetPointerDeviceProperties
-@ stub -syscall NtUserGetPointerDeviceRects
+@ stdcall -syscall NtUserGetPointerDeviceRects(long ptr ptr)
 @ stub -syscall NtUserGetPointerDevices
 @ stub -syscall NtUserGetPointerFrameTimes
 @ stdcall -syscall NtUserGetPointerInfoList(long long long long long ptr ptr ptr)
 @ stub -syscall NtUserGetPointerInputTransform
 @ stub -syscall NtUserGetPointerProprietaryId
-@ stub -syscall NtUserGetPointerType
+@ stdcall -syscall NtUserGetPointerType(long ptr)
 @ stub -syscall NtUserGetPrecisionTouchPadConfiguration
 @ stdcall -syscall NtUserGetPriorityClipboardFormat(ptr long)
 @ stdcall -syscall NtUserGetProcessDefaultLayout(ptr)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h
index be303ae4d131..c217aa9ead6c 100644
--- a/dlls/win32u/win32u_private.h
+++ b/dlls/win32u/win32u_private.h
@@ -229,6 +229,7 @@ extern NTSTATUS d3dkmt_destroy_sync( D3DKMT_HANDLE local );
 /* opengl.c */
 
 extern BOOL get_opengl_gpus( struct list *gpus );
+extern void cleanup_opengl_thread(void);
 
 /* winstation.c */
 
@@ -354,7 +355,6 @@ extern HKEY hkcu_key;
 
 /* driver.c */
 extern const struct user_driver_funcs *user_driver;
-extern struct client_surface *nulldrv_client_surface_create( HWND hwnd );
 
 extern ULONG_PTR zero_bits;
 
diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c
index c3a32dde6cf2..f4dc335c5cf3 100644
--- a/dlls/win32u/window.c
+++ b/dlls/win32u/window.c
@@ -2383,7 +2383,7 @@ static BOOL expose_window_surface( HWND hwnd, UINT flags, const RECT *rect, UINT
         add_bounds_rect( &surface->bounds, &exposed_rect );
     }
     window_surface_unlock( surface );
-    if (surface->alpha_mask) window_surface_flush( surface );
+    window_surface_flush( surface );
     window_surface_release( surface );
     return TRUE;
 }
@@ -5264,6 +5264,8 @@ LRESULT destroy_window( HWND hwnd )
 
     send_message( hwnd, WM_NCDESTROY, 0, 0 );
 
+    if (hwnd == get_capture()) user_driver->pSetCapture( NULL, 0, toplevel );
+
     if (toplevel && toplevel != hwnd) update_window_state( toplevel );
 
     /* FIXME: do we need to fake QS_MOUSEMOVE wakebit? */
@@ -5403,6 +5405,7 @@ void destroy_thread_windows(void)
         struct window_surface *surface;
         struct destroy_entry *next;
     } *entry, *free_list = NULL;
+    HWND capture = get_capture(), toplevel = NtUserGetAncestor( capture, GA_ROOT );
     struct list drawables = LIST_INIT(drawables);
     HANDLE handle = 0;
     WND *win;
@@ -5452,6 +5455,8 @@ void destroy_thread_windows(void)
         free_list = entry->next;
         TRACE( "destroying %p\n", entry );
 
+        if (entry->handle == capture) user_driver->pSetCapture( NULL, 0, toplevel );
+
         detach_client_surfaces( entry->handle );
         user_driver->pDestroyWindow( entry->handle );
         if (entry->current_drawable) opengl_drawable_release( entry->current_drawable );
diff --git a/dlls/windowscodecs/gifformat.c b/dlls/windowscodecs/gifformat.c
index 287a49f83e9c..7672b9c80d09 100644
--- a/dlls/windowscodecs/gifformat.c
+++ b/dlls/windowscodecs/gifformat.c
@@ -37,6 +37,7 @@ struct gif_decoder
 {
     struct decoder decoder;
     GifFileType *gif;
+    IStream *stream;  /* kept to allow on-demand frame decoding */
 };
 
 static inline struct gif_decoder *impl_from_decoder(struct decoder *iface)
@@ -646,6 +647,13 @@ static int _gif_inputfunc(GifFileType *gif, GifByteType *data, int len) {
     return bytesread;
 }
 
+static void gif_seek_stream(GifFileType *gif, int offset)
+{
+    LARGE_INTEGER seek;
+    seek.QuadPart = offset;
+    IStream_Seek((IStream *)gif->UserData, seek, STREAM_SEEK_SET, NULL);
+}
+
 static HRESULT CDECL gif_decoder_initialize(struct decoder *iface, IStream *stream, struct decoder_stat *st)
 {
     struct gif_decoder *decoder = impl_from_decoder(iface);
@@ -656,17 +664,31 @@ static HRESULT CDECL gif_decoder_initialize(struct decoder *iface, IStream *stre
     seek.QuadPart = 0;
     IStream_Seek(stream, seek, STREAM_SEEK_SET, NULL);
 
+    /* keep stream for on-demand frame decoding */
+    IStream_AddRef(stream);
+    decoder->stream = stream;
+
     /* read all data from the stream */
     decoder->gif = DGifOpen((void *)stream, _gif_inputfunc);
     if (!decoder->gif)
+    {
+        IStream_Release(stream);
+        decoder->stream = NULL;
         return E_FAIL;
+    }
+
+    /* Set up seek function for on-demand frame decoding */
+    decoder->gif->seekFunc = gif_seek_stream;
 
-    ret = DGifSlurp(decoder->gif);
+    /* Only scan frame headers, skip pixel data for on-demand decoding */
+    ret = DGifSlurpHeaders(decoder->gif);
     if (ret == GIF_ERROR)
+    {
+        DGifCloseFile(decoder->gif);
+        IStream_Release(stream);
+        decoder->stream = NULL;
         return E_FAIL;
-
-    /* make sure we don't use the stream after this method returns */
-    decoder->gif->UserData = NULL;
+    }
 
     st->flags = WICBitmapDecoderCapabilityCanDecodeAllImages |
                 WICBitmapDecoderCapabilityCanDecodeSomeImages |
@@ -759,6 +781,14 @@ static HRESULT CDECL gif_decoder_copy_pixels(struct decoder *iface, UINT frame,
 
     image = &decoder->gif->SavedImages[frame];
 
+    /* Decode this frame's pixel data on demand */
+    if (!image->RasterBits)
+    {
+        decoder->gif->UserData = (void *)decoder->stream;
+        if (DGifDecodeFrame(decoder->gif, frame) == GIF_ERROR)
+            return E_FAIL;
+    }
+
     if (image->ImageDesc.Interlace)
         return copy_interlaced_pixels(image->RasterBits, image->ImageDesc.Width,
                 image->ImageDesc.Height, image->ImageDesc.Width, prc, stride, buffersize, buffer);
@@ -871,6 +901,8 @@ static void CDECL gif_decoder_destroy(struct decoder *iface)
 {
     struct gif_decoder *decoder = impl_from_decoder(iface);
 
+    if (decoder->stream)
+        IStream_Release(decoder->stream);
     DGifCloseFile(decoder->gif);
     free(decoder);
 }
diff --git a/dlls/windowscodecs/tests/gifformat.c b/dlls/windowscodecs/tests/gifformat.c
index 08f8ba1c12bc..2be0e75da744 100644
--- a/dlls/windowscodecs/tests/gifformat.c
+++ b/dlls/windowscodecs/tests/gifformat.c
@@ -632,6 +632,457 @@ static void test_gif_notrailer(void)
     IWICImagingFactory_Release(factory);
 }
 
+/* GIF whose single frame's LZW stream fills the 4096-entry code table and then
+ * references the last code (the "deferred clear code" case). The decoder must keep
+ * the full table intact; a buggy decoder that overwrites entry LZ_MAX_CODE corrupts
+ * the table and fails to decode the frame. */
+static const BYTE gif_full_table[] = {
+    0x47,0x49,0x46,0x38,0x39,0x61,0x40,0x00,0x40,0x00,0x87,0x00,0x00,0x00,0x00,0x00,
+    0x01,0x01,0x01,0x02,0x02,0x02,0x03,0x03,0x03,0x04,0x04,0x04,0x05,0x05,0x05,0x06,
+    0x06,0x06,0x07,0x07,0x07,0x08,0x08,0x08,0x09,0x09,0x09,0x0a,0x0a,0x0a,0x0b,0x0b,
+    0x0b,0x0c,0x0c,0x0c,0x0d,0x0d,0x0d,0x0e,0x0e,0x0e,0x0f,0x0f,0x0f,0x10,0x10,0x10,
+    0x11,0x11,0x11,0x12,0x12,0x12,0x13,0x13,0x13,0x14,0x14,0x14,0x15,0x15,0x15,0x16,
+    0x16,0x16,0x17,0x17,0x17,0x18,0x18,0x18,0x19,0x19,0x19,0x1a,0x1a,0x1a,0x1b,0x1b,
+    0x1b,0x1c,0x1c,0x1c,0x1d,0x1d,0x1d,0x1e,0x1e,0x1e,0x1f,0x1f,0x1f,0x20,0x20,0x20,
+    0x21,0x21,0x21,0x22,0x22,0x22,0x23,0x23,0x23,0x24,0x24,0x24,0x25,0x25,0x25,0x26,
+    0x26,0x26,0x27,0x27,0x27,0x28,0x28,0x28,0x29,0x29,0x29,0x2a,0x2a,0x2a,0x2b,0x2b,
+    0x2b,0x2c,0x2c,0x2c,0x2d,0x2d,0x2d,0x2e,0x2e,0x2e,0x2f,0x2f,0x2f,0x30,0x30,0x30,
+    0x31,0x31,0x31,0x32,0x32,0x32,0x33,0x33,0x33,0x34,0x34,0x34,0x35,0x35,0x35,0x36,
+    0x36,0x36,0x37,0x37,0x37,0x38,0x38,0x38,0x39,0x39,0x39,0x3a,0x3a,0x3a,0x3b,0x3b,
+    0x3b,0x3c,0x3c,0x3c,0x3d,0x3d,0x3d,0x3e,0x3e,0x3e,0x3f,0x3f,0x3f,0x40,0x40,0x40,
+    0x41,0x41,0x41,0x42,0x42,0x42,0x43,0x43,0x43,0x44,0x44,0x44,0x45,0x45,0x45,0x46,
+    0x46,0x46,0x47,0x47,0x47,0x48,0x48,0x48,0x49,0x49,0x49,0x4a,0x4a,0x4a,0x4b,0x4b,
+    0x4b,0x4c,0x4c,0x4c,0x4d,0x4d,0x4d,0x4e,0x4e,0x4e,0x4f,0x4f,0x4f,0x50,0x50,0x50,
+    0x51,0x51,0x51,0x52,0x52,0x52,0x53,0x53,0x53,0x54,0x54,0x54,0x55,0x55,0x55,0x56,
+    0x56,0x56,0x57,0x57,0x57,0x58,0x58,0x58,0x59,0x59,0x59,0x5a,0x5a,0x5a,0x5b,0x5b,
+    0x5b,0x5c,0x5c,0x5c,0x5d,0x5d,0x5d,0x5e,0x5e,0x5e,0x5f,0x5f,0x5f,0x60,0x60,0x60,
+    0x61,0x61,0x61,0x62,0x62,0x62,0x63,0x63,0x63,0x64,0x64,0x64,0x65,0x65,0x65,0x66,
+    0x66,0x66,0x67,0x67,0x67,0x68,0x68,0x68,0x69,0x69,0x69,0x6a,0x6a,0x6a,0x6b,0x6b,
+    0x6b,0x6c,0x6c,0x6c,0x6d,0x6d,0x6d,0x6e,0x6e,0x6e,0x6f,0x6f,0x6f,0x70,0x70,0x70,
+    0x71,0x71,0x71,0x72,0x72,0x72,0x73,0x73,0x73,0x74,0x74,0x74,0x75,0x75,0x75,0x76,
+    0x76,0x76,0x77,0x77,0x77,0x78,0x78,0x78,0x79,0x79,0x79,0x7a,0x7a,0x7a,0x7b,0x7b,
+    0x7b,0x7c,0x7c,0x7c,0x7d,0x7d,0x7d,0x7e,0x7e,0x7e,0x7f,0x7f,0x7f,0x80,0x80,0x80,
+    0x81,0x81,0x81,0x82,0x82,0x82,0x83,0x83,0x83,0x84,0x84,0x84,0x85,0x85,0x85,0x86,
+    0x86,0x86,0x87,0x87,0x87,0x88,0x88,0x88,0x89,0x89,0x89,0x8a,0x8a,0x8a,0x8b,0x8b,
+    0x8b,0x8c,0x8c,0x8c,0x8d,0x8d,0x8d,0x8e,0x8e,0x8e,0x8f,0x8f,0x8f,0x90,0x90,0x90,
+    0x91,0x91,0x91,0x92,0x92,0x92,0x93,0x93,0x93,0x94,0x94,0x94,0x95,0x95,0x95,0x96,
+    0x96,0x96,0x97,0x97,0x97,0x98,0x98,0x98,0x99,0x99,0x99,0x9a,0x9a,0x9a,0x9b,0x9b,
+    0x9b,0x9c,0x9c,0x9c,0x9d,0x9d,0x9d,0x9e,0x9e,0x9e,0x9f,0x9f,0x9f,0xa0,0xa0,0xa0,
+    0xa1,0xa1,0xa1,0xa2,0xa2,0xa2,0xa3,0xa3,0xa3,0xa4,0xa4,0xa4,0xa5,0xa5,0xa5,0xa6,
+    0xa6,0xa6,0xa7,0xa7,0xa7,0xa8,0xa8,0xa8,0xa9,0xa9,0xa9,0xaa,0xaa,0xaa,0xab,0xab,
+    0xab,0xac,0xac,0xac,0xad,0xad,0xad,0xae,0xae,0xae,0xaf,0xaf,0xaf,0xb0,0xb0,0xb0,
+    0xb1,0xb1,0xb1,0xb2,0xb2,0xb2,0xb3,0xb3,0xb3,0xb4,0xb4,0xb4,0xb5,0xb5,0xb5,0xb6,
+    0xb6,0xb6,0xb7,0xb7,0xb7,0xb8,0xb8,0xb8,0xb9,0xb9,0xb9,0xba,0xba,0xba,0xbb,0xbb,
+    0xbb,0xbc,0xbc,0xbc,0xbd,0xbd,0xbd,0xbe,0xbe,0xbe,0xbf,0xbf,0xbf,0xc0,0xc0,0xc0,
+    0xc1,0xc1,0xc1,0xc2,0xc2,0xc2,0xc3,0xc3,0xc3,0xc4,0xc4,0xc4,0xc5,0xc5,0xc5,0xc6,
+    0xc6,0xc6,0xc7,0xc7,0xc7,0xc8,0xc8,0xc8,0xc9,0xc9,0xc9,0xca,0xca,0xca,0xcb,0xcb,
+    0xcb,0xcc,0xcc,0xcc,0xcd,0xcd,0xcd,0xce,0xce,0xce,0xcf,0xcf,0xcf,0xd0,0xd0,0xd0,
+    0xd1,0xd1,0xd1,0xd2,0xd2,0xd2,0xd3,0xd3,0xd3,0xd4,0xd4,0xd4,0xd5,0xd5,0xd5,0xd6,
+    0xd6,0xd6,0xd7,0xd7,0xd7,0xd8,0xd8,0xd8,0xd9,0xd9,0xd9,0xda,0xda,0xda,0xdb,0xdb,
+    0xdb,0xdc,0xdc,0xdc,0xdd,0xdd,0xdd,0xde,0xde,0xde,0xdf,0xdf,0xdf,0xe0,0xe0,0xe0,
+    0xe1,0xe1,0xe1,0xe2,0xe2,0xe2,0xe3,0xe3,0xe3,0xe4,0xe4,0xe4,0xe5,0xe5,0xe5,0xe6,
+    0xe6,0xe6,0xe7,0xe7,0xe7,0xe8,0xe8,0xe8,0xe9,0xe9,0xe9,0xea,0xea,0xea,0xeb,0xeb,
+    0xeb,0xec,0xec,0xec,0xed,0xed,0xed,0xee,0xee,0xee,0xef,0xef,0xef,0xf0,0xf0,0xf0,
+    0xf1,0xf1,0xf1,0xf2,0xf2,0xf2,0xf3,0xf3,0xf3,0xf4,0xf4,0xf4,0xf5,0xf5,0xf5,0xf6,
+    0xf6,0xf6,0xf7,0xf7,0xf7,0xf8,0xf8,0xf8,0xf9,0xf9,0xf9,0xfa,0xfa,0xfa,0xfb,0xfb,
+    0xfb,0xfc,0xfc,0xfc,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xff,0x2c,0x00,0x00,
+    0x00,0x00,0x40,0x00,0x40,0x00,0x00,0x08,0xff,0x00,0x01,0x04,0x10,0x30,0x80,0x40,
+    0x01,0x03,0x07,0x10,0x24,0x50,0xb0,0x80,0x41,0x03,0x07,0x0f,0x20,0x44,0x90,0x30,
+    0x81,0x42,0x05,0x0b,0x17,0x30,0x64,0xd0,0xb0,0x81,0x43,0x07,0x0f,0x1f,0x40,0x84,
+    0x10,0x31,0x82,0x44,0x09,0x13,0x27,0x50,0xa4,0x50,0xb1,0x82,0x45,0x0b,0x17,0x2f,
+    0x60,0xc4,0x90,0x31,0x83,0x46,0x0d,0x1b,0x37,0x70,0xe4,0xd0,0xb1,0x83,0x47,0x0f,
+    0x1f,0x3f,0x80,0x04,0x11,0x32,0x84,0x48,0x11,0x23,0x47,0x90,0x24,0x51,0xb2,0x84,
+    0x49,0x13,0x27,0x4f,0xa0,0x44,0x91,0x32,0x85,0x4a,0x15,0x2b,0x57,0xb0,0x64,0xd1,
+    0xb2,0x85,0x4b,0x17,0x2f,0x5f,0xc0,0x84,0x11,0x33,0x86,0x4c,0x19,0x33,0x67,0xd0,
+    0xa4,0x51,0xb3,0x86,0x4d,0x1b,0x37,0x6f,0xe0,0xc4,0x91,0x33,0x87,0x4e,0x1d,0x3b,
+    0x77,0xf0,0xe4,0xd1,0xb3,0x87,0x4f,0x1f,0x3f,0x7f,0x00,0x05,0x12,0x34,0x88,0x50,
+    0x21,0x43,0x87,0x10,0x25,0x52,0xb4,0x88,0x51,0x23,0x47,0x8f,0x20,0x45,0x92,0x34,
+    0x89,0x52,0x25,0x4b,0x97,0x30,0x65,0xd2,0xb4,0x89,0x53,0x27,0x4f,0x9f,0x40,0x85,
+    0x12,0x35,0x8a,0x54,0x29,0x53,0xa7,0x50,0xa5,0x52,0xb5,0x8a,0x55,0x2b,0x57,0xaf,
+    0x60,0xc5,0x92,0x35,0x8b,0x56,0x2d,0x5b,0xb7,0x70,0xe5,0xd2,0xb5,0x8b,0x57,0x2f,
+    0x5f,0xbf,0x80,0x05,0x13,0x36,0x8c,0x58,0x31,0x63,0xc7,0x90,0x25,0x53,0xb6,0x8c,
+    0x59,0x33,0x67,0xcf,0xa0,0x45,0x93,0x36,0x8d,0x5a,0x35,0x6b,0xd7,0xb0,0x65,0xd3,
+    0xb6,0x8d,0x5b,0x37,0x6f,0xdf,0xc0,0x85,0xff,0x13,0x37,0x8e,0x5c,0x39,0x73,0xe7,
+    0xd0,0xa5,0x53,0xb7,0x8e,0x5d,0x3b,0x77,0xef,0xe0,0xc5,0x93,0x37,0x8f,0x5e,0x3d,
+    0x7b,0xf7,0xf0,0xe5,0xd3,0xb7,0x8f,0x5f,0x3f,0x7f,0xff,0x00,0x10,0x80,0x00,0x03,
+    0x10,0x50,0x80,0x01,0x07,0x20,0x90,0x80,0x02,0x0b,0x30,0xd0,0x80,0x03,0x0f,0x40,
+    0x10,0x81,0x04,0x13,0x50,0x50,0x81,0x05,0x17,0x60,0x90,0x81,0x06,0x1b,0x70,0xd0,
+    0x81,0x07,0x1f,0x80,0x10,0x82,0x08,0x23,0x90,0x50,0x82,0x09,0x27,0xa0,0x90,0x82,
+    0x0a,0x2b,0xb0,0xd0,0x82,0x0b,0x2f,0xc0,0x10,0x83,0x0c,0x33,0xd0,0x50,0x83,0x0d,
+    0x37,0xe0,0x90,0x83,0x0e,0x3b,0xf0,0xd0,0x83,0x0f,0x3f,0x00,0x11,0x84,0x10,0x43,
+    0x10,0x51,0x84,0x11,0x47,0x20,0x91,0x84,0x12,0x4b,0x30,0xd1,0x84,0x13,0x4f,0x40,
+    0x11,0x85,0x14,0x53,0x50,0x51,0x85,0x15,0x57,0x60,0x91,0x85,0x16,0x5b,0x70,0xd1,
+    0x85,0x17,0x5f,0x80,0x11,0x86,0x18,0x63,0x90,0x51,0x86,0x19,0x67,0xa0,0x91,0x86,
+    0x1a,0x6b,0xb0,0xd1,0x86,0x1b,0x6f,0xc0,0x11,0x87,0x1c,0x73,0xd0,0x51,0x87,0x1d,
+    0x77,0xe0,0x91,0x87,0x1e,0x7b,0xf0,0xd1,0x87,0x1f,0x7f,0x00,0x12,0x88,0x20,0x83,
+    0x10,0x52,0x88,0x21,0x87,0x20,0x92,0x88,0x22,0x8b,0x30,0xd2,0x88,0x23,0x8f,0x40,
+    0x12,0x89,0x24,0x93,0x50,0x52,0x89,0x25,0x97,0x60,0x92,0x89,0x26,0x9b,0x70,0xd2,
+    0x89,0x27,0x9f,0x80,0x12,0x8a,0x28,0xa3,0x90,0x52,0x8a,0x29,0xa7,0xa0,0x92,0x8a,
+    0x2a,0xab,0xb0,0xd2,0x8a,0x2b,0xaf,0xc0,0xff,0x12,0x8b,0x2c,0xb3,0xd0,0x52,0x8b,
+    0x2d,0xb7,0xe0,0x92,0x8b,0x2e,0xbb,0xf0,0xd2,0x8b,0x2f,0xbf,0x00,0x13,0x8c,0x30,
+    0xc3,0x10,0x53,0x8c,0x31,0xc7,0x20,0x93,0x8c,0x32,0xcb,0x30,0xd3,0x8c,0x33,0xcf,
+    0x40,0x13,0x8d,0x34,0xd3,0x50,0x53,0x8d,0x35,0xd7,0x60,0x93,0x8d,0x36,0xdb,0x70,
+    0xd3,0x8d,0x37,0xdf,0x80,0x13,0x8e,0x38,0xe3,0x90,0x53,0x8e,0x39,0xe7,0xa0,0x93,
+    0x8e,0x3a,0xeb,0xb0,0xd3,0x8e,0x3b,0xef,0xc0,0x13,0x8f,0x3c,0xf3,0xd0,0x53,0x8f,
+    0x3d,0xf7,0xe0,0x93,0x8f,0x3e,0xfb,0xf0,0xd3,0x8f,0x3f,0xff,0x00,0x10,0x80,0x00,
+    0x03,0x10,0x50,0x80,0x01,0x07,0x20,0x90,0x80,0x02,0x0b,0x30,0xd0,0x80,0x03,0x0f,
+    0x40,0x10,0x81,0x04,0x13,0x50,0x50,0x81,0x05,0x17,0x60,0x90,0x81,0x06,0x1b,0x70,
+    0xd0,0x81,0x07,0x1f,0x80,0x10,0x82,0x08,0x23,0x90,0x50,0x82,0x09,0x27,0xa0,0x90,
+    0x82,0x0a,0x2b,0xb0,0xd0,0x82,0x0b,0x2f,0xc0,0x10,0x83,0x0c,0x33,0xd0,0x50,0x83,
+    0x0d,0x37,0xe0,0x90,0x83,0x0e,0x3b,0xf0,0xd0,0x83,0x0f,0x3f,0x00,0x11,0x84,0x10,
+    0x43,0x10,0x51,0x84,0x11,0x47,0x20,0x91,0x84,0x12,0x4b,0x30,0xd1,0x84,0x13,0x4f,
+    0x40,0x11,0x85,0x14,0x53,0x50,0x51,0x85,0x15,0x57,0x60,0x91,0x85,0x16,0x5b,0x70,
+    0xd1,0x85,0x17,0x5f,0x80,0x11,0x86,0x18,0x63,0x90,0x51,0x86,0x19,0x67,0xa0,0x91,
+    0x86,0x1a,0x6b,0xb0,0xd1,0x86,0x1b,0x6f,0xc0,0x11,0x87,0x1c,0x73,0xd0,0x51,0x87,
+    0x1d,0x77,0xe0,0x91,0x87,0x1e,0x7b,0xf0,0xff,0xd1,0x87,0x1f,0x7f,0x00,0x12,0x88,
+    0x20,0x83,0x10,0x52,0x88,0x21,0x87,0x20,0x92,0x88,0x22,0x8b,0x30,0xd2,0x88,0x23,
+    0x8f,0x40,0x12,0x89,0x24,0x93,0x50,0x52,0x89,0x25,0x97,0x60,0x92,0x89,0x26,0x9b,
+    0x70,0xd2,0x89,0x27,0x9f,0x80,0x12,0x8a,0x28,0xa3,0x90,0x52,0x8a,0x29,0xa7,0xa0,
+    0x92,0x8a,0x2a,0xab,0xb0,0xd2,0x8a,0x2b,0xaf,0xc0,0x12,0x8b,0x2c,0xb3,0xd0,0x52,
+    0x8b,0x2d,0xb7,0xe0,0x92,0x8b,0x2e,0xbb,0xf0,0xd2,0x8b,0x2f,0xbf,0x00,0x13,0x8c,
+    0x30,0xc3,0x10,0x53,0x8c,0x31,0xc7,0x20,0x93,0x8c,0x32,0xcb,0x30,0xd3,0x8c,0x33,
+    0xcf,0x40,0x13,0x8d,0x34,0xd3,0x50,0x53,0x8d,0x35,0xd7,0x60,0x93,0x8d,0x36,0xdb,
+    0x70,0xd3,0x8d,0x37,0xdf,0x80,0x13,0x8e,0x38,0xe3,0x90,0x53,0x8e,0x39,0xe7,0xa0,
+    0x93,0x8e,0x3a,0xeb,0xb0,0xd3,0x8e,0x3b,0xef,0xc0,0x13,0x8f,0x3c,0xf3,0xd0,0x53,
+    0x8f,0x3d,0xf7,0xe0,0x93,0x8f,0x3e,0xfb,0xf0,0xd3,0x8f,0x3f,0xff,0x00,0x40,0x00,
+    0x04,0x30,0x00,0x02,0x14,0xc0,0x00,0x07,0x40,0x40,0x02,0x14,0xb0,0x00,0x06,0x34,
+    0xc0,0x01,0x0f,0x80,0x40,0x04,0x24,0x30,0x01,0x0a,0x54,0xc0,0x02,0x17,0xc0,0x40,
+    0x06,0x34,0xb0,0x01,0x0e,0x74,0xc0,0x03,0x1f,0x00,0x41,0x08,0x44,0x30,0x02,0x12,
+    0x94,0xc0,0x04,0x27,0x40,0x41,0x0a,0x54,0xb0,0x02,0x16,0xb4,0xc0,0x05,0x2f,0x80,
+    0x41,0x0c,0x64,0x30,0x03,0x1a,0xd4,0xc0,0x06,0x37,0xc0,0x41,0x0e,0x74,0xb0,0x03,
+    0x1e,0xf4,0xc0,0x07,0x3f,0x00,0x42,0x10,0xff,0x84,0x30,0x04,0x22,0x14,0xc1,0x08,
+    0x47,0x40,0x42,0x12,0x94,0xb0,0x04,0x26,0x34,0xc1,0x09,0x4f,0x80,0x42,0x14,0xa4,
+    0x30,0x05,0x2a,0x54,0xc1,0x0a,0x57,0xc0,0x42,0x16,0xb4,0xb0,0x05,0x2e,0x74,0xc1,
+    0x0b,0x5f,0x00,0x43,0x18,0xc4,0x30,0x06,0x32,0x94,0xc1,0x0c,0x67,0x40,0x43,0x1a,
+    0xd4,0xb0,0x06,0x36,0xb4,0xc1,0x0d,0x6f,0x80,0x43,0x1c,0xe4,0x30,0x07,0x3a,0xd4,
+    0xc1,0x0e,0x77,0xc0,0x43,0x1e,0xf4,0xb0,0x07,0x3e,0xf4,0xc1,0x0f,0x7f,0x00,0x44,
+    0x20,0x04,0x31,0x08,0x42,0x14,0xc2,0x10,0x87,0x40,0x44,0x22,0x14,0xb1,0x08,0x46,
+    0x34,0xc2,0x11,0x8f,0x80,0x44,0x24,0x24,0x31,0x09,0x4a,0x54,0xc2,0x12,0x97,0xc0,
+    0x44,0x26,0x34,0xb1,0x09,0x4e,0x74,0xc2,0x13,0x9f,0x00,0x45,0x28,0x44,0x31,0x0a,
+    0x52,0x94,0xc2,0x14,0xa7,0x40,0x45,0x2a,0x54,0xb1,0x0a,0x56,0xb4,0xc2,0x15,0xaf,
+    0x80,0x45,0x2c,0x64,0x31,0x0b,0x5a,0xd4,0xc2,0x16,0xb7,0xc0,0x45,0x2e,0x74,0xb1,
+    0x0b,0x5e,0xf4,0xc2,0x17,0xbf,0x00,0x46,0x30,0x84,0x31,0x0c,0x62,0x14,0xc3,0x18,
+    0xc7,0x40,0x46,0x32,0x94,0xb1,0x0c,0x66,0x34,0xc3,0x19,0xcf,0x80,0x46,0x34,0xa4,
+    0x31,0x0d,0x6a,0x54,0xc3,0x1a,0xd7,0xc0,0x46,0x36,0xb4,0xb1,0x0d,0x6e,0x74,0xc3,
+    0x1b,0xdf,0x00,0x47,0x38,0xc4,0x31,0x0e,0x72,0x94,0xc3,0x1c,0xe7,0x40,0x47,0x3a,
+    0xd4,0xb1,0x0e,0x76,0xb4,0xc3,0x1d,0xef,0x80,0x47,0x3c,0xe4,0x31,0x0f,0x7a,0xd4,
+    0xc3,0x1e,0xf7,0xc0,0x47,0x3e,0xf4,0xb1,0xff,0x0f,0x7e,0xf4,0xc3,0x1f,0xff,0x00,
+    0x40,0x00,0x04,0x30,0x00,0x02,0x14,0xc0,0x00,0x07,0x40,0x40,0x02,0x14,0xb0,0x00,
+    0x06,0x34,0xc0,0x01,0x0f,0x80,0x40,0x04,0x24,0x30,0x01,0x0a,0x54,0xc0,0x02,0x17,
+    0xc0,0x40,0x06,0x34,0xb0,0x01,0x0e,0x74,0xc0,0x03,0x1f,0x00,0x41,0x08,0x44,0x30,
+    0x02,0x12,0x94,0xc0,0x04,0x27,0x40,0x41,0x0a,0x54,0xb0,0x02,0x16,0xb4,0xc0,0x05,
+    0x2f,0x80,0x41,0x0c,0x64,0x30,0x03,0x1a,0xd4,0xc0,0x06,0x37,0xc0,0x41,0x0e,0x74,
+    0xb0,0x03,0x1e,0xf4,0xc0,0x07,0x3f,0x00,0x42,0x10,0x84,0x30,0x04,0x22,0x14,0xc1,
+    0x08,0x47,0x40,0x42,0x12,0x94,0xb0,0x04,0x26,0x34,0xc1,0x09,0x4f,0x80,0x42,0x14,
+    0xa4,0x30,0x05,0x2a,0x54,0xc1,0x0a,0x57,0xc0,0x42,0x16,0xb4,0xb0,0x05,0x2e,0x74,
+    0xc1,0x0b,0x5f,0x00,0x43,0x18,0xc4,0x30,0x06,0x32,0x94,0xc1,0x0c,0x67,0x40,0x43,
+    0x1a,0xd4,0xb0,0x06,0x36,0xb4,0xc1,0x0d,0x6f,0x80,0x43,0x1c,0xe4,0x30,0x07,0x3a,
+    0xd4,0xc1,0x0e,0x77,0xc0,0x43,0x1e,0xf4,0xb0,0x07,0x3e,0xf4,0xc1,0x0f,0x7f,0x00,
+    0x44,0x20,0x04,0x31,0x08,0x42,0x14,0xc2,0x10,0x87,0x40,0x44,0x22,0x14,0xb1,0x08,
+    0x46,0x34,0xc2,0x11,0x8f,0x80,0x44,0x24,0x24,0x31,0x09,0x4a,0x54,0xc2,0x12,0x97,
+    0xc0,0x44,0x26,0x34,0xb1,0x09,0x4e,0x74,0xc2,0x13,0x9f,0x00,0x45,0x28,0x44,0x31,
+    0x0a,0x52,0x94,0xc2,0x14,0xa7,0x40,0x45,0x2a,0x54,0xb1,0x0a,0x56,0xb4,0xc2,0x15,
+    0xaf,0x80,0x45,0x2c,0x64,0x31,0x0b,0x5a,0xff,0xd4,0xc2,0x16,0xb7,0xc0,0x45,0x2e,
+    0x74,0xb1,0x0b,0x5e,0xf4,0xc2,0x17,0xbf,0x00,0x46,0x30,0x84,0x31,0x0c,0x62,0x14,
+    0xc3,0x18,0xc7,0x40,0x46,0x32,0x94,0xb1,0x0c,0x66,0x34,0xc3,0x19,0xcf,0x80,0x46,
+    0x34,0xa4,0x31,0x0d,0x6a,0x54,0xc3,0x1a,0xd7,0xc0,0x46,0x36,0xb4,0xb1,0x0d,0x6e,
+    0x74,0xc3,0x1b,0xdf,0x00,0x47,0x38,0xc4,0x31,0x0e,0x72,0x94,0xc3,0x1c,0xe7,0x40,
+    0x47,0x3a,0xd4,0xb1,0x0e,0x76,0xb4,0xc3,0x1d,0xef,0x80,0x47,0x3c,0xe4,0x31,0x0f,
+    0x7a,0xd4,0xc3,0x1e,0xf7,0xc0,0x47,0x3e,0xf4,0xb1,0x0f,0x7e,0xf4,0xc3,0x1f,0xff,
+    0x00,0x40,0x00,0x04,0x30,0x00,0x02,0x14,0xc0,0x00,0x07,0x40,0x40,0x02,0x14,0xb0,
+    0x00,0x06,0x34,0xc0,0x01,0x0f,0x80,0x40,0x04,0x24,0x30,0x01,0x0a,0x54,0xc0,0x02,
+    0x17,0xc0,0x40,0x06,0x34,0xb0,0x01,0x0e,0x74,0xc0,0x03,0x1f,0x00,0x41,0x08,0x44,
+    0x30,0x02,0x12,0x94,0xc0,0x04,0x27,0x40,0x41,0x0a,0x54,0xb0,0x02,0x16,0xb4,0xc0,
+    0x05,0x2f,0x80,0x41,0x0c,0x64,0x30,0x03,0x1a,0xd4,0xc0,0x06,0x37,0xc0,0x41,0x0e,
+    0x74,0xb0,0x03,0x1e,0xf4,0xc0,0x07,0x3f,0x00,0x42,0x10,0x84,0x30,0x04,0x22,0x14,
+    0xc1,0x08,0x47,0x40,0x42,0x12,0x94,0xb0,0x04,0x26,0x34,0xc1,0x09,0x4f,0x80,0x42,
+    0x14,0xa4,0x30,0x05,0x2a,0x54,0xc1,0x0a,0x57,0xc0,0x42,0x16,0xb4,0xb0,0x05,0x2e,
+    0x74,0xc1,0x0b,0x5f,0x00,0x43,0x18,0xc4,0x30,0x06,0x32,0x94,0xc1,0x0c,0x67,0x40,
+    0x43,0x1a,0xd4,0xb0,0x06,0x36,0xb4,0xc1,0xff,0x0d,0x6f,0x80,0x43,0x1c,0xe4,0x30,
+    0x07,0x3a,0xd4,0xc1,0x0e,0x77,0xc0,0x43,0x1e,0xf4,0xb0,0x07,0x3e,0xf4,0xc1,0x0f,
+    0x7f,0x00,0x44,0x20,0x04,0x31,0x08,0x42,0x14,0xc2,0x10,0x87,0x40,0x44,0x22,0x14,
+    0xb1,0x08,0x46,0x34,0xc2,0x11,0x8f,0x80,0x44,0x24,0x24,0x31,0x09,0x4a,0x54,0xc2,
+    0x12,0x97,0xc0,0x44,0x26,0x34,0xb1,0x09,0x4e,0x74,0xc2,0x13,0x9f,0x00,0x45,0x28,
+    0x44,0x31,0x0a,0x52,0x94,0xc2,0x14,0xa7,0x40,0x45,0x2a,0x54,0xb1,0x0a,0x56,0xb4,
+    0xc2,0x15,0xaf,0x80,0x45,0x2c,0x64,0x31,0x0b,0x5a,0xd4,0xc2,0x16,0xb7,0xc0,0x45,
+    0x2e,0x74,0xb1,0x0b,0x5e,0xf4,0xc2,0x17,0xbf,0x00,0x46,0x30,0x84,0x31,0x0c,0x62,
+    0x14,0xc3,0x18,0xc7,0x40,0x46,0x32,0x94,0xb1,0x0c,0x66,0x34,0xc3,0x19,0xcf,0x80,
+    0x46,0x34,0xa4,0x31,0x0d,0x6a,0x54,0xc3,0x1a,0xd7,0xc0,0x46,0x36,0xb4,0xb1,0x0d,
+    0x6e,0x74,0xc3,0x1b,0xdf,0x00,0x47,0x38,0xc4,0x31,0x0e,0x72,0x94,0xc3,0x1c,0xe7,
+    0x40,0x47,0x3a,0xd4,0xb1,0x0e,0x76,0xb4,0xc3,0x1d,0xef,0x80,0x47,0x3c,0xe4,0x31,
+    0x0f,0x7a,0xd4,0xc3,0x1e,0xf7,0xc0,0x47,0x3e,0xf4,0xb1,0x0f,0x7e,0xf4,0xc3,0x1f,
+    0xff,0x00,0x40,0x00,0x04,0x30,0x00,0x02,0x14,0xc0,0x00,0x07,0x40,0x40,0x02,0x14,
+    0xb0,0x00,0x06,0x34,0xc0,0x01,0x0f,0x80,0x40,0x04,0x24,0x30,0x01,0x0a,0x54,0xc0,
+    0x02,0x17,0xc0,0x40,0x06,0x34,0xb0,0x01,0x0e,0x74,0xc0,0x03,0x1f,0x00,0x41,0x08,
+    0x44,0x30,0x02,0x12,0x94,0xc0,0x04,0x27,0xff,0x40,0x41,0x0a,0x54,0xb0,0x02,0x16,
+    0xb4,0xc0,0x05,0x2f,0x80,0x41,0x0c,0x64,0x30,0x03,0x1a,0xd4,0xc0,0x06,0x37,0xc0,
+    0x41,0x0e,0x74,0xb0,0x03,0x1e,0xf4,0xc0,0x07,0x3f,0x00,0x42,0x10,0x84,0x30,0x04,
+    0x22,0x14,0xc1,0x08,0x47,0x40,0x42,0x12,0x94,0xb0,0x04,0x26,0x34,0xc1,0x09,0x4f,
+    0x80,0x42,0x14,0xa4,0x30,0x05,0x2a,0x54,0xc1,0x0a,0x57,0xc0,0x42,0x16,0xb4,0xb0,
+    0x05,0x2e,0x74,0xc1,0x0b,0x5f,0x00,0x43,0x18,0xc4,0x30,0x06,0x32,0x94,0xc1,0x0c,
+    0x67,0x40,0x43,0x1a,0xd4,0xb0,0x06,0x36,0xb4,0xc1,0x0d,0x6f,0x80,0x43,0x1c,0xe4,
+    0x30,0x07,0x3a,0xd4,0xc1,0x0e,0x77,0xc0,0x43,0x1e,0xf4,0xb0,0x07,0x3e,0xf4,0xc1,
+    0x0f,0x7f,0x00,0x44,0x20,0x04,0x31,0x08,0x42,0x14,0xc2,0x10,0x87,0x40,0x44,0x22,
+    0x14,0xb1,0x08,0x46,0x34,0xc2,0x11,0x8f,0x80,0x44,0x24,0x24,0x31,0x09,0x4a,0x54,
+    0xc2,0x12,0x97,0xc0,0x44,0x26,0x34,0xb1,0x09,0x4e,0x74,0xc2,0x13,0x9f,0x00,0x45,
+    0x28,0x44,0x31,0x0a,0x52,0x94,0xc2,0x14,0xa7,0x40,0x45,0x2a,0x54,0xb1,0x0a,0x56,
+    0xb4,0xc2,0x15,0xaf,0x80,0x45,0x2c,0x64,0x31,0x0b,0x5a,0xd4,0xc2,0x16,0xb7,0xc0,
+    0x45,0x2e,0x74,0xb1,0x0b,0x5e,0xf4,0xc2,0x17,0xbf,0x00,0x46,0x30,0x84,0x31,0x0c,
+    0x62,0x14,0xc3,0x18,0xc7,0x40,0x46,0x32,0x94,0xb1,0x0c,0x66,0x34,0xc3,0x19,0xcf,
+    0x80,0x46,0x34,0xa4,0x31,0x0d,0x6a,0x54,0xc3,0x1a,0xd7,0xc0,0x46,0x36,0xb4,0xb1,
+    0x0d,0x6e,0x74,0xc3,0x1b,0xdf,0x00,0x47,0xff,0x38,0xc4,0x31,0x0e,0x72,0x94,0xc3,
+    0x1c,0xe7,0x40,0x47,0x3a,0xd4,0xb1,0x0e,0x76,0xb4,0xc3,0x1d,0xef,0x80,0x47,0x3c,
+    0xe4,0x31,0x0f,0x7a,0xd4,0xc3,0x1e,0xf7,0xc0,0x47,0x3e,0xf4,0xb1,0x0f,0x7e,0xf4,
+    0xc3,0x1f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,0x40,0x00,0x05,0x60,0x00,0x07,0x80,
+    0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,0x00,0x0f,0x00,0x01,0x11,0x20,0x01,
+    0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,0x19,0xa0,0x01,0x1b,0xc0,0x01,0x1d,
+    0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,0x40,0x02,0x25,0x60,0x02,0x27,0x80,
+    0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,0x02,0x2f,0x00,0x03,0x31,0x20,0x03,
+    0x33,0x40,0x03,0x35,0x60,0x03,0x37,0x80,0x03,0x39,0xa0,0x03,0x3b,0xc0,0x03,0x3d,
+    0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,0x43,0x40,0x04,0x45,0x60,0x04,0x47,0x80,
+    0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,0xe0,0x04,0x4f,0x00,0x05,0x51,0x20,0x05,
+    0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,0x05,0x59,0xa0,0x05,0x5b,0xc0,0x05,0x5d,
+    0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,0x63,0x40,0x06,0x65,0x60,0x06,0x67,0x80,
+    0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,0xe0,0x06,0x6f,0x00,0x07,0x71,0x20,0x07,
+    0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,0x07,0x79,0xa0,0x07,0x7b,0xc0,0x07,0x7d,
+    0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,0x83,0x40,0x08,0x85,0x60,0x08,0x87,0x80,
+    0x08,0x89,0xa0,0x08,0x8b,0xc0,0x08,0x8d,0xff,0xe0,0x08,0x8f,0x00,0x09,0x91,0x20,
+    0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,0x09,0x99,0xa0,0x09,0x9b,0xc0,0x09,
+    0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,0xa3,0x40,0x0a,0xa5,0x60,0x0a,0xa7,
+    0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,0xe0,0x0a,0xaf,0x00,0x0b,0xb1,0x20,
+    0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,0x0b,0xb9,0xa0,0x0b,0xbb,0xc0,0x0b,
+    0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,0xc3,0x40,0x0c,0xc5,0x60,0x0c,0xc7,
+    0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,0xe0,0x0c,0xcf,0x00,0x0d,0xd1,0x20,
+    0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,0x0d,0xd9,0xa0,0x0d,0xdb,0xc0,0x0d,
+    0xdd,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,0x20,0x0e,0xe3,0x40,0x0e,0xe5,0x60,0x0e,0xe7,
+    0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,0xed,0xe0,0x0e,0xef,0x00,0x0f,0xf1,0x20,
+    0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,0x80,0x0f,0xf9,0xa0,0x0f,0xfb,0xc0,0x0f,
+    0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,0x40,0x00,0x05,0x60,0x00,0x07,
+    0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,0x00,0x0f,0x00,0x01,0x11,0x20,
+    0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,0x19,0xa0,0x01,0x1b,0xc0,0x01,
+    0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,0x40,0x02,0x25,0x60,0x02,0x27,
+    0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,0x02,0x2f,0x00,0x03,0x31,0x20,
+    0x03,0x33,0x40,0x03,0x35,0x60,0x03,0x37,0xff,0x80,0x03,0x39,0xa0,0x03,0x3b,0xc0,
+    0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,0x43,0x40,0x04,0x45,0x60,0x04,
+    0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,0xe0,0x04,0x4f,0x00,0x05,0x51,
+    0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,0x05,0x59,0xa0,0x05,0x5b,0xc0,
+    0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,0x63,0x40,0x06,0x65,0x60,0x06,
+    0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,0xe0,0x06,0x6f,0x00,0x07,0x71,
+    0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,0x07,0x79,0xa0,0x07,0x7b,0xc0,
+    0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,0x83,0x40,0x08,0x85,0x60,0x08,
+    0x87,0x80,0x08,0x89,0xa0,0x08,0x8b,0xc0,0x08,0x8d,0xe0,0x08,0x8f,0x00,0x09,0x91,
+    0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,0x09,0x99,0xa0,0x09,0x9b,0xc0,
+    0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,0xa3,0x40,0x0a,0xa5,0x60,0x0a,
+    0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,0xe0,0x0a,0xaf,0x00,0x0b,0xb1,
+    0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,0x0b,0xb9,0xa0,0x0b,0xbb,0xc0,
+    0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,0xc3,0x40,0x0c,0xc5,0x60,0x0c,
+    0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,0xe0,0x0c,0xcf,0x00,0x0d,0xd1,
+    0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,0x0d,0xd9,0xa0,0x0d,0xdb,0xc0,
+    0x0d,0xdd,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,0xff,0x20,0x0e,0xe3,0x40,0x0e,0xe5,0x60,
+    0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,0xed,0xe0,0x0e,0xef,0x00,0x0f,
+    0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,0x80,0x0f,0xf9,0xa0,0x0f,0xfb,
+    0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,0x40,0x00,0x05,0x60,
+    0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,0x00,0x0f,0x00,0x01,
+    0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,0x19,0xa0,0x01,0x1b,
+    0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,0x40,0x02,0x25,0x60,
+    0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,0x02,0x2f,0x00,0x03,
+    0x31,0x20,0x03,0x33,0x40,0x03,0x35,0x60,0x03,0x37,0x80,0x03,0x39,0xa0,0x03,0x3b,
+    0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,0x43,0x40,0x04,0x45,0x60,
+    0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,0xe0,0x04,0x4f,0x00,0x05,
+    0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,0x05,0x59,0xa0,0x05,0x5b,
+    0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,0x63,0x40,0x06,0x65,0x60,
+    0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,0xe0,0x06,0x6f,0x00,0x07,
+    0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,0x07,0x79,0xa0,0x07,0x7b,
+    0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,0x83,0x40,0x08,0x85,0x60,
+    0x08,0x87,0x80,0x08,0x89,0xa0,0x08,0x8b,0xff,0xc0,0x08,0x8d,0xe0,0x08,0x8f,0x00,
+    0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,0x09,0x99,0xa0,0x09,
+    0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,0xa3,0x40,0x0a,0xa5,
+    0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,0xe0,0x0a,0xaf,0x00,
+    0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,0x0b,0xb9,0xa0,0x0b,
+    0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,0xc3,0x40,0x0c,0xc5,
+    0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,0xe0,0x0c,0xcf,0x00,
+    0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,0x0d,0xd9,0xa0,0x0d,
+    0xdb,0xc0,0x0d,0xdd,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,0x20,0x0e,0xe3,0x40,0x0e,0xe5,
+    0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,0xed,0xe0,0x0e,0xef,0x00,
+    0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,0x80,0x0f,0xf9,0xa0,0x0f,
+    0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,0x40,0x00,0x05,
+    0x60,0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,0x00,0x0f,0x00,
+    0x01,0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,0x19,0xa0,0x01,
+    0x1b,0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,0x40,0x02,0x25,
+    0x60,0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,0x02,0x2f,0x00,
+    0x03,0x31,0x20,0x03,0x33,0x40,0x03,0x35,0xff,0x60,0x03,0x37,0x80,0x03,0x39,0xa0,
+    0x03,0x3b,0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,0x43,0x40,0x04,
+    0x45,0x60,0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,0xe0,0x04,0x4f,
+    0x00,0x05,0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,0x05,0x59,0xa0,
+    0x05,0x5b,0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,0x63,0x40,0x06,
+    0x65,0x60,0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,0xe0,0x06,0x6f,
+    0x00,0x07,0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,0x07,0x79,0xa0,
+    0x07,0x7b,0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,0x83,0x40,0x08,
+    0x85,0x60,0x08,0x87,0x80,0x08,0x89,0xa0,0x08,0x8b,0xc0,0x08,0x8d,0xe0,0x08,0x8f,
+    0x00,0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,0x09,0x99,0xa0,
+    0x09,0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,0xa3,0x40,0x0a,
+    0xa5,0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,0xe0,0x0a,0xaf,
+    0x00,0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,0x0b,0xb9,0xa0,
+    0x0b,0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,0xc3,0x40,0x0c,
+    0xc5,0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,0xe0,0x0c,0xcf,
+    0x00,0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,0x0d,0xd9,0xa0,
+    0x0d,0xdb,0xc0,0x0d,0xdd,0xe0,0x0d,0xdf,0xff,0x00,0x0e,0xe1,0x20,0x0e,0xe3,0x40,
+    0x0e,0xe5,0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,0xed,0xe0,0x0e,
+    0xef,0x00,0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,0x80,0x0f,0xf9,
+    0xa0,0x0f,0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,0x40,
+    0x00,0x05,0x60,0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,0x00,
+    0x0f,0x00,0x01,0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,0x19,
+    0xa0,0x01,0x1b,0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,0x40,
+    0x02,0x25,0x60,0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,0x02,
+    0x2f,0x00,0x03,0x31,0x20,0x03,0x33,0x40,0x03,0x35,0x60,0x03,0x37,0x80,0x03,0x39,
+    0xa0,0x03,0x3b,0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,0x43,0x40,
+    0x04,0x45,0x60,0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,0xe0,0x04,
+    0x4f,0x00,0x05,0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,0x05,0x59,
+    0xa0,0x05,0x5b,0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,0x63,0x40,
+    0x06,0x65,0x60,0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,0xe0,0x06,
+    0x6f,0x00,0x07,0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,0x07,0x79,
+    0xa0,0x07,0x7b,0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,0x83,0x40,
+    0x08,0x85,0x60,0x08,0x87,0x80,0x08,0x89,0xff,0xa0,0x08,0x8b,0xc0,0x08,0x8d,0xe0,
+    0x08,0x8f,0x00,0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,0x09,
+    0x99,0xa0,0x09,0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,0xa3,
+    0x40,0x0a,0xa5,0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,0xe0,
+    0x0a,0xaf,0x00,0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,0x0b,
+    0xb9,0xa0,0x0b,0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,0xc3,
+    0x40,0x0c,0xc5,0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,0xe0,
+    0x0c,0xcf,0x00,0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,0x0d,
+    0xd9,0xa0,0x0d,0xdb,0xc0,0x0d,0xdd,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,0x20,0x0e,0xe3,
+    0x40,0x0e,0xe5,0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,0xed,0xe0,
+    0x0e,0xef,0x00,0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,0x80,0x0f,
+    0xf9,0xa0,0x0f,0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,0x00,0x03,
+    0x40,0x00,0x05,0x60,0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,0x0d,0xe0,
+    0x00,0x0f,0x00,0x01,0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,0x80,0x01,
+    0x19,0xa0,0x01,0x1b,0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,0x02,0x23,
+    0x40,0x02,0x25,0x60,0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,0x2d,0xe0,
+    0x02,0x2f,0x00,0x03,0x31,0x20,0x03,0x33,0xff,0x40,0x03,0x35,0x60,0x03,0x37,0x80,
+    0x03,0x39,0xa0,0x03,0x3b,0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,0x04,
+    0x43,0x40,0x04,0x45,0x60,0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,0x4d,
+    0xe0,0x04,0x4f,0x00,0x05,0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,0x80,
+    0x05,0x59,0xa0,0x05,0x5b,0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,0x06,
+    0x63,0x40,0x06,0x65,0x60,0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,0x6d,
+    0xe0,0x06,0x6f,0x00,0x07,0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,0x80,
+    0x07,0x79,0xa0,0x07,0x7b,0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,0x08,
+    0x83,0x40,0x08,0x85,0x60,0x08,0x87,0x80,0x08,0x89,0xa0,0x08,0x8b,0xc0,0x08,0x8d,
+    0xe0,0x08,0x8f,0x00,0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,0x97,0x80,
+    0x09,0x99,0xa0,0x09,0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,0x20,0x0a,
+    0xa3,0x40,0x0a,0xa5,0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,0x0a,0xad,
+    0xe0,0x0a,0xaf,0x00,0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,0xb7,0x80,
+    0x0b,0xb9,0xa0,0x0b,0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,0x20,0x0c,
+    0xc3,0x40,0x0c,0xc5,0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,0x0c,0xcd,
+    0xe0,0x0c,0xcf,0x00,0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,0xd7,0x80,
+    0x0d,0xd9,0xa0,0x0d,0xdb,0xc0,0x0d,0xdd,0xff,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,0x20,
+    0x0e,0xe3,0x40,0x0e,0xe5,0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,0x0e,
+    0xed,0xe0,0x0e,0xef,0x00,0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,0xf7,
+    0x80,0x0f,0xf9,0xa0,0x0f,0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,0x20,
+    0x00,0x03,0x40,0x00,0x05,0x60,0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,0x00,
+    0x0d,0xe0,0x00,0x0f,0x00,0x01,0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,0x17,
+    0x80,0x01,0x19,0xa0,0x01,0x1b,0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,0x20,
+    0x02,0x23,0x40,0x02,0x25,0x60,0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,0x02,
+    0x2d,0xe0,0x02,0x2f,0x00,0x03,0x31,0x20,0x03,0x33,0x40,0x03,0x35,0x60,0x03,0x37,
+    0x80,0x03,0x39,0xa0,0x03,0x3b,0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,0x41,0x20,
+    0x04,0x43,0x40,0x04,0x45,0x60,0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,0xc0,0x04,
+    0x4d,0xe0,0x04,0x4f,0x00,0x05,0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,0x05,0x57,
+    0x80,0x05,0x59,0xa0,0x05,0x5b,0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,0x61,0x20,
+    0x06,0x63,0x40,0x06,0x65,0x60,0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,0xc0,0x06,
+    0x6d,0xe0,0x06,0x6f,0x00,0x07,0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,0x07,0x77,
+    0x80,0x07,0x79,0xa0,0x07,0x7b,0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,0x81,0x20,
+    0x08,0x83,0x40,0x08,0x85,0x60,0x08,0x87,0xff,0x80,0x08,0x89,0xa0,0x08,0x8b,0xc0,
+    0x08,0x8d,0xe0,0x08,0x8f,0x00,0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,0x09,
+    0x97,0x80,0x09,0x99,0xa0,0x09,0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,0xa1,
+    0x20,0x0a,0xa3,0x40,0x0a,0xa5,0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,0xc0,
+    0x0a,0xad,0xe0,0x0a,0xaf,0x00,0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,0x0b,
+    0xb7,0x80,0x0b,0xb9,0xa0,0x0b,0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,0xc1,
+    0x20,0x0c,0xc3,0x40,0x0c,0xc5,0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,0xc0,
+    0x0c,0xcd,0xe0,0x0c,0xcf,0x00,0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,0x0d,
+    0xd7,0x80,0x0d,0xd9,0xa0,0x0d,0xdb,0xc0,0x0d,0xdd,0xe0,0x0d,0xdf,0x00,0x0e,0xe1,
+    0x20,0x0e,0xe3,0x40,0x0e,0xe5,0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,0xeb,0xc0,
+    0x0e,0xed,0xe0,0x0e,0xef,0x00,0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,0x60,0x0f,
+    0xf7,0x80,0x0f,0xf9,0xa0,0x0f,0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0x00,0x00,0x01,
+    0x20,0x00,0x03,0x40,0x00,0x05,0x60,0x00,0x07,0x80,0x00,0x09,0xa0,0x00,0x0b,0xc0,
+    0x00,0x0d,0xe0,0x00,0x0f,0x00,0x01,0x11,0x20,0x01,0x13,0x40,0x01,0x15,0x60,0x01,
+    0x17,0x80,0x01,0x19,0xa0,0x01,0x1b,0xc0,0x01,0x1d,0xe0,0x01,0x1f,0x00,0x02,0x21,
+    0x20,0x02,0x23,0x40,0x02,0x25,0x60,0x02,0x27,0x80,0x02,0x29,0xa0,0x02,0x2b,0xc0,
+    0x02,0x2d,0xe0,0x02,0x2f,0x00,0x03,0x31,0xff,0x20,0x03,0x33,0x40,0x03,0x35,0x60,
+    0x03,0x37,0x80,0x03,0x39,0xa0,0x03,0x3b,0xc0,0x03,0x3d,0xe0,0x03,0x3f,0x00,0x04,
+    0x41,0x20,0x04,0x43,0x40,0x04,0x45,0x60,0x04,0x47,0x80,0x04,0x49,0xa0,0x04,0x4b,
+    0xc0,0x04,0x4d,0xe0,0x04,0x4f,0x00,0x05,0x51,0x20,0x05,0x53,0x40,0x05,0x55,0x60,
+    0x05,0x57,0x80,0x05,0x59,0xa0,0x05,0x5b,0xc0,0x05,0x5d,0xe0,0x05,0x5f,0x00,0x06,
+    0x61,0x20,0x06,0x63,0x40,0x06,0x65,0x60,0x06,0x67,0x80,0x06,0x69,0xa0,0x06,0x6b,
+    0xc0,0x06,0x6d,0xe0,0x06,0x6f,0x00,0x07,0x71,0x20,0x07,0x73,0x40,0x07,0x75,0x60,
+    0x07,0x77,0x80,0x07,0x79,0xa0,0x07,0x7b,0xc0,0x07,0x7d,0xe0,0x07,0x7f,0x00,0x08,
+    0x81,0x20,0x08,0x83,0x40,0x08,0x85,0x60,0x08,0x87,0x80,0x08,0x89,0xa0,0x08,0x8b,
+    0xc0,0x08,0x8d,0xe0,0x08,0x8f,0x00,0x09,0x91,0x20,0x09,0x93,0x40,0x09,0x95,0x60,
+    0x09,0x97,0x80,0x09,0x99,0xa0,0x09,0x9b,0xc0,0x09,0x9d,0xe0,0x09,0x9f,0x00,0x0a,
+    0xa1,0x20,0x0a,0xa3,0x40,0x0a,0xa5,0x60,0x0a,0xa7,0x80,0x0a,0xa9,0xa0,0x0a,0xab,
+    0xc0,0x0a,0xad,0xe0,0x0a,0xaf,0x00,0x0b,0xb1,0x20,0x0b,0xb3,0x40,0x0b,0xb5,0x60,
+    0x0b,0xb7,0x80,0x0b,0xb9,0xa0,0x0b,0xbb,0xc0,0x0b,0xbd,0xe0,0x0b,0xbf,0x00,0x0c,
+    0xc1,0x20,0x0c,0xc3,0x40,0x0c,0xc5,0x60,0x0c,0xc7,0x80,0x0c,0xc9,0xa0,0x0c,0xcb,
+    0xc0,0x0c,0xcd,0xe0,0x0c,0xcf,0x00,0x0d,0xd1,0x20,0x0d,0xd3,0x40,0x0d,0xd5,0x60,
+    0x0d,0xd7,0x80,0x0d,0xd9,0xa0,0x0d,0xdb,0xff,0xc0,0x0d,0xdd,0xe0,0x0d,0xdf,0x00,
+    0x0e,0xe1,0x20,0x0e,0xe3,0x40,0x0e,0xe5,0x60,0x0e,0xe7,0x80,0x0e,0xe9,0xa0,0x0e,
+    0xeb,0xc0,0x0e,0xed,0xe0,0x0e,0xef,0x00,0x0f,0xf1,0x20,0x0f,0xf3,0x40,0x0f,0xf5,
+    0x60,0x0f,0xf7,0x80,0x0f,0xf9,0xa0,0x0f,0xfb,0xc0,0x0f,0xfd,0xe0,0x0f,0xff,0xf0,
+    0xff,0xff,0xff,0xff,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0xb5,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,
+    0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,
+    0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,
+    0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x07,0x70,0x00,0x01,0x01,0x00,0x3b,
+};
+
+static void test_gif_full_table(void)
+{
+    IWICBitmapDecoder *decoder;
+    IWICBitmapFrameDecode *frame;
+    UINT count = 0, width = 0, height = 0;
+    BYTE buf[64 * 64];
+    WICRect rc = { 0, 0, 64, 64 };
+    HRESULT hr;
+
+    decoder = create_decoder(gif_full_table, sizeof(gif_full_table));
+    ok(decoder != 0, "Failed to load GIF image data\n");
+    if (!decoder) return;
+
+    hr = IWICBitmapDecoder_GetFrameCount(decoder, &count);
+    ok(hr == S_OK, "GetFrameCount error %#lx\n", hr);
+    ok(count == 1, "expected 1, got %u\n", count);
+
+    hr = IWICBitmapDecoder_GetFrame(decoder, 0, &frame);
+    ok(hr == S_OK, "GetFrame error %#lx\n", hr);
+
+    hr = IWICBitmapFrameDecode_GetSize(frame, &width, &height);
+    ok(hr == S_OK, "GetSize error %#lx\n", hr);
+    ok(width == 64 && height == 64, "expected 64x64, got %ux%u\n", width, height);
+
+    hr = IWICBitmapFrameDecode_CopyPixels(frame, &rc, 64, sizeof(buf), buf);
+    ok(hr == S_OK, "CopyPixels error %#lx\n", hr);
+
+    IWICBitmapFrameDecode_Release(frame);
+    IWICBitmapDecoder_Release(decoder);
+}
+
 START_TEST(gifformat)
 {
     HRESULT hr;
@@ -647,6 +1098,7 @@ START_TEST(gifformat)
     test_local_gif_palette();
     test_no_gif_palette();
     test_gif_frame_sizes();
+    test_gif_full_table();
     test_gif_notrailer();
 
     IWICImagingFactory_Release(factory);
@@ -661,6 +1113,7 @@ START_TEST(gifformat)
     test_local_gif_palette();
     test_no_gif_palette();
     test_gif_frame_sizes();
+    test_gif_full_table();
     test_truncated_gif();
 
     IWICImagingFactory_Release(factory);
diff --git a/dlls/windowscodecs/ungif.c b/dlls/windowscodecs/ungif.c
index aa0552c04ce7..6737958a5742 100644
--- a/dlls/windowscodecs/ungif.c
+++ b/dlls/windowscodecs/ungif.c
@@ -452,9 +452,7 @@ DGifGetImageDesc(GifFileType * GifFile) {
 
     Private->PixelCount = GifFile->Image.Width * GifFile->Image.Height;
 
-    DGifSetupDecompress(GifFile);  /* Reset decompress algorithm parameters. */
-
-    return GIF_OK;
+    return DGifSetupDecompress(GifFile);  /* Reset decompress algorithm parameters. */
 }
 
 /******************************************************************************
@@ -590,6 +588,24 @@ DGifGetCodeNext(GifFileType * GifFile,
     return GIF_OK;
 }
 
+/******************************************************************************
+ * Skip the LZW image sub-blocks without decoding any pixels.
+ * Called after DGifSetupDecompress has read the code size byte.
+ *****************************************************************************/
+static int
+DGifSkipImageData(GifFileType *GifFile)
+{
+    GifByteType *CodeBlock;
+    do {
+        if (DGifGetCodeNext(GifFile, &CodeBlock) == GIF_ERROR)
+        {
+            WARN("GIF is not properly terminated\n");
+            break;
+        }
+    } while (CodeBlock != NULL);
+    return GIF_OK;
+}
+
 /******************************************************************************
  * Setup the LZ decompression for this image:
  *****************************************************************************/
@@ -724,7 +740,9 @@ DGifDecompressLine(GifFileType * GifFile,
                 while (StackPtr != 0 && i < LineLen)
                     Line[i++] = Stack[--StackPtr];
             }
-            if (LastCode != NO_SUCH_CODE) {
+            if (LastCode != NO_SUCH_CODE &&
+                Private->RunningCode - 2 < (LZ_MAX_CODE + 1) &&
+                Prefix[Private->RunningCode - 2] == NO_SUCH_CODE) {
                 Prefix[Private->RunningCode - 2] = LastCode;
 
                 if (CrntCode == Private->RunningCode - 2) {
@@ -891,7 +909,11 @@ DGifSlurp(GifFileType * GifFile) {
               }
               if (DGifGetLine(GifFile, sp->RasterBits, ImageSize) ==
                   GIF_ERROR)
+              {
+                  free(sp->RasterBits);
+                  sp->RasterBits = NULL;
                   return (GIF_ERROR);
+              }
               if (temp_save.ExtensionBlocks) {
                   sp->Extensions.ExtensionBlocks = temp_save.ExtensionBlocks;
                   sp->Extensions.ExtensionBlockCount = temp_save.ExtensionBlockCount;
@@ -975,6 +997,165 @@ DGifSlurp(GifFileType * GifFile) {
     return (GIF_OK);
 }
 
+/******************************************************************************
+ * Like DGifSlurp() but skips pixel data of each frame.
+ * Only reads frame headers (ImageDesc, extension blocks) so it is fast.
+ * Use DGifDecodeFrame() to decode individual frames on demand.
+ *****************************************************************************/
+int
+DGifSlurpHeaders(GifFileType *GifFile)
+{
+    GifRecordType RecordType;
+    SavedImage *sp;
+    GifByteType *ExtData;
+    Extensions temp_save;
+
+    temp_save.ExtensionBlocks = NULL;
+    temp_save.ExtensionBlockCount = 0;
+
+    do {
+        if (DGifGetRecordType(GifFile, &RecordType) == GIF_ERROR)
+            return GIF_ERROR;
+
+        switch (RecordType) {
+          case IMAGE_DESC_RECORD_TYPE:
+              if (DGifGetImageDesc(GifFile) == GIF_ERROR)
+                  return GIF_ERROR;
+
+              sp = &GifFile->SavedImages[GifFile->ImageCount - 1];
+              /* GetFileOffset is past the code size byte read by DGifSetupDecompress
+               * inside DGifGetImageDesc, so subtract 1 to point at the code size byte
+               * itself, so DGifDecodeFrame can re-read it correctly after seeking. */
+              sp->LZWDataOffset = GetFileOffset(GifFile) - 1;
+
+              /* Skip LZW image sub-blocks without decoding */
+              if (DGifSkipImageData(GifFile) == GIF_ERROR)
+                  return GIF_ERROR;
+
+              /* Attach pending extension to this frame */
+              if (temp_save.ExtensionBlocks) {
+                  sp->Extensions.ExtensionBlocks = temp_save.ExtensionBlocks;
+                  sp->Extensions.ExtensionBlockCount = temp_save.ExtensionBlockCount;
+                  temp_save.ExtensionBlocks = NULL;
+                  temp_save.ExtensionBlockCount = 0;
+                  sp->Extensions.Function = sp->Extensions.ExtensionBlocks[0].Function;
+              }
+              break;
+
+          case EXTENSION_RECORD_TYPE:
+          {
+              int Function;
+              Extensions *Extensions;
+
+              if (DGifGetExtension(GifFile, &Function, &ExtData) == GIF_ERROR)
+                  return GIF_ERROR;
+
+              if (GifFile->ImageCount || Function == GRAPHICS_EXT_FUNC_CODE)
+                  Extensions = &temp_save;
+              else
+                  Extensions = &GifFile->Extensions;
+
+              Extensions->Function = Function;
+
+              if (ExtData)
+              {
+                  if (AddExtensionBlock(Extensions, ExtData[0], &ExtData[1]) == GIF_ERROR)
+                      return GIF_ERROR;
+              }
+              else
+              {
+                  if (AddExtensionBlock(Extensions, 0, NULL) == GIF_ERROR)
+                      return GIF_ERROR;
+              }
+
+              while (ExtData != NULL) {
+                  int Len;
+                  GifByteType *Data;
+
+                  if (DGifGetExtensionNext(GifFile, &ExtData) == GIF_ERROR)
+                      return GIF_ERROR;
+
+                  if (ExtData)
+                  {
+                      Len = ExtData[0];
+                      Data = &ExtData[1];
+                  }
+                  else
+                  {
+                      Len = 0;
+                      Data = NULL;
+                  }
+
+                  if (AppendExtensionBlock(Extensions, Len, Data) == GIF_ERROR)
+                      return GIF_ERROR;
+              }
+              break;
+          }
+
+          case TERMINATE_RECORD_TYPE:
+              break;
+
+          default:
+              break;
+        }
+    } while (RecordType != TERMINATE_RECORD_TYPE);
+
+    if (temp_save.ExtensionBlocks)
+        FreeExtension(&temp_save);
+
+    return GIF_OK;
+}
+
+/******************************************************************************
+ * Decode a specific frame on demand.
+ * Requires DGifSlurpHeaders() to have been called first to populate SavedImages.
+ * On success the frame's RasterBits are allocated and filled; subsequent calls
+ * return immediately if the frame is already decoded.
+ *****************************************************************************/
+int
+DGifDecodeFrame(GifFileType *GifFile, int frame)
+{
+    GifFilePrivateType *Private = GifFile->Private;
+    SavedImage *sp;
+    int ImageSize;
+
+    if (frame < 0 || frame >= GifFile->ImageCount)
+        return GIF_ERROR;
+
+    sp = &GifFile->SavedImages[frame];
+
+    /* Already decoded */
+    if (sp->RasterBits)
+        return GIF_OK;
+
+    /* Seek to this frame's LZW data in the stream */
+    if (GifFile->seekFunc)
+    {
+        ((SeekFunc)GifFile->seekFunc)(GifFile, sp->LZWDataOffset);
+        /* Reset the decoder's byte offset counter so subsequent READ() calls
+         * start from the correct position */
+        Private->Offset = sp->LZWDataOffset;
+    }
+
+    ImageSize = sp->ImageDesc.Width * sp->ImageDesc.Height;
+
+    /* Re-initialize LZW decompress state (reads the code size byte) */
+    Private->PixelCount = ImageSize;
+    DGifSetupDecompress(GifFile);
+
+    sp->RasterBits = malloc(ImageSize * sizeof(GifPixelType));
+    if (!sp->RasterBits)
+        return GIF_ERROR;
+
+    if (DGifGetLine(GifFile, sp->RasterBits, ImageSize) != GIF_OK)
+    {
+        free(sp->RasterBits);
+        sp->RasterBits = NULL;
+        return GIF_ERROR;
+    }
+    return GIF_OK;
+}
+
 /******************************************************************************
  * GifFileType constructor with user supplied input function (TVT)
  *****************************************************************************/
diff --git a/dlls/windowscodecs/ungif.h b/dlls/windowscodecs/ungif.h
index c402109bc673..4c91c4c4881c 100644
--- a/dlls/windowscodecs/ungif.h
+++ b/dlls/windowscodecs/ungif.h
@@ -124,6 +124,7 @@ typedef struct GifFileType {
     struct SavedImage *SavedImages; /* Use this to accumulate file state */
     void *UserData;             /* hook to attach user data (TVT) */
     void *Private;              /* Don't mess with this! */
+    void *seekFunc;             /* SeekFunc: seek to absolute byte offset for on-demand decoding */
 } GifFileType;
 
 typedef enum {
@@ -137,6 +138,9 @@ typedef enum {
 /* func type to read gif data from arbitrary sources (TVT) */
 typedef int (*InputFunc) (GifFileType *, GifByteType *, int);
 
+/* func type to seek to an absolute byte offset in the GIF data source */
+typedef void (*SeekFunc) (GifFileType *, int offset);
+
 /*  GIF89 extension function codes */
 
 #define COMMENT_EXT_FUNC_CODE     0xfe    /* comment */
@@ -171,8 +175,12 @@ int DGifCloseFile(GifFileType * GifFile);
 typedef struct SavedImage {
     GifImageDesc ImageDesc;
     int ImageDescOffset;
+    int LZWDataOffset;   /* byte offset to this frame's LZW sub-blocks in the stream */
     unsigned char *RasterBits;
     Extensions Extensions;
 } SavedImage;
 
+int DGifSlurpHeaders(GifFileType *GifFile);   /* scan frame headers only, skip pixel data */
+int DGifDecodeFrame(GifFileType *GifFile, int frame); /* on-demand decode of a specific frame */
+
 #endif /* _UNGIF_H_ */
diff --git a/dlls/wineandroid.drv/android.h b/dlls/wineandroid.drv/android.h
index cc558aa01f63..1d3df21d10ff 100644
--- a/dlls/wineandroid.drv/android.h
+++ b/dlls/wineandroid.drv/android.h
@@ -111,10 +111,11 @@ extern void ANDROID_DestroyWindow( HWND hwnd );
 extern BOOL ANDROID_ProcessEvents( DWORD mask );
 extern LRESULT ANDROID_DesktopWindowProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
 extern void ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent );
-extern void ANDROID_SetCapture( HWND hwnd, UINT flags );
+extern void ANDROID_SetCapture( HWND hwnd, UINT flags, HWND previous );
 extern UINT ANDROID_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp );
 extern LRESULT ANDROID_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp );
 extern BOOL ANDROID_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects );
+extern struct client_surface *ANDROID_CreateClientSurface( HWND hwnd, int pixel_format );
 extern BOOL ANDROID_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface );
 extern void ANDROID_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags,
                                       const struct window_rects *new_rects, struct window_surface *surface );
diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c
index df0cb2b72ec8..2dca7362a69a 100644
--- a/dlls/wineandroid.drv/init.c
+++ b/dlls/wineandroid.drv/init.c
@@ -322,6 +322,7 @@ static const struct user_driver_funcs android_drv_funcs =
     .pShowWindow = ANDROID_ShowWindow,
     .pWindowMessage = ANDROID_WindowMessage,
     .pWindowPosChanging = ANDROID_WindowPosChanging,
+    .pCreateClientSurface = ANDROID_CreateClientSurface,
     .pCreateWindowSurface = ANDROID_CreateWindowSurface,
     .pWindowPosChanged = ANDROID_WindowPosChanged,
     .pOpenGLInit = ANDROID_OpenGLInit,
diff --git a/dlls/wineandroid.drv/opengl.c b/dlls/wineandroid.drv/opengl.c
index 62b4fa7dd6c9..12bae7fca298 100644
--- a/dlls/wineandroid.drv/opengl.c
+++ b/dlls/wineandroid.drv/opengl.c
@@ -47,7 +47,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(android);
 
 static const struct egl_platform *egl;
 static const struct opengl_funcs *funcs;
-static const struct client_surface_funcs android_client_surface_funcs;
 static const struct opengl_drawable_funcs android_drawable_funcs;
 
 struct gl_drawable
@@ -82,11 +81,11 @@ void update_gl_drawable( HWND hwnd )
     NtUserRedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE | RDW_ERASE );
 }
 
-static BOOL android_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
+static BOOL android_surface_create( struct client_surface *client, int format, struct opengl_drawable **drawable )
 {
     struct gl_drawable *gl;
 
-    TRACE( "hwnd %p, format %d, drawable %p\n", hwnd, format, drawable );
+    TRACE( "hwnd %p, format %d, drawable %p\n", client->hwnd, format, drawable );
 
     if (*drawable)
     {
@@ -106,14 +105,10 @@ static BOOL android_surface_create( HWND hwnd, int format, struct opengl_drawabl
     {
         static const int attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
         EGLConfig config = egl_config_for_format( format );
-        struct client_surface *client;
-
-        if (!(client = client_surface_create( sizeof(*client), &android_client_surface_funcs, hwnd ))) return FALSE;
-        gl = opengl_drawable_create( sizeof(*gl), &android_drawable_funcs, format, client );
-        client_surface_release( client );
-        if (!gl) return FALSE;
 
+        if (!(gl = opengl_drawable_create( sizeof(*gl), &android_drawable_funcs, format, client ))) return FALSE;
         gl->window = get_client_window( client->hwnd );
+
         if (!has_client_surface( client->hwnd )) gl->base.surface = funcs->p_eglCreatePbufferSurface( egl->display, config, attribs );
         else gl->base.surface = funcs->p_eglCreateWindowSurface( egl->display, config, gl->window, NULL );
 
@@ -194,6 +189,11 @@ static const struct client_surface_funcs android_client_surface_funcs =
     .present = android_client_surface_present,
 };
 
+struct client_surface *ANDROID_CreateClientSurface( HWND hwnd, int pixel_format )
+{
+    return client_surface_create( sizeof(struct client_surface), &android_client_surface_funcs, hwnd );
+}
+
 static const struct opengl_drawable_funcs android_drawable_funcs =
 {
     .destroy = android_drawable_destroy,
diff --git a/dlls/wineandroid.drv/window.c b/dlls/wineandroid.drv/window.c
index db9294ee0d1f..3cc971558ff6 100644
--- a/dlls/wineandroid.drv/window.c
+++ b/dlls/wineandroid.drv/window.c
@@ -1110,7 +1110,7 @@ void ANDROID_SetParent( HWND hwnd, HWND parent, HWND old_parent )
 /***********************************************************************
  *           ANDROID_SetCapture
  */
-void ANDROID_SetCapture( HWND hwnd, UINT flags )
+void ANDROID_SetCapture( HWND hwnd, UINT flags, HWND previous )
 {
     if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
     ioctl_set_capture( hwnd );
diff --git a/dlls/winebth.sys/winebth.c b/dlls/winebth.sys/winebth.c
index fccac50bdefe..dd25c494f752 100644
--- a/dlls/winebth.sys/winebth.c
+++ b/dlls/winebth.sys/winebth.c
@@ -1055,7 +1055,8 @@ static void bluetooth_radio_add_remote_device( struct winebluetooth_watcher_even
             }
 
             list_add_tail( &radio->remote_devices, &ext->remote_device.entry );
-            IoInvalidateDeviceRelations( radio->device_obj, BusRelations );
+            if (radio->started)
+                IoInvalidateDeviceRelations( radio->device_obj, BusRelations );
             break;
         }
     }
@@ -1113,8 +1114,9 @@ static void bluetooth_radio_remove_remote_device( struct winebluetooth_watcher_e
                         ExFreePool( notification );
                     }
                 }
+                if (radio->started)
+                    IoInvalidateDeviceRelations( radio->device_obj, BusRelations );
                 LeaveCriticalSection( &device_list_cs );
-                IoInvalidateDeviceRelations( radio->device_obj, BusRelations );
                 winebluetooth_device_free( event.device );
                 return;
             }
@@ -1367,11 +1369,12 @@ static void bluetooth_device_add_gatt_service( struct winebluetooth_watcher_even
                 bluetooth_device_enable_le_iface( device );
 
                 list_add_tail( &device->gatt_services, &ext->gatt_service.entry );
+                if (device->started)
+                    IoInvalidateDeviceRelations( device->device_obj, BusRelations );
                 LeaveCriticalSection( &device->props_cs );
 
                 LeaveCriticalSection( &device_list_cs );
                 winebluetooth_device_free( event.device );
-                IoInvalidateDeviceRelations( device->device_obj, BusRelations );
                 return;
             }
         }
@@ -1408,9 +1411,10 @@ static void bluetooth_gatt_service_remove( winebluetooth_gatt_service_t service
                 {
                     list_remove( &svc->entry );
                     svc->removed = 1;
+                    if (device->started)
+                        IoInvalidateDeviceRelations( device->device_obj, BusRelations );
                     LeaveCriticalSection( &device->props_cs );
                     LeaveCriticalSection( &device_list_cs );
-                    IoInvalidateDeviceRelations( device->device_obj, BusRelations );
                     winebluetooth_gatt_service_free( service );
                     return;
                 }
@@ -2122,6 +2126,7 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct
     case IRP_MN_START_DEVICE:
     {
         BLUETOOTH_ADDRESS adapter_addr;
+        BOOL needs_invalidate;
 
         EnterCriticalSection( &device_list_cs );
         adapter_addr = ext->radio->props.address;
@@ -2134,7 +2139,10 @@ static NTSTATUS WINAPI remote_device_pdo_pnp( DEVICE_OBJECT *device_obj, struct
             IoSetDeviceInterfaceState( &ext->bthle_symlink_name, TRUE );
         ext->started = TRUE;
         bluetooth_device_set_properties( ext, adapter_addr.rgBytes, &ext->props, ext->props_mask );
+        needs_invalidate = !list_empty( &ext->gatt_services );
         LeaveCriticalSection( &ext->props_cs );
+        if (needs_invalidate)
+            IoInvalidateDeviceRelations( device_obj, BusRelations );
         ret = STATUS_SUCCESS;
         break;
     }
@@ -2225,9 +2233,13 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot
             break;
         }
         case IRP_MN_START_DEVICE:
+        {
+            BOOL needs_invalidate;
+
             EnterCriticalSection( &device_list_cs );
             bluetooth_radio_set_properties( device_obj, device->props_mask, &device->props );
             device->started = TRUE;
+            needs_invalidate = !list_empty( &device->remote_devices );
             LeaveCriticalSection( &device_list_cs );
 
             if (IoRegisterDeviceInterface( device_obj, &GUID_BTHPORT_DEVICE_INTERFACE, NULL,
@@ -2237,8 +2249,11 @@ static NTSTATUS WINAPI radio_pdo_pnp( DEVICE_OBJECT *device_obj, struct bluetoot
             if (IoRegisterDeviceInterface( device_obj, &GUID_BLUETOOTH_RADIO_INTERFACE, NULL,
                                           &device->bthradio_symlink_name ) == STATUS_SUCCESS)
                 IoSetDeviceInterfaceState( &device->bthradio_symlink_name, TRUE );
+            if (needs_invalidate)
+                IoInvalidateDeviceRelations( device_obj, BusRelations );
             ret = STATUS_SUCCESS;
             break;
+        }
         case IRP_MN_REMOVE_DEVICE:
             assert( device->removed );
             EnterCriticalSection( &device_list_cs );
diff --git a/dlls/winebus.sys/main.c b/dlls/winebus.sys/main.c
index 0132297a4a6c..a6227be99087 100644
--- a/dlls/winebus.sys/main.c
+++ b/dlls/winebus.sys/main.c
@@ -47,9 +47,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(hid);
 
 static DRIVER_OBJECT *driver_obj;
 
-static DEVICE_OBJECT *mouse_obj;
-static DEVICE_OBJECT *keyboard_obj;
-
 /* The root-enumerated device stack. */
 static DEVICE_OBJECT *bus_pdo;
 static DEVICE_OBJECT *bus_fdo;
@@ -813,7 +810,7 @@ static void mouse_device_create(void)
     struct device_create_params params = {{0}};
 
     if (winebus_call(mouse_create, &params)) return;
-    mouse_obj = bus_create_hid_device(&params.desc, params.device);
+    bus_create_hid_device(&params.desc, params.device);
     IoInvalidateDeviceRelations(bus_pdo, BusRelations);
 }
 
@@ -822,7 +819,7 @@ static void keyboard_device_create(void)
     struct device_create_params params = {{0}};
 
     if (winebus_call(keyboard_create, &params)) return;
-    keyboard_obj = bus_create_hid_device(&params.desc, params.device);
+    bus_create_hid_device(&params.desc, params.device);
     IoInvalidateDeviceRelations(bus_pdo, BusRelations);
 }
 
diff --git a/dlls/wined3d/wined3d.spec b/dlls/wined3d/wined3d.spec
index e08dd0895212..735957c8777d 100644
--- a/dlls/wined3d/wined3d.spec
+++ b/dlls/wined3d/wined3d.spec
@@ -388,6 +388,7 @@
 @ cdecl vkd3d_shader_free_messages(ptr)
 @ cdecl vkd3d_shader_free_root_signature(ptr)
 @ cdecl vkd3d_shader_free_scan_descriptor_info(ptr)
+@ cdecl vkd3d_shader_free_scan_signature_info(ptr)
 @ cdecl vkd3d_shader_free_shader_code(ptr)
 @ cdecl vkd3d_shader_free_shader_signature(ptr)
 @ cdecl vkd3d_shader_get_supported_source_types(ptr)
diff --git a/dlls/winegstreamer/Makefile.in b/dlls/winegstreamer/Makefile.in
index 1c7a7b417c13..12907f90b2f9 100644
--- a/dlls/winegstreamer/Makefile.in
+++ b/dlls/winegstreamer/Makefile.in
@@ -1,7 +1,7 @@
 MODULE    = winegstreamer.dll
 UNIXLIB   = winegstreamer.so
 IMPORTLIB = winegstreamer
-IMPORTS   = strmbase ole32 oleaut32 msdmo msvcrt user32
+IMPORTS   = strmbase ole32 oleaut32 msdmo user32
 DELAYIMPORTS = mfplat mf
 UNIX_CFLAGS  = $(GSTREAMER_CFLAGS)
 UNIX_LIBS    = $(GSTREAMER_LIBS) $(PTHREAD_LIBS)
@@ -11,19 +11,16 @@ VER_OLESELFREGISTER     = 1
 
 SOURCES = \
 	aac_decoder.c \
-	color_convert.c \
 	main.c \
 	media_sink.c \
 	media_source.c \
 	mfplat.c \
 	quartz_parser.c \
 	quartz_transform.c \
-	resampler.c \
 	rsrc.rc \
 	unixlib.c \
 	video_decoder.c \
 	video_encoder.c \
-	video_processor.c \
 	wg_allocator.c \
 	wg_format.c \
 	wg_media_type.c \
diff --git a/dlls/winegstreamer/color_convert.c b/dlls/winegstreamer/color_convert.c
deleted file mode 100644
index 5d9e5f1c0a96..000000000000
--- a/dlls/winegstreamer/color_convert.c
+++ /dev/null
@@ -1,1056 +0,0 @@
-/* Copyright 2022 Rémi Bernon for CodeWeavers
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "gst_private.h"
-
-#include "mfapi.h"
-#include "mferror.h"
-#include "mfobjects.h"
-#include "mftransform.h"
-#include "wmcodecdsp.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
-
-static const GUID *const input_types[] =
-{
-    &MFVideoFormat_YV12,
-    &MFVideoFormat_YUY2,
-    &MFVideoFormat_UYVY,
-    &MFVideoFormat_AYUV,
-    &MFVideoFormat_NV12,
-    &MFVideoFormat_RGB32,
-    &MFVideoFormat_RGB565,
-    &MFVideoFormat_I420,
-    &MFVideoFormat_IYUV,
-    &MFVideoFormat_YVYU,
-    &MFVideoFormat_RGB24,
-    &MFVideoFormat_RGB555,
-    &MEDIASUBTYPE_RGB8,
-    &MEDIASUBTYPE_V216,
-    &MEDIASUBTYPE_V410,
-    &MFVideoFormat_NV11,
-    &MFVideoFormat_Y41P,
-    &MFVideoFormat_Y41T,
-    &MFVideoFormat_Y42T,
-    &MFVideoFormat_YVU9,
-};
-static const GUID *const output_types[] =
-{
-    &MFVideoFormat_YV12,
-    &MFVideoFormat_YUY2,
-    &MFVideoFormat_UYVY,
-    &MFVideoFormat_AYUV,
-    &MFVideoFormat_NV12,
-    &MFVideoFormat_RGB32,
-    &MFVideoFormat_RGB565,
-    &MFVideoFormat_I420,
-    &MFVideoFormat_IYUV,
-    &MFVideoFormat_YVYU,
-    &MFVideoFormat_RGB24,
-    &MFVideoFormat_RGB555,
-    &MEDIASUBTYPE_RGB8,
-    &MEDIASUBTYPE_V216,
-    &MEDIASUBTYPE_V410,
-    &MFVideoFormat_NV11,
-};
-
-struct color_convert
-{
-    IUnknown IUnknown_inner;
-    IMFTransform IMFTransform_iface;
-    IMediaObject IMediaObject_iface;
-    IPropertyBag IPropertyBag_iface;
-    IPropertyStore IPropertyStore_iface;
-    IUnknown *outer;
-    LONG refcount;
-
-    IMFMediaType *input_type;
-    MFT_INPUT_STREAM_INFO input_info;
-    IMFMediaType *output_type;
-    MFT_OUTPUT_STREAM_INFO output_info;
-
-    wg_transform_t wg_transform;
-    struct wg_sample_queue *wg_sample_queue;
-};
-
-static inline struct color_convert *impl_from_IUnknown(IUnknown *iface)
-{
-    return CONTAINING_RECORD(iface, struct color_convert, IUnknown_inner);
-}
-
-static void update_video_aperture(MFVideoInfo *input_info, MFVideoInfo *output_info)
-{
-    static const MFVideoArea empty_area = {0};
-
-    /* Tests show that the color converter ignores aperture entirely, probably a side
-     * effect of an internal conversion to VIDEOINFOHEADER2, as the component is also
-     * exposing a IMediaObject interface, and designed for dshow.
-     */
-
-    input_info->GeometricAperture = empty_area;
-    input_info->MinimumDisplayAperture = empty_area;
-    input_info->PanScanAperture = empty_area;
-
-    output_info->GeometricAperture = empty_area;
-    output_info->MinimumDisplayAperture = empty_area;
-    output_info->PanScanAperture = empty_area;
-}
-
-static HRESULT normalize_media_types(IMFMediaType **input_type, IMFMediaType **output_type)
-{
-    MFVIDEOFORMAT *input_format, *output_format;
-    UINT32 size;
-    HRESULT hr;
-
-    if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*input_type, &input_format, &size)))
-        return hr;
-    if (FAILED(hr = MFCreateMFVideoFormatFromMFMediaType(*output_type, &output_format, &size)))
-    {
-        CoTaskMemFree(input_format);
-        return hr;
-    }
-
-    update_video_aperture(&input_format->videoInfo, &output_format->videoInfo);
-
-    if (FAILED(hr = MFCreateVideoMediaType(input_format, (IMFVideoMediaType **)input_type)))
-        goto done;
-    if (FAILED(hr = MFCreateVideoMediaType(output_format, (IMFVideoMediaType **)output_type)))
-    {
-        IMFMediaType_Release(*input_type);
-        *input_type = NULL;
-    }
-
-done:
-    CoTaskMemFree(input_format);
-    CoTaskMemFree(output_format);
-    return hr;
-}
-
-static HRESULT try_create_wg_transform(struct color_convert *impl)
-{
-    IMFMediaType *input_type = impl->input_type, *output_type = impl->output_type;
-    struct wg_transform_attrs attrs = {0};
-    HRESULT hr;
-
-    if (impl->wg_transform)
-    {
-        wg_transform_destroy(impl->wg_transform);
-        impl->wg_transform = 0;
-    }
-
-    if (FAILED(hr = normalize_media_types(&input_type, &output_type)))
-        return hr;
-    hr = wg_transform_create_mf(input_type, output_type, &attrs, &impl->wg_transform);
-    IMFMediaType_Release(output_type);
-    IMFMediaType_Release(input_type);
-
-    return hr;
-}
-
-static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out)
-{
-    struct color_convert *impl = impl_from_IUnknown(iface);
-
-    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
-
-    if (IsEqualGUID(iid, &IID_IUnknown))
-        *out = &impl->IUnknown_inner;
-    else if (IsEqualGUID(iid, &IID_IMFTransform))
-        *out = &impl->IMFTransform_iface;
-    else if (IsEqualGUID(iid, &IID_IMediaObject))
-        *out = &impl->IMediaObject_iface;
-    else if (IsEqualIID(iid, &IID_IPropertyBag))
-        *out = &impl->IPropertyBag_iface;
-    else if (IsEqualIID(iid, &IID_IPropertyStore))
-        *out = &impl->IPropertyStore_iface;
-    else
-    {
-        *out = NULL;
-        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown *)*out);
-    return S_OK;
-}
-
-static ULONG WINAPI unknown_AddRef(IUnknown *iface)
-{
-    struct color_convert *impl = impl_from_IUnknown(iface);
-    ULONG refcount = InterlockedIncrement(&impl->refcount);
-
-    TRACE("iface %p increasing refcount to %lu.\n", iface, refcount);
-
-    return refcount;
-}
-
-static ULONG WINAPI unknown_Release(IUnknown *iface)
-{
-    struct color_convert *impl = impl_from_IUnknown(iface);
-    ULONG refcount = InterlockedDecrement(&impl->refcount);
-
-    TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount);
-
-    if (!refcount)
-    {
-        if (impl->wg_transform)
-            wg_transform_destroy(impl->wg_transform);
-        if (impl->input_type)
-            IMFMediaType_Release(impl->input_type);
-        if (impl->output_type)
-            IMFMediaType_Release(impl->output_type);
-
-        wg_sample_queue_destroy(impl->wg_sample_queue);
-        free(impl);
-    }
-
-    return refcount;
-}
-
-static const IUnknownVtbl unknown_vtbl =
-{
-    unknown_QueryInterface,
-    unknown_AddRef,
-    unknown_Release,
-};
-
-static struct color_convert *impl_from_IMFTransform(IMFTransform *iface)
-{
-    return CONTAINING_RECORD(iface, struct color_convert, IMFTransform_iface);
-}
-
-static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI transform_AddRef(IMFTransform *iface)
-{
-    return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer);
-}
-
-static ULONG WINAPI transform_Release(IMFTransform *iface)
-{
-    return IUnknown_Release(impl_from_IMFTransform(iface)->outer);
-}
-
-static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
-        DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
-{
-    TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
-            iface, input_minimum, input_maximum, output_minimum, output_maximum);
-    *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
-{
-    TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
-    *inputs = *outputs = 1;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
-        DWORD output_size, DWORD *outputs)
-{
-    TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
-            input_size, inputs, output_size, outputs);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
-
-    if (!impl->input_type || !impl->output_type)
-    {
-        memset(info, 0, sizeof(*info));
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-    }
-
-    *info = impl->input_info;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
-
-    if (!impl->input_type || !impl->output_type)
-    {
-        memset(info, 0, sizeof(*info));
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-    }
-
-    *info = impl->output_info;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
-{
-    TRACE("iface %p, attributes %p.\n", iface, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
-{
-    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
-{
-    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
-{
-    TRACE("iface %p, id %#lx.\n", iface, id);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
-{
-    TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
-        IMFMediaType **type)
-{
-    IMFMediaType *media_type;
-    const GUID *subtype;
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
-
-    *type = NULL;
-
-    if (index >= ARRAY_SIZE(input_types))
-        return MF_E_NO_MORE_TYPES;
-    subtype = input_types[index];
-
-    if (FAILED(hr = MFCreateMediaType(&media_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1)))
-        goto done;
-
-    IMFMediaType_AddRef((*type = media_type));
-
-done:
-    IMFMediaType_Release(media_type);
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
-        IMFMediaType **type)
-{
-    IMFMediaType *media_type;
-    const GUID *subtype;
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
-
-    *type = NULL;
-
-    if (index >= ARRAY_SIZE(output_types))
-        return MF_E_NO_MORE_TYPES;
-    subtype = output_types[index];
-
-    if (FAILED(hr = MFCreateMediaType(&media_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Video)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_FIXED_SIZE_SAMPLES, 1)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1)))
-        goto done;
-
-    IMFMediaType_AddRef((*type = media_type));
-
-done:
-    IMFMediaType_Release(media_type);
-    return hr;
-}
-
-static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-    GUID major, subtype;
-    UINT64 frame_size;
-    UINT32 stride;
-    HRESULT hr;
-    ULONG i;
-
-    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
-
-    if (!type)
-    {
-        if (impl->input_type)
-        {
-            IMFMediaType_Release(impl->input_type);
-            impl->input_type = NULL;
-        }
-        if (impl->wg_transform)
-        {
-            wg_transform_destroy(impl->wg_transform);
-            impl->wg_transform = 0;
-        }
-
-        return S_OK;
-    }
-
-    if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
-            FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
-        return MF_E_ATTRIBUTENOTFOUND;
-
-    if (!IsEqualGUID(&major, &MFMediaType_Video)
-            || IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
-        return E_INVALIDARG;
-
-    for (i = 0; i < ARRAY_SIZE(input_types); ++i)
-        if (IsEqualGUID(&subtype, input_types[i]))
-            break;
-    if (i == ARRAY_SIZE(input_types))
-        return MF_E_INVALIDMEDIATYPE;
-    if (flags & MFT_SET_TYPE_TEST_ONLY)
-        return S_OK;
-
-    if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->input_type)))
-    {
-        IMFMediaType_Release(impl->input_type);
-        impl->input_type = NULL;
-    }
-    if (FAILED(IMFMediaType_GetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, &stride)))
-    {
-        if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride)))
-        {
-            IMFMediaType_Release(impl->input_type);
-            impl->input_type = NULL;
-        }
-        if (FAILED(hr = IMFMediaType_SetUINT32(impl->input_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride))))
-        {
-            IMFMediaType_Release(impl->input_type);
-            impl->input_type = NULL;
-        }
-    }
-
-    if (impl->output_type && FAILED(hr = try_create_wg_transform(impl)))
-    {
-        IMFMediaType_Release(impl->input_type);
-        impl->input_type = NULL;
-    }
-
-    if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size,
-            (UINT32 *)&impl->input_info.cbSize)))
-        impl->input_info.cbSize = 0;
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-    GUID major, subtype;
-    UINT64 frame_size;
-    UINT32 stride;
-    HRESULT hr;
-    ULONG i;
-
-    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
-
-    if (!type)
-    {
-        if (impl->output_type)
-        {
-            IMFMediaType_Release(impl->output_type);
-            impl->output_type = NULL;
-        }
-        if (impl->wg_transform)
-        {
-            wg_transform_destroy(impl->wg_transform);
-            impl->wg_transform = 0;
-        }
-
-        return S_OK;
-    }
-
-    if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
-            FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
-        return MF_E_ATTRIBUTENOTFOUND;
-
-    if (!IsEqualGUID(&major, &MFMediaType_Video)
-            || IMFMediaType_GetUINT64(type, &MF_MT_FRAME_SIZE, &frame_size))
-        return E_INVALIDARG;
-
-    for (i = 0; i < ARRAY_SIZE(output_types); ++i)
-        if (IsEqualGUID(&subtype, output_types[i]))
-            break;
-    if (i == ARRAY_SIZE(output_types))
-        return MF_E_INVALIDMEDIATYPE;
-    if (flags & MFT_SET_TYPE_TEST_ONLY)
-        return S_OK;
-
-    if (!impl->output_type && FAILED(hr = MFCreateMediaType(&impl->output_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->output_type)))
-    {
-        IMFMediaType_Release(impl->output_type);
-        impl->output_type = NULL;
-    }
-    if (FAILED(IMFMediaType_GetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, &stride)))
-    {
-        if (FAILED(hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, frame_size >> 32, (LONG *)&stride)))
-        {
-            IMFMediaType_Release(impl->output_type);
-            impl->output_type = NULL;
-        }
-        if (FAILED(hr = IMFMediaType_SetUINT32(impl->output_type, &MF_MT_DEFAULT_STRIDE, abs((INT32)stride))))
-        {
-            IMFMediaType_Release(impl->output_type);
-            impl->output_type = NULL;
-        }
-    }
-
-    if (impl->input_type && FAILED(hr = try_create_wg_transform(impl)))
-    {
-        IMFMediaType_Release(impl->output_type);
-        impl->output_type = NULL;
-    }
-
-    if (FAILED(hr) || FAILED(MFCalculateImageSize(&subtype, frame_size >> 32, (UINT32)frame_size,
-            (UINT32 *)&impl->output_info.cbSize)))
-        impl->output_info.cbSize = 0;
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
-
-    if (id != 0)
-        return MF_E_INVALIDSTREAMNUMBER;
-
-    if (!impl->input_type)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    if (FAILED(hr = MFCreateMediaType(type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(impl->input_type, (IMFAttributes *)*type)))
-        IMFMediaType_Release(*type);
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
-
-    if (id != 0)
-        return MF_E_INVALIDSTREAMNUMBER;
-
-    if (!impl->output_type)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    if (FAILED(hr = MFCreateMediaType(type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(impl->output_type, (IMFAttributes *)*type)))
-        IMFMediaType_Release(*type);
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
-{
-    FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
-{
-    FIXME("iface %p, flags %p stub!\n", iface, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
-{
-    TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
-{
-    FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
-{
-    FIXME("iface %p, message %#x, param %#Ix stub!\n", iface, message, param);
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
-
-    if (!impl->wg_transform)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue);
-}
-
-static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
-        MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
-{
-    struct color_convert *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
-
-    if (count != 1)
-        return E_INVALIDARG;
-
-    if (!impl->wg_transform)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    *status = samples->dwStatus = 0;
-    if (!samples->pSample)
-        return E_INVALIDARG;
-
-    if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample,
-            impl->output_info.cbSize, &samples->dwStatus, NULL)))
-        wg_sample_queue_flush(impl->wg_sample_queue, false);
-
-    return hr;
-}
-
-static const IMFTransformVtbl transform_vtbl =
-{
-    transform_QueryInterface,
-    transform_AddRef,
-    transform_Release,
-    transform_GetStreamLimits,
-    transform_GetStreamCount,
-    transform_GetStreamIDs,
-    transform_GetInputStreamInfo,
-    transform_GetOutputStreamInfo,
-    transform_GetAttributes,
-    transform_GetInputStreamAttributes,
-    transform_GetOutputStreamAttributes,
-    transform_DeleteInputStream,
-    transform_AddInputStreams,
-    transform_GetInputAvailableType,
-    transform_GetOutputAvailableType,
-    transform_SetInputType,
-    transform_SetOutputType,
-    transform_GetInputCurrentType,
-    transform_GetOutputCurrentType,
-    transform_GetInputStatus,
-    transform_GetOutputStatus,
-    transform_SetOutputBounds,
-    transform_ProcessEvent,
-    transform_ProcessMessage,
-    transform_ProcessInput,
-    transform_ProcessOutput,
-};
-
-static inline struct color_convert *impl_from_IMediaObject(IMediaObject *iface)
-{
-    return CONTAINING_RECORD(iface, struct color_convert, IMediaObject_iface);
-}
-
-static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj)
-{
-    return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj);
-}
-
-static ULONG WINAPI media_object_AddRef(IMediaObject *iface)
-{
-    return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer);
-}
-
-static ULONG WINAPI media_object_Release(IMediaObject *iface)
-{
-    return IUnknown_Release(impl_from_IMediaObject(iface)->outer);
-}
-
-static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output)
-{
-    FIXME("iface %p, input %p, output %p stub!\n", iface, input, output);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index,
-        DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index,
-        DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index,
-        const DMO_MEDIA_TYPE *type, DWORD flags)
-{
-    FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index,
-        const DMO_MEDIA_TYPE *type, DWORD flags)
-{
-    FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size,
-        DWORD *lookahead, DWORD *alignment)
-{
-    FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size,
-            lookahead, alignment);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
-{
-    FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
-{
-    FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency)
-{
-    FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency));
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Flush(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index)
-{
-    FIXME("iface %p, index %lu stub!\n", iface, index);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index,
-        IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
-{
-    FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface,
-            index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength));
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count,
-        DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
-{
-    FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
-{
-    FIXME("iface %p, lock %ld stub!\n", iface, lock);
-    return E_NOTIMPL;
-}
-
-static const IMediaObjectVtbl media_object_vtbl =
-{
-    media_object_QueryInterface,
-    media_object_AddRef,
-    media_object_Release,
-    media_object_GetStreamCount,
-    media_object_GetInputStreamInfo,
-    media_object_GetOutputStreamInfo,
-    media_object_GetInputType,
-    media_object_GetOutputType,
-    media_object_SetInputType,
-    media_object_SetOutputType,
-    media_object_GetInputCurrentType,
-    media_object_GetOutputCurrentType,
-    media_object_GetInputSizeInfo,
-    media_object_GetOutputSizeInfo,
-    media_object_GetInputMaxLatency,
-    media_object_SetInputMaxLatency,
-    media_object_Flush,
-    media_object_Discontinuity,
-    media_object_AllocateStreamingResources,
-    media_object_FreeStreamingResources,
-    media_object_GetInputStatus,
-    media_object_ProcessInput,
-    media_object_ProcessOutput,
-    media_object_Lock,
-};
-
-static inline struct color_convert *impl_from_IPropertyBag(IPropertyBag *iface)
-{
-    return CONTAINING_RECORD(iface, struct color_convert, IPropertyBag_iface);
-}
-
-static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface)
-{
-    return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer);
-}
-
-static ULONG WINAPI property_bag_Release(IPropertyBag *iface)
-{
-    return IUnknown_Release(impl_from_IPropertyBag(iface)->outer);
-}
-
-static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value,
-        IErrorLog *error_log)
-{
-    FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value)
-{
-    FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value);
-    return S_OK;
-}
-
-static const IPropertyBagVtbl property_bag_vtbl =
-{
-    property_bag_QueryInterface,
-    property_bag_AddRef,
-    property_bag_Release,
-    property_bag_Read,
-    property_bag_Write,
-};
-
-static inline struct color_convert *impl_from_IPropertyStore(IPropertyStore *iface)
-{
-    return CONTAINING_RECORD(iface, struct color_convert, IPropertyStore_iface);
-}
-
-static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI property_store_AddRef(IPropertyStore *iface)
-{
-    return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer);
-}
-
-static ULONG WINAPI property_store_Release(IPropertyStore *iface)
-{
-    return IUnknown_Release(impl_from_IPropertyStore(iface)->outer);
-}
-
-static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count)
-{
-    FIXME("iface %p, count %p stub!\n", iface, count);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key)
-{
-    FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
-{
-    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
-{
-    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_Commit(IPropertyStore *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static const IPropertyStoreVtbl property_store_vtbl =
-{
-    property_store_QueryInterface,
-    property_store_AddRef,
-    property_store_Release,
-    property_store_GetCount,
-    property_store_GetAt,
-    property_store_GetValue,
-    property_store_SetValue,
-    property_store_Commit,
-};
-
-HRESULT color_convert_create(IUnknown *outer, IUnknown **out)
-{
-    const MFVIDEOFORMAT input_format =
-    {
-        .dwSize = sizeof(MFVIDEOFORMAT),
-        .videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
-        .guidFormat = MFVideoFormat_I420,
-    };
-    const MFVIDEOFORMAT output_format =
-    {
-        .dwSize = sizeof(MFVIDEOFORMAT),
-        .videoInfo = {.dwWidth = 1920, .dwHeight = 1080},
-        .guidFormat = MFVideoFormat_NV12,
-    };
-    struct color_convert *impl;
-    HRESULT hr;
-
-    TRACE("outer %p, out %p.\n", outer, out);
-
-    if (FAILED(hr = check_video_transform_support(&input_format, &output_format)))
-    {
-        ERR_(winediag)("GStreamer doesn't support video conversion, please install appropriate plugins.\n");
-        return hr;
-    }
-
-    if (!(impl = calloc(1, sizeof(*impl))))
-        return E_OUTOFMEMORY;
-
-    if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue)))
-    {
-        free(impl);
-        return hr;
-    }
-
-    impl->IUnknown_inner.lpVtbl = &unknown_vtbl;
-    impl->IMFTransform_iface.lpVtbl = &transform_vtbl;
-    impl->IMediaObject_iface.lpVtbl = &media_object_vtbl;
-    impl->IPropertyBag_iface.lpVtbl = &property_bag_vtbl;
-    impl->IPropertyStore_iface.lpVtbl = &property_store_vtbl;
-    impl->refcount = 1;
-    impl->outer = outer ? outer : &impl->IUnknown_inner;
-
-    impl->input_info.cbAlignment = 1;
-    impl->output_info.cbAlignment = 1;
-
-    *out = &impl->IUnknown_inner;
-    TRACE("Created %p\n", *out);
-    return S_OK;
-}
-
-HRESULT WINAPI winegstreamer_create_color_converter(IMFTransform **out)
-{
-    IUnknown *unknown;
-    HRESULT hr;
-
-    TRACE("out %p.\n", out);
-
-    if (!init_gstreamer())
-        return E_FAIL;
-
-    if (FAILED(hr = color_convert_create(NULL, &unknown)))
-        return hr;
-
-    return IUnknown_QueryInterface(unknown, &IID_IMFTransform, (void**)out);
-}
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 431e79302086..7a5c2f3f4b0f 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -138,8 +138,6 @@ HRESULT mpeg_splitter_create(IUnknown *outer, IUnknown **out);
 HRESULT wave_parser_create(IUnknown *outer, IUnknown **out);
 HRESULT wma_decoder_create(IUnknown *outer, IUnknown **out);
 HRESULT wmv_decoder_create(IUnknown *outer, IUnknown **out);
-HRESULT resampler_create(IUnknown *outer, IUnknown **out);
-HRESULT color_convert_create(IUnknown *outer, IUnknown **out);
 HRESULT mp3_sink_class_factory_create(IUnknown *outer, IUnknown **out);
 HRESULT mpeg4_sink_class_factory_create(IUnknown *outer, IUnknown **out);
 
@@ -183,8 +181,6 @@ bool wg_video_format_is_rgb(enum wg_video_format format);
 
 HRESULT aac_decoder_create(REFIID riid, void **ret);
 HRESULT h264_decoder_create(REFIID riid, void **ret);
-HRESULT video_processor_create(REFIID riid, void **ret);
-
 HRESULT h264_encoder_create(REFIID riid, void **ret);
 
 extern const GUID MFAudioFormat_RAW_AAC;
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index c7893f710263..6a8bd4b6413b 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -979,20 +979,16 @@ static struct class_factory mpeg_splitter_cf = {{&class_factory_vtbl}, mpeg_spli
 static struct class_factory wave_parser_cf = {{&class_factory_vtbl}, wave_parser_create};
 static struct class_factory wma_decoder_cf = {{&class_factory_vtbl}, wma_decoder_create};
 static struct class_factory wmv_decoder_cf = {{&class_factory_vtbl}, wmv_decoder_create};
-static struct class_factory resampler_cf = {{&class_factory_vtbl}, resampler_create};
-static struct class_factory color_convert_cf = {{&class_factory_vtbl}, color_convert_create};
 static struct class_factory mp3_sink_class_factory_cf = {{&class_factory_vtbl}, mp3_sink_class_factory_create};
 static struct class_factory mpeg4_sink_class_factory_cf = {{&class_factory_vtbl}, mpeg4_sink_class_factory_create};
 
 HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
 {
     static const GUID CLSID_wg_avi_splitter = {0x272bfbfb,0x50d0,0x4078,{0xb6,0x00,0x1e,0x95,0x9c,0x30,0x13,0x37}};
-    static const GUID CLSID_wg_color_converter = {0xf47e2da5,0xe370,0x47b7,{0x90,0x3a,0x07,0x8d,0xdd,0x45,0xa5,0xcc}};
     static const GUID CLSID_wg_mp3_sink_factory = {0x1f302877,0xaaab,0x40a3,{0xb9,0xe0,0x9f,0x48,0xda,0xf3,0x5b,0xc8}};
     static const GUID CLSID_wg_mpeg4_sink_factory = {0x5d5407d9,0xc6ca,0x4770,{0xa7,0xcc,0x27,0xc0,0xcb,0x8a,0x76,0x27}};
     static const GUID CLSID_wg_mpeg_audio_decoder = {0xc9f285f8,0x4380,0x4121,{0x97,0x1f,0x49,0xa9,0x53,0x16,0xc2,0x7b}};
     static const GUID CLSID_wg_mpeg_video_decoder = {0x5ed2e5f6,0xbf3e,0x4180,{0x83,0xa4,0x48,0x47,0xcc,0x5b,0x4e,0xa3}};
-    static const GUID CLSID_wg_resampler = {0x92f35e78,0x15a5,0x486b,{0x88,0x8e,0x57,0x5f,0x99,0x65,0x1c,0xe2}};
     static const GUID CLSID_wg_wma_decoder = {0x5b4d4e54,0x0620,0x4cf9,{0x94,0xae,0x78,0x23,0x96,0x5c,0x28,0xb6}};
     static const GUID CLSID_wg_wmv_decoder = {0x62ee5ddb,0x4f52,0x48e2,{0x89,0x28,0x78,0x7b,0x02,0x53,0xa0,0xbc}};
     static const GUID CLSID_wg_mp3_decoder = {0x84cd8e3e,0xb221,0x434a,{0x88,0x82,0x9d,0x6c,0x8d,0xf4,0x90,0xe1}};
@@ -1027,10 +1023,6 @@ HRESULT WINAPI DllGetClassObject(REFCLSID clsid, REFIID iid, void **out)
         factory = &wma_decoder_cf;
     else if (IsEqualGUID(clsid, &CLSID_wg_wmv_decoder))
         factory = &wmv_decoder_cf;
-    else if (IsEqualGUID(clsid, &CLSID_wg_resampler))
-        factory = &resampler_cf;
-    else if (IsEqualGUID(clsid, &CLSID_wg_color_converter))
-        factory = &color_convert_cf;
     else if (IsEqualGUID(clsid, &CLSID_wg_mp3_sink_factory))
         factory = &mp3_sink_class_factory_cf;
     else if (IsEqualGUID(clsid, &CLSID_wg_mpeg4_sink_factory))
diff --git a/dlls/winegstreamer/mfplat.c b/dlls/winegstreamer/mfplat.c
index 4088a935625c..65a1079155e7 100644
--- a/dlls/winegstreamer/mfplat.c
+++ b/dlls/winegstreamer/mfplat.c
@@ -121,7 +121,6 @@ static const IClassFactoryVtbl class_factory_vtbl =
 };
 
 static const GUID CLSID_GStreamerByteStreamHandler = {0x317df618, 0x5e5a, 0x468a, {0x9f, 0x15, 0xd8, 0x27, 0xa9, 0xa0, 0x81, 0x62}};
-static const GUID CLSID_wg_video_processor = {0xd527607f,0x89cb,0x4e94,{0x95,0x71,0xbc,0xfe,0x62,0x17,0x56,0x13}};
 static const GUID CLSID_wg_aac_decoder = {0xe7889a8a,0x2083,0x4844,{0x83,0x70,0x5e,0xe3,0x49,0xb1,0x45,0x03}};
 static const GUID CLSID_wg_h264_decoder = {0x1f1e273d,0x12c0,0x4b3a,{0x8e,0x9b,0x19,0x33,0xc2,0x49,0x8a,0xea}};
 static const GUID CLSID_wg_h264_encoder = {0x6c34de69,0x4670,0x46cd,{0x8c,0xb4,0x1f,0x2f,0xa1,0xdf,0xfb,0x65}};
@@ -133,7 +132,6 @@ static const struct class_object
 }
 class_objects[] =
 {
-    { &CLSID_wg_video_processor, &video_processor_create },
     { &CLSID_GStreamerByteStreamHandler, &gstreamer_byte_stream_handler_create },
     { &CLSID_wg_aac_decoder, &aac_decoder_create },
     { &CLSID_wg_h264_decoder, &h264_decoder_create },
diff --git a/dlls/winegstreamer/resampler.c b/dlls/winegstreamer/resampler.c
deleted file mode 100644
index 6147d8da4fc3..000000000000
--- a/dlls/winegstreamer/resampler.c
+++ /dev/null
@@ -1,966 +0,0 @@
-/* Copyright 2022 Rémi Bernon for CodeWeavers
- *
- * 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 St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "gst_private.h"
-
-#include "mfapi.h"
-#include "mferror.h"
-#include "mfobjects.h"
-#include "mftransform.h"
-#include "wmcodecdsp.h"
-
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
-WINE_DECLARE_DEBUG_CHANNEL(winediag);
-
-static const GUID *audio_formats[] =
-{
-    &MFAudioFormat_Float,
-    &MFAudioFormat_PCM,
-};
-
-struct resampler
-{
-    IUnknown IUnknown_inner;
-    IMFTransform IMFTransform_iface;
-    IMediaObject IMediaObject_iface;
-    IPropertyBag IPropertyBag_iface;
-    IPropertyStore IPropertyStore_iface;
-    IWMResamplerProps IWMResamplerProps_iface;
-    IUnknown *outer;
-    LONG refcount;
-
-    IMFMediaType *input_type;
-    MFT_INPUT_STREAM_INFO input_info;
-    IMFMediaType *output_type;
-    MFT_OUTPUT_STREAM_INFO output_info;
-
-    wg_transform_t wg_transform;
-    struct wg_sample_queue *wg_sample_queue;
-};
-
-static HRESULT try_create_wg_transform(struct resampler *impl)
-{
-    struct wg_transform_attrs attrs = {0};
-
-    if (impl->wg_transform)
-    {
-        wg_transform_destroy(impl->wg_transform);
-        impl->wg_transform = 0;
-    }
-
-    return wg_transform_create_mf(impl->input_type, impl->output_type, &attrs, &impl->wg_transform);
-}
-
-static inline struct resampler *impl_from_IUnknown(IUnknown *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IUnknown_inner);
-}
-
-static HRESULT WINAPI unknown_QueryInterface(IUnknown *iface, REFIID iid, void **out)
-{
-    struct resampler *impl = impl_from_IUnknown(iface);
-
-    TRACE("iface %p, iid %s, out %p.\n", iface, debugstr_guid(iid), out);
-
-    if (IsEqualGUID(iid, &IID_IUnknown))
-        *out = &impl->IUnknown_inner;
-    else if (IsEqualGUID(iid, &IID_IMFTransform))
-        *out = &impl->IMFTransform_iface;
-    else if (IsEqualGUID(iid, &IID_IMediaObject))
-        *out = &impl->IMediaObject_iface;
-    else if (IsEqualIID(iid, &IID_IPropertyBag))
-        *out = &impl->IPropertyBag_iface;
-    else if (IsEqualIID(iid, &IID_IPropertyStore))
-        *out = &impl->IPropertyStore_iface;
-    else if (IsEqualIID(iid, &IID_IWMResamplerProps))
-        *out = &impl->IWMResamplerProps_iface;
-    else
-    {
-        *out = NULL;
-        WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid));
-        return E_NOINTERFACE;
-    }
-
-    IUnknown_AddRef((IUnknown *)*out);
-    return S_OK;
-}
-
-static ULONG WINAPI unknown_AddRef(IUnknown *iface)
-{
-    struct resampler *impl = impl_from_IUnknown(iface);
-    ULONG refcount = InterlockedIncrement(&impl->refcount);
-
-    TRACE("iface %p increasing refcount to %lu.\n", iface, refcount);
-
-    return refcount;
-}
-
-static ULONG WINAPI unknown_Release(IUnknown *iface)
-{
-    struct resampler *impl = impl_from_IUnknown(iface);
-    ULONG refcount = InterlockedDecrement(&impl->refcount);
-
-    TRACE("iface %p decreasing refcount to %lu.\n", iface, refcount);
-
-    if (!refcount)
-    {
-        if (impl->wg_transform)
-            wg_transform_destroy(impl->wg_transform);
-        if (impl->input_type)
-            IMFMediaType_Release(impl->input_type);
-        if (impl->output_type)
-            IMFMediaType_Release(impl->output_type);
-
-        wg_sample_queue_destroy(impl->wg_sample_queue);
-        free(impl);
-    }
-
-    return refcount;
-}
-
-static const IUnknownVtbl unknown_vtbl =
-{
-    unknown_QueryInterface,
-    unknown_AddRef,
-    unknown_Release,
-};
-
-static struct resampler *impl_from_IMFTransform(IMFTransform *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IMFTransform_iface);
-}
-
-static HRESULT WINAPI transform_QueryInterface(IMFTransform *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IMFTransform(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI transform_AddRef(IMFTransform *iface)
-{
-    return IUnknown_AddRef(impl_from_IMFTransform(iface)->outer);
-}
-
-static ULONG WINAPI transform_Release(IMFTransform *iface)
-{
-    return IUnknown_Release(impl_from_IMFTransform(iface)->outer);
-}
-
-static HRESULT WINAPI transform_GetStreamLimits(IMFTransform *iface, DWORD *input_minimum,
-        DWORD *input_maximum, DWORD *output_minimum, DWORD *output_maximum)
-{
-    TRACE("iface %p, input_minimum %p, input_maximum %p, output_minimum %p, output_maximum %p.\n",
-            iface, input_minimum, input_maximum, output_minimum, output_maximum);
-    *input_minimum = *input_maximum = *output_minimum = *output_maximum = 1;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetStreamCount(IMFTransform *iface, DWORD *inputs, DWORD *outputs)
-{
-    TRACE("iface %p, inputs %p, outputs %p.\n", iface, inputs, outputs);
-    *inputs = *outputs = 1;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetStreamIDs(IMFTransform *iface, DWORD input_size, DWORD *inputs,
-        DWORD output_size, DWORD *outputs)
-{
-    TRACE("iface %p, input_size %lu, inputs %p, output_size %lu, outputs %p.\n", iface,
-            input_size, inputs, output_size, outputs);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetInputStreamInfo(IMFTransform *iface, DWORD id, MFT_INPUT_STREAM_INFO *info)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
-
-    if (!impl->input_type || !impl->output_type)
-    {
-        memset(info, 0, sizeof(*info));
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-    }
-
-    *info = impl->input_info;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetOutputStreamInfo(IMFTransform *iface, DWORD id, MFT_OUTPUT_STREAM_INFO *info)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, info %p.\n", iface, id, info);
-
-    if (!impl->input_type || !impl->output_type)
-    {
-        memset(info, 0, sizeof(*info));
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-    }
-
-    *info = impl->output_info;
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_GetAttributes(IMFTransform *iface, IMFAttributes **attributes)
-{
-    TRACE("iface %p, attributes %p.\n", iface, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetInputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
-{
-    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetOutputStreamAttributes(IMFTransform *iface, DWORD id, IMFAttributes **attributes)
-{
-    TRACE("iface %p, id %#lx, attributes %p.\n", iface, id, attributes);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_DeleteInputStream(IMFTransform *iface, DWORD id)
-{
-    TRACE("iface %p, id %#lx.\n", iface, id);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_AddInputStreams(IMFTransform *iface, DWORD streams, DWORD *ids)
-{
-    TRACE("iface %p, streams %lu, ids %p.\n", iface, streams, ids);
-    return E_NOTIMPL;
-}
-
-static HRESULT get_available_media_type(DWORD index, IMFMediaType **type, BOOL output)
-{
-    UINT32 sample_size, sample_rate = 48000, block_alignment, channel_count = 2;
-    IMFMediaType *media_type;
-    const GUID *subtype;
-    HRESULT hr;
-
-    *type = NULL;
-
-    if (index >= (output ? 2 : 1) * ARRAY_SIZE(audio_formats))
-        return MF_E_NO_MORE_TYPES;
-    subtype = audio_formats[index % ARRAY_SIZE(audio_formats)];
-
-    if (FAILED(hr = MFCreateMediaType(&media_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_MAJOR_TYPE, &MFMediaType_Audio)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetGUID(media_type, &MF_MT_SUBTYPE, subtype)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_ALL_SAMPLES_INDEPENDENT, 1)))
-        goto done;
-    if (index < ARRAY_SIZE(audio_formats))
-        goto done;
-
-    if (IsEqualGUID(subtype, &MFAudioFormat_Float))
-        sample_size = 32;
-    else if (IsEqualGUID(subtype, &MFAudioFormat_PCM))
-        sample_size = 16;
-    else
-    {
-        FIXME("Subtype %s not implemented!\n", debugstr_guid(subtype));
-        hr = E_NOTIMPL;
-        goto done;
-    }
-
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BITS_PER_SAMPLE, sample_size)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_NUM_CHANNELS, channel_count)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, sample_rate)))
-        goto done;
-
-    block_alignment = sample_size * channel_count / 8;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, block_alignment)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, sample_rate * block_alignment)))
-        goto done;
-    if (FAILED(hr = IMFMediaType_SetUINT32(media_type, &MF_MT_AUDIO_PREFER_WAVEFORMATEX, 1)))
-        goto done;
-
-done:
-    if (SUCCEEDED(hr))
-        IMFMediaType_AddRef((*type = media_type));
-
-    IMFMediaType_Release(media_type);
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetInputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
-        IMFMediaType **type)
-{
-    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
-    return get_available_media_type(index, type, FALSE);
-}
-
-static HRESULT WINAPI transform_GetOutputAvailableType(IMFTransform *iface, DWORD id, DWORD index,
-        IMFMediaType **type)
-{
-    TRACE("iface %p, id %#lx, index %#lx, type %p.\n", iface, id, index, type);
-    return get_available_media_type(index, type, TRUE);
-}
-
-static HRESULT check_media_type(IMFMediaType *type)
-{
-    MF_ATTRIBUTE_TYPE item_type;
-    GUID major, subtype;
-    HRESULT hr;
-    ULONG i;
-
-    if (!type)
-        return S_OK;
-
-    if (FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_MAJOR_TYPE, &major)) ||
-            FAILED(hr = IMFMediaType_GetGUID(type, &MF_MT_SUBTYPE, &subtype)))
-        return MF_E_ATTRIBUTENOTFOUND;
-
-    if (!IsEqualGUID(&major, &MFMediaType_Audio))
-        return MF_E_INVALIDMEDIATYPE;
-
-    for (i = 0; i < ARRAY_SIZE(audio_formats); ++i)
-        if (IsEqualGUID(&subtype, audio_formats[i]))
-            break;
-    if (i == ARRAY_SIZE(audio_formats))
-        return MF_E_INVALIDMEDIATYPE;
-
-    if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_BITS_PER_SAMPLE, &item_type)) ||
-        item_type != MF_ATTRIBUTE_UINT32)
-        return MF_E_INVALIDMEDIATYPE;
-    if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &item_type)) ||
-        item_type != MF_ATTRIBUTE_UINT32)
-        return MF_E_INVALIDMEDIATYPE;
-    if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_NUM_CHANNELS, &item_type)) ||
-        item_type != MF_ATTRIBUTE_UINT32)
-        return MF_E_INVALIDMEDIATYPE;
-    if (FAILED(IMFMediaType_GetItemType(type, &MF_MT_AUDIO_SAMPLES_PER_SECOND, &item_type)) ||
-        item_type != MF_ATTRIBUTE_UINT32)
-        return MF_E_INVALIDMEDIATYPE;
-
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_SetInputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-    UINT32 block_alignment;
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
-
-    if (FAILED(hr = check_media_type(type)))
-        return hr;
-    if (type && FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
-        return MF_E_INVALIDMEDIATYPE;
-    if (flags & MFT_SET_TYPE_TEST_ONLY)
-        return S_OK;
-
-    if (!type)
-    {
-        if (impl->input_type)
-        {
-            IMFMediaType_Release(impl->input_type);
-            impl->input_type = NULL;
-        }
-        return S_OK;
-    }
-
-    if (!impl->input_type && FAILED(hr = MFCreateMediaType(&impl->input_type)))
-        return hr;
-
-    if (SUCCEEDED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->input_type)))
-        impl->input_info.cbSize = block_alignment;
-    else
-    {
-        IMFMediaType_Release(impl->input_type);
-        impl->input_info.cbSize = 0;
-        impl->input_type = NULL;
-    }
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_SetOutputType(IMFTransform *iface, DWORD id, IMFMediaType *type, DWORD flags)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-    UINT32 block_alignment;
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p, flags %#lx.\n", iface, id, type, flags);
-
-    if (!impl->input_type)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    if (FAILED(hr = check_media_type(type)))
-        return hr;
-    if (type && FAILED(hr = IMFMediaType_GetUINT32(type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
-        return MF_E_INVALIDMEDIATYPE;
-    if (flags & MFT_SET_TYPE_TEST_ONLY)
-        return S_OK;
-
-    if (!type)
-    {
-        if (impl->output_type)
-        {
-            IMFMediaType_Release(impl->output_type);
-            impl->output_type = NULL;
-        }
-        return S_OK;
-    }
-
-    if (!impl->output_type && FAILED(hr = MFCreateMediaType(&impl->output_type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(type, (IMFAttributes *)impl->output_type)))
-        goto failed;
-
-    if (FAILED(hr = try_create_wg_transform(impl)))
-        goto failed;
-
-    impl->output_info.cbSize = block_alignment;
-    return hr;
-
-failed:
-    IMFMediaType_Release(impl->output_type);
-    impl->output_info.cbSize = 0;
-    impl->output_type = NULL;
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetInputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
-
-    if (id != 0)
-        return MF_E_INVALIDSTREAMNUMBER;
-
-    if (!impl->input_type)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    if (FAILED(hr = MFCreateMediaType(type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(impl->input_type, (IMFAttributes *)*type)))
-        IMFMediaType_Release(*type);
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetOutputCurrentType(IMFTransform *iface, DWORD id, IMFMediaType **type)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, id %#lx, type %p.\n", iface, id, type);
-
-    if (id != 0)
-        return MF_E_INVALIDSTREAMNUMBER;
-
-    if (!impl->output_type)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    if (FAILED(hr = MFCreateMediaType(type)))
-        return hr;
-
-    if (FAILED(hr = IMFMediaType_CopyAllItems(impl->output_type, (IMFAttributes *)*type)))
-        IMFMediaType_Release(*type);
-
-    return hr;
-}
-
-static HRESULT WINAPI transform_GetInputStatus(IMFTransform *iface, DWORD id, DWORD *flags)
-{
-    FIXME("iface %p, id %#lx, flags %p stub!\n", iface, id, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_GetOutputStatus(IMFTransform *iface, DWORD *flags)
-{
-    FIXME("iface %p, flags %p stub!\n", iface, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_SetOutputBounds(IMFTransform *iface, LONGLONG lower, LONGLONG upper)
-{
-    TRACE("iface %p, lower %I64d, upper %I64d.\n", iface, lower, upper);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_ProcessEvent(IMFTransform *iface, DWORD id, IMFMediaEvent *event)
-{
-    FIXME("iface %p, id %#lx, event %p stub!\n", iface, id, event);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI transform_ProcessMessage(IMFTransform *iface, MFT_MESSAGE_TYPE message, ULONG_PTR param)
-{
-    FIXME("iface %p, message %#x, param %p stub!\n", iface, message, (void *)param);
-    return S_OK;
-}
-
-static HRESULT WINAPI transform_ProcessInput(IMFTransform *iface, DWORD id, IMFSample *sample, DWORD flags)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-
-    TRACE("iface %p, id %#lx, sample %p, flags %#lx.\n", iface, id, sample, flags);
-
-    if (!impl->wg_transform)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    return wg_transform_push_mf(impl->wg_transform, sample, impl->wg_sample_queue);
-}
-
-static HRESULT WINAPI transform_ProcessOutput(IMFTransform *iface, DWORD flags, DWORD count,
-        MFT_OUTPUT_DATA_BUFFER *samples, DWORD *status)
-{
-    struct resampler *impl = impl_from_IMFTransform(iface);
-    HRESULT hr;
-
-    TRACE("iface %p, flags %#lx, count %lu, samples %p, status %p.\n", iface, flags, count, samples, status);
-
-    if (count != 1)
-        return E_INVALIDARG;
-
-    if (!impl->wg_transform)
-        return MF_E_TRANSFORM_TYPE_NOT_SET;
-
-    *status = samples->dwStatus = 0;
-    if (!samples->pSample)
-    {
-        samples->dwStatus = MFT_OUTPUT_DATA_BUFFER_NO_SAMPLE;
-        return MF_E_TRANSFORM_NEED_MORE_INPUT;
-    }
-
-    if (SUCCEEDED(hr = wg_transform_read_mf(impl->wg_transform, samples->pSample, 0, &samples->dwStatus, NULL)))
-        wg_sample_queue_flush(impl->wg_sample_queue, false);
-
-    return hr;
-}
-
-static const IMFTransformVtbl transform_vtbl =
-{
-    transform_QueryInterface,
-    transform_AddRef,
-    transform_Release,
-    transform_GetStreamLimits,
-    transform_GetStreamCount,
-    transform_GetStreamIDs,
-    transform_GetInputStreamInfo,
-    transform_GetOutputStreamInfo,
-    transform_GetAttributes,
-    transform_GetInputStreamAttributes,
-    transform_GetOutputStreamAttributes,
-    transform_DeleteInputStream,
-    transform_AddInputStreams,
-    transform_GetInputAvailableType,
-    transform_GetOutputAvailableType,
-    transform_SetInputType,
-    transform_SetOutputType,
-    transform_GetInputCurrentType,
-    transform_GetOutputCurrentType,
-    transform_GetInputStatus,
-    transform_GetOutputStatus,
-    transform_SetOutputBounds,
-    transform_ProcessEvent,
-    transform_ProcessMessage,
-    transform_ProcessInput,
-    transform_ProcessOutput,
-};
-
-static inline struct resampler *impl_from_IMediaObject(IMediaObject *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IMediaObject_iface);
-}
-
-static HRESULT WINAPI media_object_QueryInterface(IMediaObject *iface, REFIID iid, void **obj)
-{
-    return IUnknown_QueryInterface(impl_from_IMediaObject(iface)->outer, iid, obj);
-}
-
-static ULONG WINAPI media_object_AddRef(IMediaObject *iface)
-{
-    return IUnknown_AddRef(impl_from_IMediaObject(iface)->outer);
-}
-
-static ULONG WINAPI media_object_Release(IMediaObject *iface)
-{
-    return IUnknown_Release(impl_from_IMediaObject(iface)->outer);
-}
-
-static HRESULT WINAPI media_object_GetStreamCount(IMediaObject *iface, DWORD *input, DWORD *output)
-{
-    FIXME("iface %p, input %p, output %p semi-stub!\n", iface, input, output);
-    *input = *output = 1;
-    return S_OK;
-}
-
-static HRESULT WINAPI media_object_GetInputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputStreamInfo(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputType(IMediaObject *iface, DWORD index, DWORD type_index,
-        DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputType(IMediaObject *iface, DWORD index, DWORD type_index,
-        DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type_index %lu, type %p stub!\n", iface, index, type_index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetInputType(IMediaObject *iface, DWORD index,
-        const DMO_MEDIA_TYPE *type, DWORD flags)
-{
-    FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetOutputType(IMediaObject *iface, DWORD index,
-        const DMO_MEDIA_TYPE *type, DWORD flags)
-{
-    FIXME("iface %p, index %lu, type %p, flags %#lx stub!\n", iface, index, type, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputCurrentType(IMediaObject *iface, DWORD index, DMO_MEDIA_TYPE *type)
-{
-    FIXME("iface %p, index %lu, type %p stub!\n", iface, index, type);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size,
-        DWORD *lookahead, DWORD *alignment)
-{
-    FIXME("iface %p, index %lu, size %p, lookahead %p, alignment %p stub!\n", iface, index, size,
-            lookahead, alignment);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetOutputSizeInfo(IMediaObject *iface, DWORD index, DWORD *size, DWORD *alignment)
-{
-    FIXME("iface %p, index %lu, size %p, alignment %p stub!\n", iface, index, size, alignment);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME *latency)
-{
-    FIXME("iface %p, index %lu, latency %p stub!\n", iface, index, latency);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_SetInputMaxLatency(IMediaObject *iface, DWORD index, REFERENCE_TIME latency)
-{
-    FIXME("iface %p, index %lu, latency %s stub!\n", iface, index, wine_dbgstr_longlong(latency));
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Flush(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Discontinuity(IMediaObject *iface, DWORD index)
-{
-    FIXME("iface %p, index %lu stub!\n", iface, index);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_AllocateStreamingResources(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_FreeStreamingResources(IMediaObject *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_GetInputStatus(IMediaObject *iface, DWORD index, DWORD *flags)
-{
-    FIXME("iface %p, index %lu, flags %p stub!\n", iface, index, flags);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_ProcessInput(IMediaObject *iface, DWORD index,
-        IMediaBuffer *buffer, DWORD flags, REFERENCE_TIME timestamp, REFERENCE_TIME timelength)
-{
-    FIXME("iface %p, index %lu, buffer %p, flags %#lx, timestamp %s, timelength %s stub!\n", iface,
-            index, buffer, flags, wine_dbgstr_longlong(timestamp), wine_dbgstr_longlong(timelength));
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_ProcessOutput(IMediaObject *iface, DWORD flags, DWORD count,
-        DMO_OUTPUT_DATA_BUFFER *buffers, DWORD *status)
-{
-    FIXME("iface %p, flags %#lx, count %lu, buffers %p, status %p stub!\n", iface, flags, count, buffers, status);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI media_object_Lock(IMediaObject *iface, LONG lock)
-{
-    FIXME("iface %p, lock %ld stub!\n", iface, lock);
-    return E_NOTIMPL;
-}
-
-static const IMediaObjectVtbl media_object_vtbl =
-{
-    media_object_QueryInterface,
-    media_object_AddRef,
-    media_object_Release,
-    media_object_GetStreamCount,
-    media_object_GetInputStreamInfo,
-    media_object_GetOutputStreamInfo,
-    media_object_GetInputType,
-    media_object_GetOutputType,
-    media_object_SetInputType,
-    media_object_SetOutputType,
-    media_object_GetInputCurrentType,
-    media_object_GetOutputCurrentType,
-    media_object_GetInputSizeInfo,
-    media_object_GetOutputSizeInfo,
-    media_object_GetInputMaxLatency,
-    media_object_SetInputMaxLatency,
-    media_object_Flush,
-    media_object_Discontinuity,
-    media_object_AllocateStreamingResources,
-    media_object_FreeStreamingResources,
-    media_object_GetInputStatus,
-    media_object_ProcessInput,
-    media_object_ProcessOutput,
-    media_object_Lock,
-};
-
-static inline struct resampler *impl_from_IPropertyBag(IPropertyBag *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IPropertyBag_iface);
-}
-
-static HRESULT WINAPI property_bag_QueryInterface(IPropertyBag *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IPropertyBag(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI property_bag_AddRef(IPropertyBag *iface)
-{
-    return IUnknown_AddRef(impl_from_IPropertyBag(iface)->outer);
-}
-
-static ULONG WINAPI property_bag_Release(IPropertyBag *iface)
-{
-    return IUnknown_Release(impl_from_IPropertyBag(iface)->outer);
-}
-
-static HRESULT WINAPI property_bag_Read(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value,
-        IErrorLog *error_log)
-{
-    FIXME("iface %p, prop_name %s, value %p, error_log %p stub!\n", iface, debugstr_w(prop_name), value, error_log);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_bag_Write(IPropertyBag *iface, const WCHAR *prop_name, VARIANT *value)
-{
-    FIXME("iface %p, prop_name %s, value %p stub!\n", iface, debugstr_w(prop_name), value);
-    return S_OK;
-}
-
-static const IPropertyBagVtbl property_bag_vtbl =
-{
-    property_bag_QueryInterface,
-    property_bag_AddRef,
-    property_bag_Release,
-    property_bag_Read,
-    property_bag_Write,
-};
-
-static inline struct resampler *impl_from_IPropertyStore(IPropertyStore *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IPropertyStore_iface);
-}
-
-static HRESULT WINAPI property_store_QueryInterface(IPropertyStore *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IPropertyStore(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI property_store_AddRef(IPropertyStore *iface)
-{
-    return IUnknown_AddRef(impl_from_IPropertyStore(iface)->outer);
-}
-
-static ULONG WINAPI property_store_Release(IPropertyStore *iface)
-{
-    return IUnknown_Release(impl_from_IPropertyStore(iface)->outer);
-}
-
-static HRESULT WINAPI property_store_GetCount(IPropertyStore *iface, DWORD *count)
-{
-    FIXME("iface %p, count %p stub!\n", iface, count);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_GetAt(IPropertyStore *iface, DWORD index, PROPERTYKEY *key)
-{
-    FIXME("iface %p, index %lu, key %p stub!\n", iface, index, key);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_GetValue(IPropertyStore *iface, REFPROPERTYKEY key, PROPVARIANT *value)
-{
-    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_SetValue(IPropertyStore *iface, REFPROPERTYKEY key, REFPROPVARIANT value)
-{
-    FIXME("iface %p, key %p, value %p stub!\n", iface, key, value);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI property_store_Commit(IPropertyStore *iface)
-{
-    FIXME("iface %p stub!\n", iface);
-    return E_NOTIMPL;
-}
-
-static const IPropertyStoreVtbl property_store_vtbl =
-{
-    property_store_QueryInterface,
-    property_store_AddRef,
-    property_store_Release,
-    property_store_GetCount,
-    property_store_GetAt,
-    property_store_GetValue,
-    property_store_SetValue,
-    property_store_Commit,
-};
-
-static inline struct resampler *impl_from_IWMResamplerProps(IWMResamplerProps *iface)
-{
-    return CONTAINING_RECORD(iface, struct resampler, IWMResamplerProps_iface);
-}
-
-static HRESULT WINAPI resampler_props_QueryInterface(IWMResamplerProps *iface, REFIID iid, void **out)
-{
-    return IUnknown_QueryInterface(impl_from_IWMResamplerProps(iface)->outer, iid, out);
-}
-
-static ULONG WINAPI resampler_props_AddRef(IWMResamplerProps *iface)
-{
-    return IUnknown_AddRef(impl_from_IWMResamplerProps(iface)->outer);
-}
-
-static ULONG WINAPI resampler_props_Release(IWMResamplerProps *iface)
-{
-    return IUnknown_Release(impl_from_IWMResamplerProps(iface)->outer);
-}
-
-static HRESULT WINAPI resampler_props_SetHalfFilterLength(IWMResamplerProps *iface, LONG length)
-{
-    FIXME("iface %p, count %lu stub!\n", iface, length);
-    return E_NOTIMPL;
-}
-
-static HRESULT WINAPI resampler_props_SetUserChannelMtx(IWMResamplerProps *iface, ChMtxType *conversion_matrix)
-{
-    FIXME("iface %p, userChannelMtx %p stub!\n", iface, conversion_matrix);
-    return E_NOTIMPL;
-}
-
-static const IWMResamplerPropsVtbl resampler_props_vtbl =
-{
-    resampler_props_QueryInterface,
-    resampler_props_AddRef,
-    resampler_props_Release,
-    resampler_props_SetHalfFilterLength,
-    resampler_props_SetUserChannelMtx,
-};
-
-HRESULT resampler_create(IUnknown *outer, IUnknown **out)
-{
-    static const WAVEFORMATEX output_format =
-    {
-        .wFormatTag = WAVE_FORMAT_IEEE_FLOAT, .wBitsPerSample = 32, .nSamplesPerSec = 44100, .nChannels = 1,
-    };
-    static const WAVEFORMATEX input_format =
-    {
-        .wFormatTag = WAVE_FORMAT_PCM, .wBitsPerSample = 16, .nSamplesPerSec = 44100, .nChannels = 1,
-    };
-    struct resampler *impl;
-    HRESULT hr;
-
-    TRACE("outer %p, out %p.\n", outer, out);
-
-    if (FAILED(hr = check_audio_transform_support(&input_format, &output_format)))
-    {
-        ERR_(winediag)("GStreamer doesn't support audio resampling, please install appropriate plugins.\n");
-        return hr;
-    }
-
-    if (!(impl = calloc(1, sizeof(*impl))))
-        return E_OUTOFMEMORY;
-
-    if (FAILED(hr = wg_sample_queue_create(&impl->wg_sample_queue)))
-    {
-        free(impl);
-        return hr;
-    }
-
-    impl->IUnknown_inner.lpVtbl = &unknown_vtbl;
-    impl->IMFTransform_iface.lpVtbl = &transform_vtbl;
-    impl->IMediaObject_iface.lpVtbl = &media_object_vtbl;
-    impl->IPropertyBag_iface.lpVtbl = &property_bag_vtbl;
-    impl->IPropertyStore_iface.lpVtbl = &property_store_vtbl;
-    impl->IWMResamplerProps_iface.lpVtbl = &resampler_props_vtbl;
-    impl->refcount = 1;
-    impl->outer = outer ? outer : &impl->IUnknown_inner;
-
-    impl->input_info.cbAlignment = 1;
-    impl->output_info.cbAlignment = 1;
-
-    *out = &impl->IUnknown_inner;
-    TRACE("Created %p\n", *out);
-    return S_OK;
-}
diff --git a/dlls/winegstreamer/winegstreamer.spec b/dlls/winegstreamer/winegstreamer.spec
index 69eed004b785..095f75a0865b 100644
--- a/dlls/winegstreamer/winegstreamer.spec
+++ b/dlls/winegstreamer/winegstreamer.spec
@@ -4,4 +4,3 @@
 @ stdcall -private DllUnregisterServer()
 @ stdcall winegstreamer_create_wm_sync_reader(ptr ptr)
 @ stdcall winegstreamer_create_video_decoder(ptr)
-@ stdcall winegstreamer_create_color_converter(ptr)
diff --git a/dlls/winegstreamer/winegstreamer_classes.idl b/dlls/winegstreamer/winegstreamer_classes.idl
index bb9f81c23411..fd46ba3e6873 100644
--- a/dlls/winegstreamer/winegstreamer_classes.idl
+++ b/dlls/winegstreamer/winegstreamer_classes.idl
@@ -64,12 +64,6 @@ coclass wg_wave_parser {}
 ]
 coclass decodebin_parser {}
 
-[
-    threading(both),
-    uuid(d527607f-89cb-4e94-9571-bcfe62175613)
-]
-coclass wg_video_processor {}
-
 [
     helpstring("Generic Decodebin Byte Stream Handler"),
     threading(both),
@@ -107,18 +101,6 @@ coclass wg_h264_decoder {}
 ]
 coclass wg_h264_encoder {}
 
-[
-    threading(both),
-    uuid(92f35e78-15a5-486b-888e-575f99651ce2)
-]
-coclass wg_resampler {}
-
-[
-    threading(both),
-    uuid(f47e2da5-e370-47b7-903a-078ddd45a5cc)
-]
-coclass wg_color_converter {}
-
 [
     threading(both),
     uuid(1f302877-aaab-40a3-b9e0-9f48daf35bc8)
diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c
index a0f314234b97..906bb4d09e69 100644
--- a/dlls/winemac.drv/gdi.c
+++ b/dlls/winemac.drv/gdi.c
@@ -284,6 +284,7 @@ static const struct user_driver_funcs macdrv_funcs =
     .pWindowPosChanged = macdrv_WindowPosChanged,
     .pWindowPosChanging = macdrv_WindowPosChanging,
     .pGetWindowStyleMasks = macdrv_GetWindowStyleMasks,
+    .pCreateClientSurface = macdrv_CreateClientSurface,
     .pCreateWindowSurface = macdrv_CreateWindowSurface,
     .pVulkanInit = macdrv_VulkanInit,
     .pOpenGLInit = macdrv_OpenGLInit,
diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h
index 4f7107baf682..aeeadae122ea 100644
--- a/dlls/winemac.drv/macdrv.h
+++ b/dlls/winemac.drv/macdrv.h
@@ -150,12 +150,13 @@ extern void macdrv_SetLayeredWindowAttributes(HWND hwnd, COLORREF key, BYTE alph
 extern LRESULT macdrv_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
 extern BOOL macdrv_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects);
 extern BOOL macdrv_GetWindowStyleMasks(HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask);
+extern struct client_surface *macdrv_CreateClientSurface(HWND hwnd, int pixel_format);
 extern BOOL macdrv_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface);
 extern void macdrv_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags,
                                     const struct window_rects *new_rects, struct window_surface *surface);
 extern void macdrv_DestroyCursorIcon(HCURSOR cursor);
 extern BOOL macdrv_GetCursorPos(LPPOINT pos);
-extern void macdrv_SetCapture(HWND hwnd, UINT flags);
+extern void macdrv_SetCapture(HWND hwnd, UINT flags, HWND previous);
 extern void macdrv_SetCursor(HWND hwnd, HCURSOR cursor);
 extern BOOL macdrv_SetCursorPos(INT x, INT y);
 extern BOOL macdrv_RegisterHotKey(HWND hwnd, UINT mod_flags, UINT vkey);
@@ -200,12 +201,7 @@ extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_p
     macdrv_metal_swapchain  metal_swapchain;
 };
 
-static inline struct macdrv_client_surface *impl_from_client_surface(struct client_surface *client)
-{
-    return CONTAINING_RECORD(client, struct macdrv_client_surface, client);
-}
-
-extern struct macdrv_client_surface *macdrv_client_surface_create(HWND hwnd);
+extern struct macdrv_client_surface *impl_from_client_surface(struct client_surface *client);
 extern BOOL macdrv_client_surface_acquire_metal_swapchain(struct macdrv_client_surface *surface);
 
 extern struct macdrv_win_data *get_win_data(HWND hwnd);
@@ -242,7 +238,6 @@ extern BOOL macdrv_SystemParametersInfo(UINT action, UINT int_param, void *ptr_p
 extern void macdrv_mouse_moved(HWND hwnd, const macdrv_event *event);
 extern void macdrv_mouse_scroll(HWND hwnd, const macdrv_event *event);
 extern void macdrv_release_capture(HWND hwnd, const macdrv_event *event);
-extern void macdrv_SetCapture(HWND hwnd, UINT flags);
 
 extern void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data);
 extern void macdrv_keyboard_changed(const macdrv_event *event);
diff --git a/dlls/winemac.drv/mouse.c b/dlls/winemac.drv/mouse.c
index ee876d5355c1..19674b2d0993 100644
--- a/dlls/winemac.drv/mouse.c
+++ b/dlls/winemac.drv/mouse.c
@@ -702,13 +702,12 @@ BOOL macdrv_GetCursorPos(LPPOINT pos)
 /***********************************************************************
  *              SetCapture (MACDRV.@)
  */
- void macdrv_SetCapture(HWND hwnd, UINT flags)
+ void macdrv_SetCapture(HWND hwnd, UINT flags, HWND previous)
 {
     struct macdrv_thread_data *thread_data = macdrv_thread_data();
-    HWND top = NtUserGetAncestor(hwnd, GA_ROOT);
-    macdrv_window cocoa_window = macdrv_get_cocoa_window(top, FALSE);
+    macdrv_window cocoa_window = macdrv_get_cocoa_window(hwnd, FALSE);
 
-    TRACE("hwnd %p top %p/%p flags 0x%08x\n", hwnd, top, cocoa_window, flags);
+    TRACE("hwnd %p/%p flags 0x%08x previous %p\n", hwnd, cocoa_window, flags, previous);
 
     if (!thread_data) return;
 
diff --git a/dlls/winemac.drv/opengl.c b/dlls/winemac.drv/opengl.c
index 0af1d3f71929..01b4b03b029f 100644
--- a/dlls/winemac.drv/opengl.c
+++ b/dlls/winemac.drv/opengl.c
@@ -1455,28 +1455,23 @@ static BOOL create_context(struct macdrv_context *context, CGLContextObj share,
     return TRUE;
 }
 
-static BOOL macdrv_surface_create(HWND hwnd, int format, struct opengl_drawable **drawable)
+static BOOL macdrv_surface_create(struct client_surface *client, int format, struct opengl_drawable **drawable)
 {
-    struct macdrv_client_surface *client;
     struct macdrv_win_data *data;
+    HWND hwnd = client->hwnd;
     struct gl_drawable *gl;
 
-    TRACE("hwnd %p, format %d, drawable %p\n", hwnd, format, drawable);
+    TRACE("client %s, format %d, drawable %p\n", debugstr_client_surface(client), format, drawable);
 
     if (!(data = get_win_data(hwnd)))
     {
         FIXME("DC for window %p of other process: not implemented\n", hwnd);
         return FALSE;
     }
-
     data->pixel_format = format;
     release_win_data(data);
 
-    if (!(client = macdrv_client_surface_create(hwnd))) return FALSE;
-    gl = opengl_drawable_create(sizeof(*gl), &macdrv_surface_funcs, format, &client->client);
-    client_surface_release(&client->client);
-    if (!gl) return FALSE;
-
+    if (!(gl = opengl_drawable_create(sizeof(*gl), &macdrv_surface_funcs, format, client))) return FALSE;
     *drawable = &gl->base;
     return TRUE;
 }
@@ -2272,6 +2267,11 @@ static BOOL macdrv_make_current(struct opengl_drawable *draw_base, struct opengl
         NtCurrentTeb()->glReserved2 = NULL;
         return TRUE;
     }
+    if (!draw || !read)
+    {
+        CGLSetCurrentContext(context->cglcontext);
+        return TRUE;
+    }
 
     context->read_hwnd = context->draw_hwnd = NULL;
     context->read_view = context->draw_view = NULL;
diff --git a/dlls/winemac.drv/vulkan.c b/dlls/winemac.drv/vulkan.c
index f1643e3e5c4b..532f792ed46f 100644
--- a/dlls/winemac.drv/vulkan.c
+++ b/dlls/winemac.drv/vulkan.c
@@ -40,17 +40,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
 static const struct vulkan_driver_funcs macdrv_vulkan_driver_funcs;
 
-static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_instance *instance, VkSurfaceKHR *handle,
-                                             struct client_surface **client)
+static VkResult macdrv_vulkan_surface_create(struct client_surface *client, const struct vulkan_instance *instance, VkSurfaceKHR *handle)
 {
     VkResult res;
-    struct macdrv_client_surface *surface;
+    struct macdrv_client_surface *surface = impl_from_client_surface(client);
 
-    TRACE("%p %p %p %p\n", hwnd, instance, handle, client);
+    TRACE("%s %p %p\n", debugstr_client_surface(client), instance, handle);
 
-    if (!(surface = macdrv_client_surface_create(hwnd))) return VK_ERROR_OUT_OF_HOST_MEMORY;
-
-    if (!macdrv_client_surface_acquire_metal_swapchain(surface)) goto err;
+    if (!macdrv_client_surface_acquire_metal_swapchain(surface)) return VK_ERROR_INCOMPATIBLE_DRIVER;
 
     if (instance->p_vkCreateMetalSurfaceEXT)
     {
@@ -60,7 +57,7 @@ static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_inst
         create_info_host.flags = 0; /* reserved */
         create_info_host.pLayer = macdrv_swapchain_get_layer(surface->metal_swapchain);
 
-        res = instance->p_vkCreateMetalSurfaceEXT(instance->host.instance, &create_info_host, NULL /* allocator */, handle);
+        if ((res = instance->p_vkCreateMetalSurfaceEXT(instance->host.instance, &create_info_host, NULL /* allocator */, handle))) return res;
     }
     else
     {
@@ -70,21 +67,11 @@ static VkResult macdrv_vulkan_surface_create(HWND hwnd, const struct vulkan_inst
         create_info_host.flags = 0; /* reserved */
         create_info_host.pView = macdrv_swapchain_get_layer(surface->metal_swapchain);
 
-        res = instance->p_vkCreateMacOSSurfaceMVK(instance->host.instance, &create_info_host, NULL /* allocator */, handle);
-    }
-    if (res != VK_SUCCESS)
-    {
-        ERR("Failed to create MoltenVK surface, res=%d\n", res);
-        goto err;
+        if ((res = instance->p_vkCreateMacOSSurfaceMVK(instance->host.instance, &create_info_host, NULL /* allocator */, handle))) return res;
     }
 
-    *client = &surface->client;
-    TRACE("Created surface=0x%s, client=%p\n", wine_dbgstr_longlong(*handle), *client);
+    TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*handle));
     return VK_SUCCESS;
-
-err:
-    client_surface_release(&surface->client);
-    return VK_ERROR_INCOMPATIBLE_DRIVER;
 }
 
 static VkBool32 macdrv_get_physical_device_presentation_support(struct vulkan_physical_device *physical_device,
diff --git a/dlls/winemac.drv/window.c b/dlls/winemac.drv/window.c
index adfc059e34fc..61f14ad496b2 100644
--- a/dlls/winemac.drv/window.c
+++ b/dlls/winemac.drv/window.c
@@ -825,7 +825,7 @@ static BOOL set_capture_window_for_move(HWND hwnd)
 
     if (ret)
     {
-        macdrv_SetCapture(hwnd, GUI_INMOVESIZE);
+        macdrv_SetCapture(NtUserGetAncestor(hwnd, GA_ROOT), GUI_INMOVESIZE, NtUserGetAncestor(previous, GA_ROOT));
 
         if (previous && previous != hwnd)
             send_message(previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd);
@@ -1144,7 +1144,13 @@ static const struct client_surface_funcs macdrv_client_surface_funcs =
     .present = macdrv_client_surface_present,
 };
 
-struct macdrv_client_surface *macdrv_client_surface_create(HWND hwnd)
+struct macdrv_client_surface *impl_from_client_surface(struct client_surface *client)
+{
+    assert(client->funcs == &macdrv_client_surface_funcs);
+    return CONTAINING_RECORD(client, struct macdrv_client_surface, client);
+}
+
+struct client_surface *macdrv_CreateClientSurface(HWND hwnd, int pixel_format)
 {
     HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT);
     struct macdrv_client_surface *surface;
@@ -1163,7 +1169,7 @@ struct macdrv_client_surface *macdrv_client_surface_create(HWND hwnd)
         macdrv_client_surface_present(&surface->client, 0);
     }
 
-    return surface;
+    return &surface->client;
 }
 
 BOOL macdrv_client_surface_acquire_metal_swapchain(struct macdrv_client_surface *surface)
@@ -1273,7 +1279,6 @@ void macdrv_DestroyWindow(HWND hwnd)
 
     if (!(data = get_win_data(hwnd))) return;
 
-    if (hwnd == get_capture()) macdrv_SetCapture(0, 0);
     if (data->drag_event) NtSetEvent(data->drag_event, NULL);
 
     destroy_cocoa_window(data);
diff --git a/dlls/winevulkan/loader.c b/dlls/winevulkan/loader.c
index 684d201339f6..864328e3f4f4 100644
--- a/dlls/winevulkan/loader.c
+++ b/dlls/winevulkan/loader.c
@@ -376,7 +376,6 @@ VkResult WINAPI vkCreateInstance(const VkInstanceCreateInfo *create_info,
     const VkApplicationInfo *app_info;
     struct VkInstance_T *instance;
     uint32_t device_count = 8, i;
-    NTSTATUS status;
 
     TRACE("create_info %p, allocator %p, instance %p\n", create_info, allocator, ret);
 
@@ -415,8 +414,7 @@ VkResult WINAPI vkCreateInstance(const VkInstanceCreateInfo *create_info,
         params.pCreateInfo = create_info;
         params.pAllocator = allocator;
         params.pInstance = ret;
-        status = UNIX_CALL(vkCreateInstance, &params);
-        assert(!status);
+        UNIX_CALL_CHECKED(vkCreateInstance, &params);
         if (instance->physical_device_count <= device_count)
             break;
         device_count = instance->physical_device_count;
@@ -435,12 +433,10 @@ VkResult WINAPI vkCreateInstance(const VkInstanceCreateInfo *create_info,
 void WINAPI vkDestroyInstance(VkInstance instance, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyInstance_params params;
-    NTSTATUS status;
 
     params.instance = instance;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyInstance, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkDestroyInstance, &params);
     free(instance);
 }
 
@@ -452,13 +448,11 @@ static VkResult enum_host_instance_extension_properties(const char *layer_name,
         .pLayerName = layer_name,
         .pPropertyCount = count,
     };
-    NTSTATUS status;
 
     for (;;)
     {
         *properties = params.pProperties;
-        status = UNIX_CALL(vkEnumerateInstanceExtensionProperties, &params);
-        assert(!status && "vkEnumerateInstanceExtensionProperties");
+        UNIX_CALL_CHECKED(vkEnumerateInstanceExtensionProperties, &params);
         if (params.result == VK_INCOMPLETE)
         {
             free(params.pProperties);
@@ -527,13 +521,11 @@ static VkResult enum_host_device_extension_properties(VkPhysicalDevice physical_
         .pLayerName = layer_name,
         .pPropertyCount = count,
     };
-    NTSTATUS status;
 
     for (;;)
     {
         *properties = params.pProperties;
-        status = UNIX_CALL(vkEnumerateDeviceExtensionProperties, &params);
-        assert(!status && "vkEnumerateDeviceExtensionProperties");
+        UNIX_CALL_CHECKED(vkEnumerateDeviceExtensionProperties, &params);
         if (params.result == VK_INCOMPLETE)
         {
             free(params.pProperties);
@@ -608,7 +600,6 @@ done:
 VkResult WINAPI vkEnumerateInstanceVersion(uint32_t *version)
 {
     struct vkEnumerateInstanceVersion_params params;
-    NTSTATUS status;
 
     TRACE("%p\n", version);
 
@@ -619,8 +610,7 @@ VkResult WINAPI vkEnumerateInstanceVersion(uint32_t *version)
     }
 
     params.pApiVersion = version;
-    status = UNIX_CALL(vkEnumerateInstanceVersion, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkEnumerateInstanceVersion, &params);
     return params.result;
 }
 
@@ -631,7 +621,6 @@ VkResult WINAPI vkCreateDevice(VkPhysicalDevice physical_device, const VkDeviceC
     struct vkCreateDevice_params params;
     uint32_t queue_count = 0, i;
     VkDevice device;
-    NTSTATUS status;
 
     TRACE("Enabling %u client device extensions\n", create_info->enabledExtensionCount);
     for (uint32_t i = 0; i < create_info->enabledExtensionCount; i++)
@@ -656,8 +645,7 @@ VkResult WINAPI vkCreateDevice(VkPhysicalDevice physical_device, const VkDeviceC
     params.pAllocator = allocator;
     params.pDevice = ret;
 
-    status = UNIX_CALL(vkCreateDevice, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkCreateDevice, &params);
     if (params.result)
     {
         free(device);
@@ -669,12 +657,10 @@ VkResult WINAPI vkCreateDevice(VkPhysicalDevice physical_device, const VkDeviceC
 void WINAPI vkDestroyDevice(VkDevice device, const VkAllocationCallbacks *allocator)
 {
     struct vkDestroyDevice_params params;
-    NTSTATUS status;
 
     params.device = device;
     params.pAllocator = allocator;
-    status = UNIX_CALL(vkDestroyDevice, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkDestroyDevice, &params);
     free(device);
 }
 
@@ -683,7 +669,6 @@ VkResult WINAPI vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateIn
 {
     struct vkCreateCommandPool_params params;
     struct vk_command_pool *cmd_pool;
-    NTSTATUS status;
 
     if (!(cmd_pool = vulkan_client_object_create(sizeof(*cmd_pool))))
         return VK_ERROR_OUT_OF_HOST_MEMORY;
@@ -694,8 +679,7 @@ VkResult WINAPI vkCreateCommandPool(VkDevice device, const VkCommandPoolCreateIn
     params.pCreateInfo = create_info;
     params.pAllocator = allocator;
     params.pCommandPool = ret;
-    status = UNIX_CALL(vkCreateCommandPool, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkCreateCommandPool, &params);
     if (params.result)
     {
         free(cmd_pool);
@@ -709,7 +693,6 @@ void WINAPI vkDestroyCommandPool(VkDevice device, VkCommandPool handle, const Vk
     struct vk_command_pool *cmd_pool = command_pool_from_handle(handle);
     struct vkDestroyCommandPool_params params;
     VkCommandBuffer buffer, cursor;
-    NTSTATUS status;
 
     if (!cmd_pool)
         return;
@@ -726,8 +709,7 @@ void WINAPI vkDestroyCommandPool(VkDevice device, VkCommandPool handle, const Vk
     params.device = device;
     params.commandPool = handle;
     params.pAllocator = allocator;
-    status = UNIX_CALL(vkDestroyCommandPool, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkDestroyCommandPool, &params);
     free(cmd_pool);
 }
 
@@ -736,7 +718,6 @@ VkResult WINAPI vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferA
 {
     struct vk_command_pool *pool = command_pool_from_handle(allocate_info->commandPool);
     struct vkAllocateCommandBuffers_params params;
-    NTSTATUS status;
     uint32_t i;
 
     for (i = 0; i < allocate_info->commandBufferCount; i++)
@@ -745,8 +726,7 @@ VkResult WINAPI vkAllocateCommandBuffers(VkDevice device, const VkCommandBufferA
     params.device = device;
     params.pAllocateInfo = allocate_info;
     params.pCommandBuffers = buffers;
-    status = UNIX_CALL(vkAllocateCommandBuffers, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkAllocateCommandBuffers, &params);
     if (params.result == VK_SUCCESS)
     {
         for (i = 0; i < allocate_info->commandBufferCount; i++)
@@ -767,15 +747,13 @@ void WINAPI vkFreeCommandBuffers(VkDevice device, VkCommandPool cmd_pool, uint32
                                  const VkCommandBuffer *buffers)
 {
     struct vkFreeCommandBuffers_params params;
-    NTSTATUS status;
     uint32_t i;
 
     params.device = device;
     params.commandPool = cmd_pool;
     params.commandBufferCount = count;
     params.pCommandBuffers = buffers;
-    status = UNIX_CALL(vkFreeCommandBuffers, &params);
-    assert(!status);
+    UNIX_CALL_CHECKED(vkFreeCommandBuffers, &params);
     for (i = 0; i < count; i++)
     {
         if (!buffers[i])
diff --git a/dlls/winevulkan/loader_thunks.c b/dlls/winevulkan/loader_thunks.c
index d8d2365a0e31..6a0cfdebf598 100644
--- a/dlls/winevulkan/loader_thunks.c
+++ b/dlls/winevulkan/loader_thunks.c
@@ -21,271 +21,227 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 VkResult WINAPI vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex)
 {
     struct vkAcquireNextImage2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pAcquireInfo = pAcquireInfo;
     params.pImageIndex = pImageIndex;
-    status = UNIX_CALL(vkAcquireNextImage2KHR, &params);
-    assert(!status && "vkAcquireNextImage2KHR");
+    UNIX_CALL_CHECKED(vkAcquireNextImage2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkAcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t *pImageIndex)
 {
     struct vkAcquireNextImageKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.timeout = timeout;
     params.semaphore = semaphore;
     params.fence = fence;
     params.pImageIndex = pImageIndex;
-    status = UNIX_CALL(vkAcquireNextImageKHR, &params);
-    assert(!status && "vkAcquireNextImageKHR");
+    UNIX_CALL_CHECKED(vkAcquireNextImageKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkAcquirePerformanceConfigurationINTEL(VkDevice device, const VkPerformanceConfigurationAcquireInfoINTEL *pAcquireInfo, VkPerformanceConfigurationINTEL *pConfiguration)
 {
     struct vkAcquirePerformanceConfigurationINTEL_params params;
-    NTSTATUS status;
     params.device = device;
     params.pAcquireInfo = pAcquireInfo;
     params.pConfiguration = pConfiguration;
-    status = UNIX_CALL(vkAcquirePerformanceConfigurationINTEL, &params);
-    assert(!status && "vkAcquirePerformanceConfigurationINTEL");
+    UNIX_CALL_CHECKED(vkAcquirePerformanceConfigurationINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkAcquireProfilingLockKHR(VkDevice device, const VkAcquireProfilingLockInfoKHR *pInfo)
 {
     struct vkAcquireProfilingLockKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkAcquireProfilingLockKHR, &params);
-    assert(!status && "vkAcquireProfilingLockKHR");
+    UNIX_CALL_CHECKED(vkAcquireProfilingLockKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkAllocateDescriptorSets(VkDevice device, const VkDescriptorSetAllocateInfo *pAllocateInfo, VkDescriptorSet *pDescriptorSets)
 {
     struct vkAllocateDescriptorSets_params params;
-    NTSTATUS status;
     params.device = device;
     params.pAllocateInfo = pAllocateInfo;
     params.pDescriptorSets = pDescriptorSets;
-    status = UNIX_CALL(vkAllocateDescriptorSets, &params);
-    assert(!status && "vkAllocateDescriptorSets");
+    UNIX_CALL_CHECKED(vkAllocateDescriptorSets, &params);
     return params.result;
 }
 
 VkResult WINAPI vkAllocateMemory(VkDevice device, const VkMemoryAllocateInfo *pAllocateInfo, const VkAllocationCallbacks *pAllocator, VkDeviceMemory *pMemory)
 {
     struct vkAllocateMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.pAllocateInfo = pAllocateInfo;
     params.pAllocator = pAllocator;
     params.pMemory = pMemory;
-    status = UNIX_CALL(vkAllocateMemory, &params);
-    assert(!status && "vkAllocateMemory");
+    UNIX_CALL_CHECKED(vkAllocateMemory, &params);
     return params.result;
 }
 
 void WINAPI vkAntiLagUpdateAMD(VkDevice device, const VkAntiLagDataAMD *pData)
 {
     struct vkAntiLagUpdateAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.pData = pData;
-    status = UNIX_CALL(vkAntiLagUpdateAMD, &params);
-    assert(!status && "vkAntiLagUpdateAMD");
+    UNIX_CALL_CHECKED(vkAntiLagUpdateAMD, &params);
 }
 
 VkResult WINAPI vkBeginCommandBuffer(VkCommandBuffer commandBuffer, const VkCommandBufferBeginInfo *pBeginInfo)
 {
     struct vkBeginCommandBuffer_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.pBeginInfo = pBeginInfo;
-    status = UNIX_CALL(vkBeginCommandBuffer, &params);
-    assert(!status && "vkBeginCommandBuffer");
+    UNIX_CALL_CHECKED(vkBeginCommandBuffer, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindAccelerationStructureMemoryNV(VkDevice device, uint32_t bindInfoCount, const VkBindAccelerationStructureMemoryInfoNV *pBindInfos)
 {
     struct vkBindAccelerationStructureMemoryNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindAccelerationStructureMemoryNV, &params);
-    assert(!status && "vkBindAccelerationStructureMemoryNV");
+    UNIX_CALL_CHECKED(vkBindAccelerationStructureMemoryNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, VkDeviceSize memoryOffset)
 {
     struct vkBindBufferMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.buffer = buffer;
     params.memory = memory;
     params.memoryOffset = memoryOffset;
-    status = UNIX_CALL(vkBindBufferMemory, &params);
-    assert(!status && "vkBindBufferMemory");
+    UNIX_CALL_CHECKED(vkBindBufferMemory, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos)
 {
     struct vkBindBufferMemory2_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindBufferMemory2, &params);
-    assert(!status && "vkBindBufferMemory2");
+    UNIX_CALL_CHECKED(vkBindBufferMemory2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindBufferMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo *pBindInfos)
 {
     struct vkBindBufferMemory2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindBufferMemory2KHR, &params);
-    assert(!status && "vkBindBufferMemory2KHR");
+    UNIX_CALL_CHECKED(vkBindBufferMemory2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindDataGraphPipelineSessionMemoryARM(VkDevice device, uint32_t bindInfoCount, const VkBindDataGraphPipelineSessionMemoryInfoARM *pBindInfos)
 {
     struct vkBindDataGraphPipelineSessionMemoryARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindDataGraphPipelineSessionMemoryARM, &params);
-    assert(!status && "vkBindDataGraphPipelineSessionMemoryARM");
+    UNIX_CALL_CHECKED(vkBindDataGraphPipelineSessionMemoryARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, VkDeviceSize memoryOffset)
 {
     struct vkBindImageMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.memory = memory;
     params.memoryOffset = memoryOffset;
-    status = UNIX_CALL(vkBindImageMemory, &params);
-    assert(!status && "vkBindImageMemory");
+    UNIX_CALL_CHECKED(vkBindImageMemory, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos)
 {
     struct vkBindImageMemory2_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindImageMemory2, &params);
-    assert(!status && "vkBindImageMemory2");
+    UNIX_CALL_CHECKED(vkBindImageMemory2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo *pBindInfos)
 {
     struct vkBindImageMemory2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindImageMemory2KHR, &params);
-    assert(!status && "vkBindImageMemory2KHR");
+    UNIX_CALL_CHECKED(vkBindImageMemory2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindOpticalFlowSessionImageNV(VkDevice device, VkOpticalFlowSessionNV session, VkOpticalFlowSessionBindingPointNV bindingPoint, VkImageView view, VkImageLayout layout)
 {
     struct vkBindOpticalFlowSessionImageNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.session = session;
     params.bindingPoint = bindingPoint;
     params.view = view;
     params.layout = layout;
-    status = UNIX_CALL(vkBindOpticalFlowSessionImageNV, &params);
-    assert(!status && "vkBindOpticalFlowSessionImageNV");
+    UNIX_CALL_CHECKED(vkBindOpticalFlowSessionImageNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindTensorMemoryARM(VkDevice device, uint32_t bindInfoCount, const VkBindTensorMemoryInfoARM *pBindInfos)
 {
     struct vkBindTensorMemoryARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfos = pBindInfos;
-    status = UNIX_CALL(vkBindTensorMemoryARM, &params);
-    assert(!status && "vkBindTensorMemoryARM");
+    UNIX_CALL_CHECKED(vkBindTensorMemoryARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBindVideoSessionMemoryKHR(VkDevice device, VkVideoSessionKHR videoSession, uint32_t bindSessionMemoryInfoCount, const VkBindVideoSessionMemoryInfoKHR *pBindSessionMemoryInfos)
 {
     struct vkBindVideoSessionMemoryKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.videoSession = videoSession;
     params.bindSessionMemoryInfoCount = bindSessionMemoryInfoCount;
     params.pBindSessionMemoryInfos = pBindSessionMemoryInfos;
-    status = UNIX_CALL(vkBindVideoSessionMemoryKHR, &params);
-    assert(!status && "vkBindVideoSessionMemoryKHR");
+    UNIX_CALL_CHECKED(vkBindVideoSessionMemoryKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBuildAccelerationStructuresKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkAccelerationStructureBuildGeometryInfoKHR *pInfos, const VkAccelerationStructureBuildRangeInfoKHR * const*ppBuildRangeInfos)
 {
     struct vkBuildAccelerationStructuresKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.infoCount = infoCount;
     params.pInfos = pInfos;
     params.ppBuildRangeInfos = ppBuildRangeInfos;
-    status = UNIX_CALL(vkBuildAccelerationStructuresKHR, &params);
-    assert(!status && "vkBuildAccelerationStructuresKHR");
+    UNIX_CALL_CHECKED(vkBuildAccelerationStructuresKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkBuildMicromapsEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, uint32_t infoCount, const VkMicromapBuildInfoEXT *pInfos)
 {
     struct vkBuildMicromapsEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.infoCount = infoCount;
     params.pInfos = pInfos;
-    status = UNIX_CALL(vkBuildMicromapsEXT, &params);
-    assert(!status && "vkBuildMicromapsEXT");
+    UNIX_CALL_CHECKED(vkBuildMicromapsEXT, &params);
     return params.result;
 }
 
 void WINAPI vkClearShaderInstrumentationMetricsARM(VkDevice device, VkShaderInstrumentationARM instrumentation)
 {
     struct vkClearShaderInstrumentationMetricsARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.instrumentation = instrumentation;
-    status = UNIX_CALL(vkClearShaderInstrumentationMetricsARM, &params);
-    assert(!status && "vkClearShaderInstrumentationMetricsARM");
+    UNIX_CALL_CHECKED(vkClearShaderInstrumentationMetricsARM, &params);
 }
 
 void WINAPI vkCmdBeginConditionalRendering2EXT(VkCommandBuffer commandBuffer, const VkConditionalRenderingBeginInfo2EXT *pConditionalRenderingBegin)
@@ -323,24 +279,20 @@ void WINAPI vkCmdBeginDebugUtilsLabelEXT(VkCommandBuffer commandBuffer, const Vk
 VkResult WINAPI vkCmdBeginGpaSampleAMD(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession, const VkGpaSampleBeginInfoAMD *pGpaSampleBeginInfo, uint32_t *pSampleID)
 {
     struct vkCmdBeginGpaSampleAMD_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.gpaSession = gpaSession;
     params.pGpaSampleBeginInfo = pGpaSampleBeginInfo;
     params.pSampleID = pSampleID;
-    status = UNIX_CALL(vkCmdBeginGpaSampleAMD, &params);
-    assert(!status && "vkCmdBeginGpaSampleAMD");
+    UNIX_CALL_CHECKED(vkCmdBeginGpaSampleAMD, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCmdBeginGpaSessionAMD(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession)
 {
     struct vkCmdBeginGpaSessionAMD_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.gpaSession = gpaSession;
-    status = UNIX_CALL(vkCmdBeginGpaSessionAMD, &params);
-    assert(!status && "vkCmdBeginGpaSessionAMD");
+    UNIX_CALL_CHECKED(vkCmdBeginGpaSessionAMD, &params);
     return params.result;
 }
 
@@ -1599,11 +1551,9 @@ void WINAPI vkCmdEndGpaSampleAMD(VkCommandBuffer commandBuffer, VkGpaSessionAMD
 VkResult WINAPI vkCmdEndGpaSessionAMD(VkCommandBuffer commandBuffer, VkGpaSessionAMD gpaSession)
 {
     struct vkCmdEndGpaSessionAMD_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.gpaSession = gpaSession;
-    status = UNIX_CALL(vkCmdEndGpaSessionAMD, &params);
-    assert(!status && "vkCmdEndGpaSessionAMD");
+    UNIX_CALL_CHECKED(vkCmdEndGpaSessionAMD, &params);
     return params.result;
 }
 
@@ -2601,33 +2551,27 @@ void WINAPI vkCmdSetPatchControlPointsEXT(VkCommandBuffer commandBuffer, uint32_
 VkResult WINAPI vkCmdSetPerformanceMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceMarkerInfoINTEL *pMarkerInfo)
 {
     struct vkCmdSetPerformanceMarkerINTEL_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.pMarkerInfo = pMarkerInfo;
-    status = UNIX_CALL(vkCmdSetPerformanceMarkerINTEL, &params);
-    assert(!status && "vkCmdSetPerformanceMarkerINTEL");
+    UNIX_CALL_CHECKED(vkCmdSetPerformanceMarkerINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCmdSetPerformanceOverrideINTEL(VkCommandBuffer commandBuffer, const VkPerformanceOverrideInfoINTEL *pOverrideInfo)
 {
     struct vkCmdSetPerformanceOverrideINTEL_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.pOverrideInfo = pOverrideInfo;
-    status = UNIX_CALL(vkCmdSetPerformanceOverrideINTEL, &params);
-    assert(!status && "vkCmdSetPerformanceOverrideINTEL");
+    UNIX_CALL_CHECKED(vkCmdSetPerformanceOverrideINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCmdSetPerformanceStreamMarkerINTEL(VkCommandBuffer commandBuffer, const VkPerformanceStreamMarkerInfoINTEL *pMarkerInfo)
 {
     struct vkCmdSetPerformanceStreamMarkerINTEL_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.pMarkerInfo = pMarkerInfo;
-    status = UNIX_CALL(vkCmdSetPerformanceStreamMarkerINTEL, &params);
-    assert(!status && "vkCmdSetPerformanceStreamMarkerINTEL");
+    UNIX_CALL_CHECKED(vkCmdSetPerformanceStreamMarkerINTEL, &params);
     return params.result;
 }
 
@@ -3209,287 +3153,240 @@ void WINAPI vkCmdWriteTimestamp2KHR(VkCommandBuffer commandBuffer, VkPipelineSta
 VkResult WINAPI vkCompileDeferredNV(VkDevice device, VkPipeline pipeline, uint32_t shader)
 {
     struct vkCompileDeferredNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.shader = shader;
-    status = UNIX_CALL(vkCompileDeferredNV, &params);
-    assert(!status && "vkCompileDeferredNV");
+    UNIX_CALL_CHECKED(vkCompileDeferredNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkConvertCooperativeVectorMatrixNV(VkDevice device, const VkConvertCooperativeVectorMatrixInfoNV *pInfo)
 {
     struct vkConvertCooperativeVectorMatrixNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkConvertCooperativeVectorMatrixNV, &params);
-    assert(!status && "vkConvertCooperativeVectorMatrixNV");
+    UNIX_CALL_CHECKED(vkConvertCooperativeVectorMatrixNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureInfoKHR *pInfo)
 {
     struct vkCopyAccelerationStructureKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyAccelerationStructureKHR, &params);
-    assert(!status && "vkCopyAccelerationStructureKHR");
+    UNIX_CALL_CHECKED(vkCopyAccelerationStructureKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyAccelerationStructureToMemoryKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyAccelerationStructureToMemoryInfoKHR *pInfo)
 {
     struct vkCopyAccelerationStructureToMemoryKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyAccelerationStructureToMemoryKHR, &params);
-    assert(!status && "vkCopyAccelerationStructureToMemoryKHR");
+    UNIX_CALL_CHECKED(vkCopyAccelerationStructureToMemoryKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyImageToImage(VkDevice device, const VkCopyImageToImageInfo *pCopyImageToImageInfo)
 {
     struct vkCopyImageToImage_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyImageToImageInfo = pCopyImageToImageInfo;
-    status = UNIX_CALL(vkCopyImageToImage, &params);
-    assert(!status && "vkCopyImageToImage");
+    UNIX_CALL_CHECKED(vkCopyImageToImage, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyImageToImageEXT(VkDevice device, const VkCopyImageToImageInfo *pCopyImageToImageInfo)
 {
     struct vkCopyImageToImageEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyImageToImageInfo = pCopyImageToImageInfo;
-    status = UNIX_CALL(vkCopyImageToImageEXT, &params);
-    assert(!status && "vkCopyImageToImageEXT");
+    UNIX_CALL_CHECKED(vkCopyImageToImageEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyImageToMemory(VkDevice device, const VkCopyImageToMemoryInfo *pCopyImageToMemoryInfo)
 {
     struct vkCopyImageToMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyImageToMemoryInfo = pCopyImageToMemoryInfo;
-    status = UNIX_CALL(vkCopyImageToMemory, &params);
-    assert(!status && "vkCopyImageToMemory");
+    UNIX_CALL_CHECKED(vkCopyImageToMemory, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyImageToMemoryEXT(VkDevice device, const VkCopyImageToMemoryInfo *pCopyImageToMemoryInfo)
 {
     struct vkCopyImageToMemoryEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyImageToMemoryInfo = pCopyImageToMemoryInfo;
-    status = UNIX_CALL(vkCopyImageToMemoryEXT, &params);
-    assert(!status && "vkCopyImageToMemoryEXT");
+    UNIX_CALL_CHECKED(vkCopyImageToMemoryEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMemoryToAccelerationStructureKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToAccelerationStructureInfoKHR *pInfo)
 {
     struct vkCopyMemoryToAccelerationStructureKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyMemoryToAccelerationStructureKHR, &params);
-    assert(!status && "vkCopyMemoryToAccelerationStructureKHR");
+    UNIX_CALL_CHECKED(vkCopyMemoryToAccelerationStructureKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMemoryToImage(VkDevice device, const VkCopyMemoryToImageInfo *pCopyMemoryToImageInfo)
 {
     struct vkCopyMemoryToImage_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyMemoryToImageInfo = pCopyMemoryToImageInfo;
-    status = UNIX_CALL(vkCopyMemoryToImage, &params);
-    assert(!status && "vkCopyMemoryToImage");
+    UNIX_CALL_CHECKED(vkCopyMemoryToImage, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMemoryToImageEXT(VkDevice device, const VkCopyMemoryToImageInfo *pCopyMemoryToImageInfo)
 {
     struct vkCopyMemoryToImageEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCopyMemoryToImageInfo = pCopyMemoryToImageInfo;
-    status = UNIX_CALL(vkCopyMemoryToImageEXT, &params);
-    assert(!status && "vkCopyMemoryToImageEXT");
+    UNIX_CALL_CHECKED(vkCopyMemoryToImageEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMemoryToMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMemoryToMicromapInfoEXT *pInfo)
 {
     struct vkCopyMemoryToMicromapEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyMemoryToMicromapEXT, &params);
-    assert(!status && "vkCopyMemoryToMicromapEXT");
+    UNIX_CALL_CHECKED(vkCopyMemoryToMicromapEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMicromapEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapInfoEXT *pInfo)
 {
     struct vkCopyMicromapEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyMicromapEXT, &params);
-    assert(!status && "vkCopyMicromapEXT");
+    UNIX_CALL_CHECKED(vkCopyMicromapEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCopyMicromapToMemoryEXT(VkDevice device, VkDeferredOperationKHR deferredOperation, const VkCopyMicromapToMemoryInfoEXT *pInfo)
 {
     struct vkCopyMicromapToMemoryEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkCopyMicromapToMemoryEXT, &params);
-    assert(!status && "vkCopyMicromapToMemoryEXT");
+    UNIX_CALL_CHECKED(vkCopyMicromapToMemoryEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateAccelerationStructure2KHR(VkDevice device, const VkAccelerationStructureCreateInfo2KHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureKHR *pAccelerationStructure)
 {
     struct vkCreateAccelerationStructure2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pAccelerationStructure = pAccelerationStructure;
-    status = UNIX_CALL(vkCreateAccelerationStructure2KHR, &params);
-    assert(!status && "vkCreateAccelerationStructure2KHR");
+    UNIX_CALL_CHECKED(vkCreateAccelerationStructure2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateAccelerationStructureKHR(VkDevice device, const VkAccelerationStructureCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureKHR *pAccelerationStructure)
 {
     struct vkCreateAccelerationStructureKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pAccelerationStructure = pAccelerationStructure;
-    status = UNIX_CALL(vkCreateAccelerationStructureKHR, &params);
-    assert(!status && "vkCreateAccelerationStructureKHR");
+    UNIX_CALL_CHECKED(vkCreateAccelerationStructureKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateAccelerationStructureNV(VkDevice device, const VkAccelerationStructureCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkAccelerationStructureNV *pAccelerationStructure)
 {
     struct vkCreateAccelerationStructureNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pAccelerationStructure = pAccelerationStructure;
-    status = UNIX_CALL(vkCreateAccelerationStructureNV, &params);
-    assert(!status && "vkCreateAccelerationStructureNV");
+    UNIX_CALL_CHECKED(vkCreateAccelerationStructureNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer)
 {
     struct vkCreateBuffer_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pBuffer = pBuffer;
-    status = UNIX_CALL(vkCreateBuffer, &params);
-    assert(!status && "vkCreateBuffer");
+    UNIX_CALL_CHECKED(vkCreateBuffer, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkBufferView *pView)
 {
     struct vkCreateBufferView_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pView = pView;
-    status = UNIX_CALL(vkCreateBufferView, &params);
-    assert(!status && "vkCreateBufferView");
+    UNIX_CALL_CHECKED(vkCreateBufferView, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateComputePipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkComputePipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
 {
     struct vkCreateComputePipelines_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineCache = pipelineCache;
     params.createInfoCount = createInfoCount;
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pPipelines = pPipelines;
-    status = UNIX_CALL(vkCreateComputePipelines, &params);
-    assert(!status && "vkCreateComputePipelines");
+    UNIX_CALL_CHECKED(vkCreateComputePipelines, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateCuFunctionNVX(VkDevice device, const VkCuFunctionCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuFunctionNVX *pFunction)
 {
     struct vkCreateCuFunctionNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pFunction = pFunction;
-    status = UNIX_CALL(vkCreateCuFunctionNVX, &params);
-    assert(!status && "vkCreateCuFunctionNVX");
+    UNIX_CALL_CHECKED(vkCreateCuFunctionNVX, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateCuModuleNVX(VkDevice device, const VkCuModuleCreateInfoNVX *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkCuModuleNVX *pModule)
 {
     struct vkCreateCuModuleNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pModule = pModule;
-    status = UNIX_CALL(vkCreateCuModuleNVX, &params);
-    assert(!status && "vkCreateCuModuleNVX");
+    UNIX_CALL_CHECKED(vkCreateCuModuleNVX, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDataGraphPipelineSessionARM(VkDevice device, const VkDataGraphPipelineSessionCreateInfoARM *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDataGraphPipelineSessionARM *pSession)
 {
     struct vkCreateDataGraphPipelineSessionARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSession = pSession;
-    status = UNIX_CALL(vkCreateDataGraphPipelineSessionARM, &params);
-    assert(!status && "vkCreateDataGraphPipelineSessionARM");
+    UNIX_CALL_CHECKED(vkCreateDataGraphPipelineSessionARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDataGraphPipelinesARM(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkDataGraphPipelineCreateInfoARM *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
 {
     struct vkCreateDataGraphPipelinesARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pipelineCache = pipelineCache;
@@ -3497,341 +3394,289 @@ VkResult WINAPI vkCreateDataGraphPipelinesARM(VkDevice device, VkDeferredOperati
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pPipelines = pPipelines;
-    status = UNIX_CALL(vkCreateDataGraphPipelinesARM, &params);
-    assert(!status && "vkCreateDataGraphPipelinesARM");
+    UNIX_CALL_CHECKED(vkCreateDataGraphPipelinesARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugReportCallbackEXT *pCallback)
 {
     struct vkCreateDebugReportCallbackEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pCallback = pCallback;
-    status = UNIX_CALL(vkCreateDebugReportCallbackEXT, &params);
-    assert(!status && "vkCreateDebugReportCallbackEXT");
+    UNIX_CALL_CHECKED(vkCreateDebugReportCallbackEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDebugUtilsMessengerEXT(VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDebugUtilsMessengerEXT *pMessenger)
 {
     struct vkCreateDebugUtilsMessengerEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pMessenger = pMessenger;
-    status = UNIX_CALL(vkCreateDebugUtilsMessengerEXT, &params);
-    assert(!status && "vkCreateDebugUtilsMessengerEXT");
+    UNIX_CALL_CHECKED(vkCreateDebugUtilsMessengerEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDeferredOperationKHR(VkDevice device, const VkAllocationCallbacks *pAllocator, VkDeferredOperationKHR *pDeferredOperation)
 {
     struct vkCreateDeferredOperationKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pAllocator = pAllocator;
     params.pDeferredOperation = pDeferredOperation;
-    status = UNIX_CALL(vkCreateDeferredOperationKHR, &params);
-    assert(!status && "vkCreateDeferredOperationKHR");
+    UNIX_CALL_CHECKED(vkCreateDeferredOperationKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDescriptorPool(VkDevice device, const VkDescriptorPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorPool *pDescriptorPool)
 {
     struct vkCreateDescriptorPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pDescriptorPool = pDescriptorPool;
-    status = UNIX_CALL(vkCreateDescriptorPool, &params);
-    assert(!status && "vkCreateDescriptorPool");
+    UNIX_CALL_CHECKED(vkCreateDescriptorPool, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDescriptorSetLayout(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorSetLayout *pSetLayout)
 {
     struct vkCreateDescriptorSetLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSetLayout = pSetLayout;
-    status = UNIX_CALL(vkCreateDescriptorSetLayout, &params);
-    assert(!status && "vkCreateDescriptorSetLayout");
+    UNIX_CALL_CHECKED(vkCreateDescriptorSetLayout, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate)
 {
     struct vkCreateDescriptorUpdateTemplate_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pDescriptorUpdateTemplate = pDescriptorUpdateTemplate;
-    status = UNIX_CALL(vkCreateDescriptorUpdateTemplate, &params);
-    assert(!status && "vkCreateDescriptorUpdateTemplate");
+    UNIX_CALL_CHECKED(vkCreateDescriptorUpdateTemplate, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateDescriptorUpdateTemplateKHR(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkDescriptorUpdateTemplate *pDescriptorUpdateTemplate)
 {
     struct vkCreateDescriptorUpdateTemplateKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pDescriptorUpdateTemplate = pDescriptorUpdateTemplate;
-    status = UNIX_CALL(vkCreateDescriptorUpdateTemplateKHR, &params);
-    assert(!status && "vkCreateDescriptorUpdateTemplateKHR");
+    UNIX_CALL_CHECKED(vkCreateDescriptorUpdateTemplateKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateEvent(VkDevice device, const VkEventCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkEvent *pEvent)
 {
     struct vkCreateEvent_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pEvent = pEvent;
-    status = UNIX_CALL(vkCreateEvent, &params);
-    assert(!status && "vkCreateEvent");
+    UNIX_CALL_CHECKED(vkCreateEvent, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateFence(VkDevice device, const VkFenceCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFence *pFence)
 {
     struct vkCreateFence_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pFence = pFence;
-    status = UNIX_CALL(vkCreateFence, &params);
-    assert(!status && "vkCreateFence");
+    UNIX_CALL_CHECKED(vkCreateFence, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateFramebuffer(VkDevice device, const VkFramebufferCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkFramebuffer *pFramebuffer)
 {
     struct vkCreateFramebuffer_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pFramebuffer = pFramebuffer;
-    status = UNIX_CALL(vkCreateFramebuffer, &params);
-    assert(!status && "vkCreateFramebuffer");
+    UNIX_CALL_CHECKED(vkCreateFramebuffer, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateGpaSessionAMD(VkDevice device, const VkGpaSessionCreateInfoAMD *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkGpaSessionAMD *pGpaSession)
 {
     struct vkCreateGpaSessionAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pGpaSession = pGpaSession;
-    status = UNIX_CALL(vkCreateGpaSessionAMD, &params);
-    assert(!status && "vkCreateGpaSessionAMD");
+    UNIX_CALL_CHECKED(vkCreateGpaSessionAMD, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateGraphicsPipelines(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkGraphicsPipelineCreateInfo *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
 {
     struct vkCreateGraphicsPipelines_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineCache = pipelineCache;
     params.createInfoCount = createInfoCount;
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pPipelines = pPipelines;
-    status = UNIX_CALL(vkCreateGraphicsPipelines, &params);
-    assert(!status && "vkCreateGraphicsPipelines");
+    UNIX_CALL_CHECKED(vkCreateGraphicsPipelines, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImage *pImage)
 {
     struct vkCreateImage_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pImage = pImage;
-    status = UNIX_CALL(vkCreateImage, &params);
-    assert(!status && "vkCreateImage");
+    UNIX_CALL_CHECKED(vkCreateImage, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkImageView *pView)
 {
     struct vkCreateImageView_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pView = pView;
-    status = UNIX_CALL(vkCreateImageView, &params);
-    assert(!status && "vkCreateImageView");
+    UNIX_CALL_CHECKED(vkCreateImageView, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateIndirectCommandsLayoutEXT(VkDevice device, const VkIndirectCommandsLayoutCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkIndirectCommandsLayoutEXT *pIndirectCommandsLayout)
 {
     struct vkCreateIndirectCommandsLayoutEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pIndirectCommandsLayout = pIndirectCommandsLayout;
-    status = UNIX_CALL(vkCreateIndirectCommandsLayoutEXT, &params);
-    assert(!status && "vkCreateIndirectCommandsLayoutEXT");
+    UNIX_CALL_CHECKED(vkCreateIndirectCommandsLayoutEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateIndirectCommandsLayoutNV(VkDevice device, const VkIndirectCommandsLayoutCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkIndirectCommandsLayoutNV *pIndirectCommandsLayout)
 {
     struct vkCreateIndirectCommandsLayoutNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pIndirectCommandsLayout = pIndirectCommandsLayout;
-    status = UNIX_CALL(vkCreateIndirectCommandsLayoutNV, &params);
-    assert(!status && "vkCreateIndirectCommandsLayoutNV");
+    UNIX_CALL_CHECKED(vkCreateIndirectCommandsLayoutNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateIndirectExecutionSetEXT(VkDevice device, const VkIndirectExecutionSetCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkIndirectExecutionSetEXT *pIndirectExecutionSet)
 {
     struct vkCreateIndirectExecutionSetEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pIndirectExecutionSet = pIndirectExecutionSet;
-    status = UNIX_CALL(vkCreateIndirectExecutionSetEXT, &params);
-    assert(!status && "vkCreateIndirectExecutionSetEXT");
+    UNIX_CALL_CHECKED(vkCreateIndirectExecutionSetEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateMicromapEXT(VkDevice device, const VkMicromapCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkMicromapEXT *pMicromap)
 {
     struct vkCreateMicromapEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pMicromap = pMicromap;
-    status = UNIX_CALL(vkCreateMicromapEXT, &params);
-    assert(!status && "vkCreateMicromapEXT");
+    UNIX_CALL_CHECKED(vkCreateMicromapEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateOpticalFlowSessionNV(VkDevice device, const VkOpticalFlowSessionCreateInfoNV *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkOpticalFlowSessionNV *pSession)
 {
     struct vkCreateOpticalFlowSessionNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSession = pSession;
-    status = UNIX_CALL(vkCreateOpticalFlowSessionNV, &params);
-    assert(!status && "vkCreateOpticalFlowSessionNV");
+    UNIX_CALL_CHECKED(vkCreateOpticalFlowSessionNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreatePipelineBinariesKHR(VkDevice device, const VkPipelineBinaryCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineBinaryHandlesInfoKHR *pBinaries)
 {
     struct vkCreatePipelineBinariesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pBinaries = pBinaries;
-    status = UNIX_CALL(vkCreatePipelineBinariesKHR, &params);
-    assert(!status && "vkCreatePipelineBinariesKHR");
+    UNIX_CALL_CHECKED(vkCreatePipelineBinariesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreatePipelineCache(VkDevice device, const VkPipelineCacheCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineCache *pPipelineCache)
 {
     struct vkCreatePipelineCache_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pPipelineCache = pPipelineCache;
-    status = UNIX_CALL(vkCreatePipelineCache, &params);
-    assert(!status && "vkCreatePipelineCache");
+    UNIX_CALL_CHECKED(vkCreatePipelineCache, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreatePipelineLayout(VkDevice device, const VkPipelineLayoutCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPipelineLayout *pPipelineLayout)
 {
     struct vkCreatePipelineLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pPipelineLayout = pPipelineLayout;
-    status = UNIX_CALL(vkCreatePipelineLayout, &params);
-    assert(!status && "vkCreatePipelineLayout");
+    UNIX_CALL_CHECKED(vkCreatePipelineLayout, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreatePrivateDataSlot(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot)
 {
     struct vkCreatePrivateDataSlot_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pPrivateDataSlot = pPrivateDataSlot;
-    status = UNIX_CALL(vkCreatePrivateDataSlot, &params);
-    assert(!status && "vkCreatePrivateDataSlot");
+    UNIX_CALL_CHECKED(vkCreatePrivateDataSlot, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreatePrivateDataSlotEXT(VkDevice device, const VkPrivateDataSlotCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkPrivateDataSlot *pPrivateDataSlot)
 {
     struct vkCreatePrivateDataSlotEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pPrivateDataSlot = pPrivateDataSlot;
-    status = UNIX_CALL(vkCreatePrivateDataSlotEXT, &params);
-    assert(!status && "vkCreatePrivateDataSlotEXT");
+    UNIX_CALL_CHECKED(vkCreatePrivateDataSlotEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkQueryPool *pQueryPool)
 {
     struct vkCreateQueryPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pQueryPool = pQueryPool;
-    status = UNIX_CALL(vkCreateQueryPool, &params);
-    assert(!status && "vkCreateQueryPool");
+    UNIX_CALL_CHECKED(vkCreateQueryPool, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperationKHR deferredOperation, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoKHR *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
 {
     struct vkCreateRayTracingPipelinesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.deferredOperation = deferredOperation;
     params.pipelineCache = pipelineCache;
@@ -3839,274 +3684,232 @@ VkResult WINAPI vkCreateRayTracingPipelinesKHR(VkDevice device, VkDeferredOperat
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pPipelines = pPipelines;
-    status = UNIX_CALL(vkCreateRayTracingPipelinesKHR, &params);
-    assert(!status && "vkCreateRayTracingPipelinesKHR");
+    UNIX_CALL_CHECKED(vkCreateRayTracingPipelinesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateRayTracingPipelinesNV(VkDevice device, VkPipelineCache pipelineCache, uint32_t createInfoCount, const VkRayTracingPipelineCreateInfoNV *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkPipeline *pPipelines)
 {
     struct vkCreateRayTracingPipelinesNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineCache = pipelineCache;
     params.createInfoCount = createInfoCount;
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pPipelines = pPipelines;
-    status = UNIX_CALL(vkCreateRayTracingPipelinesNV, &params);
-    assert(!status && "vkCreateRayTracingPipelinesNV");
+    UNIX_CALL_CHECKED(vkCreateRayTracingPipelinesNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateRenderPass(VkDevice device, const VkRenderPassCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass)
 {
     struct vkCreateRenderPass_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pRenderPass = pRenderPass;
-    status = UNIX_CALL(vkCreateRenderPass, &params);
-    assert(!status && "vkCreateRenderPass");
+    UNIX_CALL_CHECKED(vkCreateRenderPass, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass)
 {
     struct vkCreateRenderPass2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pRenderPass = pRenderPass;
-    status = UNIX_CALL(vkCreateRenderPass2, &params);
-    assert(!status && "vkCreateRenderPass2");
+    UNIX_CALL_CHECKED(vkCreateRenderPass2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateRenderPass2KHR(VkDevice device, const VkRenderPassCreateInfo2 *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkRenderPass *pRenderPass)
 {
     struct vkCreateRenderPass2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pRenderPass = pRenderPass;
-    status = UNIX_CALL(vkCreateRenderPass2KHR, &params);
-    assert(!status && "vkCreateRenderPass2KHR");
+    UNIX_CALL_CHECKED(vkCreateRenderPass2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateSampler(VkDevice device, const VkSamplerCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSampler *pSampler)
 {
     struct vkCreateSampler_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSampler = pSampler;
-    status = UNIX_CALL(vkCreateSampler, &params);
-    assert(!status && "vkCreateSampler");
+    UNIX_CALL_CHECKED(vkCreateSampler, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion)
 {
     struct vkCreateSamplerYcbcrConversion_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pYcbcrConversion = pYcbcrConversion;
-    status = UNIX_CALL(vkCreateSamplerYcbcrConversion, &params);
-    assert(!status && "vkCreateSamplerYcbcrConversion");
+    UNIX_CALL_CHECKED(vkCreateSamplerYcbcrConversion, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateSamplerYcbcrConversionKHR(VkDevice device, const VkSamplerYcbcrConversionCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSamplerYcbcrConversion *pYcbcrConversion)
 {
     struct vkCreateSamplerYcbcrConversionKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pYcbcrConversion = pYcbcrConversion;
-    status = UNIX_CALL(vkCreateSamplerYcbcrConversionKHR, &params);
-    assert(!status && "vkCreateSamplerYcbcrConversionKHR");
+    UNIX_CALL_CHECKED(vkCreateSamplerYcbcrConversionKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateSemaphore(VkDevice device, const VkSemaphoreCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSemaphore *pSemaphore)
 {
     struct vkCreateSemaphore_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSemaphore = pSemaphore;
-    status = UNIX_CALL(vkCreateSemaphore, &params);
-    assert(!status && "vkCreateSemaphore");
+    UNIX_CALL_CHECKED(vkCreateSemaphore, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateShaderInstrumentationARM(VkDevice device, const VkShaderInstrumentationCreateInfoARM *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderInstrumentationARM *pInstrumentation)
 {
     struct vkCreateShaderInstrumentationARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pInstrumentation = pInstrumentation;
-    status = UNIX_CALL(vkCreateShaderInstrumentationARM, &params);
-    assert(!status && "vkCreateShaderInstrumentationARM");
+    UNIX_CALL_CHECKED(vkCreateShaderInstrumentationARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateShaderModule(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkShaderModule *pShaderModule)
 {
     struct vkCreateShaderModule_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pShaderModule = pShaderModule;
-    status = UNIX_CALL(vkCreateShaderModule, &params);
-    assert(!status && "vkCreateShaderModule");
+    UNIX_CALL_CHECKED(vkCreateShaderModule, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateShadersEXT(VkDevice device, uint32_t createInfoCount, const VkShaderCreateInfoEXT *pCreateInfos, const VkAllocationCallbacks *pAllocator, VkShaderEXT *pShaders)
 {
     struct vkCreateShadersEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.createInfoCount = createInfoCount;
     params.pCreateInfos = pCreateInfos;
     params.pAllocator = pAllocator;
     params.pShaders = pShaders;
-    status = UNIX_CALL(vkCreateShadersEXT, &params);
-    assert(!status && "vkCreateShadersEXT");
+    UNIX_CALL_CHECKED(vkCreateShadersEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateSwapchainKHR(VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSwapchainKHR *pSwapchain)
 {
     struct vkCreateSwapchainKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSwapchain = pSwapchain;
-    status = UNIX_CALL(vkCreateSwapchainKHR, &params);
-    assert(!status && "vkCreateSwapchainKHR");
+    UNIX_CALL_CHECKED(vkCreateSwapchainKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateTensorARM(VkDevice device, const VkTensorCreateInfoARM *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkTensorARM *pTensor)
 {
     struct vkCreateTensorARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pTensor = pTensor;
-    status = UNIX_CALL(vkCreateTensorARM, &params);
-    assert(!status && "vkCreateTensorARM");
+    UNIX_CALL_CHECKED(vkCreateTensorARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateTensorViewARM(VkDevice device, const VkTensorViewCreateInfoARM *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkTensorViewARM *pView)
 {
     struct vkCreateTensorViewARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pView = pView;
-    status = UNIX_CALL(vkCreateTensorViewARM, &params);
-    assert(!status && "vkCreateTensorViewARM");
+    UNIX_CALL_CHECKED(vkCreateTensorViewARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateValidationCacheEXT(VkDevice device, const VkValidationCacheCreateInfoEXT *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkValidationCacheEXT *pValidationCache)
 {
     struct vkCreateValidationCacheEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pValidationCache = pValidationCache;
-    status = UNIX_CALL(vkCreateValidationCacheEXT, &params);
-    assert(!status && "vkCreateValidationCacheEXT");
+    UNIX_CALL_CHECKED(vkCreateValidationCacheEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateVideoSessionKHR(VkDevice device, const VkVideoSessionCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkVideoSessionKHR *pVideoSession)
 {
     struct vkCreateVideoSessionKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pVideoSession = pVideoSession;
-    status = UNIX_CALL(vkCreateVideoSessionKHR, &params);
-    assert(!status && "vkCreateVideoSessionKHR");
+    UNIX_CALL_CHECKED(vkCreateVideoSessionKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateVideoSessionParametersKHR(VkDevice device, const VkVideoSessionParametersCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkVideoSessionParametersKHR *pVideoSessionParameters)
 {
     struct vkCreateVideoSessionParametersKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pVideoSessionParameters = pVideoSessionParameters;
-    status = UNIX_CALL(vkCreateVideoSessionParametersKHR, &params);
-    assert(!status && "vkCreateVideoSessionParametersKHR");
+    UNIX_CALL_CHECKED(vkCreateVideoSessionParametersKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkCreateWin32SurfaceKHR(VkInstance instance, const VkWin32SurfaceCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks *pAllocator, VkSurfaceKHR *pSurface)
 {
     struct vkCreateWin32SurfaceKHR_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pCreateInfo = pCreateInfo;
     params.pAllocator = pAllocator;
     params.pSurface = pSurface;
-    status = UNIX_CALL(vkCreateWin32SurfaceKHR, &params);
-    assert(!status && "vkCreateWin32SurfaceKHR");
+    UNIX_CALL_CHECKED(vkCreateWin32SurfaceKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkDebugMarkerSetObjectNameEXT(VkDevice device, const VkDebugMarkerObjectNameInfoEXT *pNameInfo)
 {
     struct vkDebugMarkerSetObjectNameEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pNameInfo = pNameInfo;
-    status = UNIX_CALL(vkDebugMarkerSetObjectNameEXT, &params);
-    assert(!status && "vkDebugMarkerSetObjectNameEXT");
+    UNIX_CALL_CHECKED(vkDebugMarkerSetObjectNameEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkDebugMarkerSetObjectTagEXT(VkDevice device, const VkDebugMarkerObjectTagInfoEXT *pTagInfo)
 {
     struct vkDebugMarkerSetObjectTagEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pTagInfo = pTagInfo;
-    status = UNIX_CALL(vkDebugMarkerSetObjectTagEXT, &params);
-    assert(!status && "vkDebugMarkerSetObjectTagEXT");
+    UNIX_CALL_CHECKED(vkDebugMarkerSetObjectTagEXT, &params);
     return params.result;
 }
 
 void WINAPI vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char *pLayerPrefix, const char *pMessage)
 {
     struct vkDebugReportMessageEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.flags = flags;
     params.objectType = objectType;
@@ -4115,950 +3918,783 @@ void WINAPI vkDebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT f
     params.messageCode = messageCode;
     params.pLayerPrefix = pLayerPrefix;
     params.pMessage = pMessage;
-    status = UNIX_CALL(vkDebugReportMessageEXT, &params);
-    assert(!status && "vkDebugReportMessageEXT");
+    UNIX_CALL_CHECKED(vkDebugReportMessageEXT, &params);
 }
 
 VkResult WINAPI vkDeferredOperationJoinKHR(VkDevice device, VkDeferredOperationKHR operation)
 {
     struct vkDeferredOperationJoinKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.operation = operation;
-    status = UNIX_CALL(vkDeferredOperationJoinKHR, &params);
-    assert(!status && "vkDeferredOperationJoinKHR");
+    UNIX_CALL_CHECKED(vkDeferredOperationJoinKHR, &params);
     return params.result;
 }
 
 void WINAPI vkDestroyAccelerationStructureKHR(VkDevice device, VkAccelerationStructureKHR accelerationStructure, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyAccelerationStructureKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.accelerationStructure = accelerationStructure;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyAccelerationStructureKHR, &params);
-    assert(!status && "vkDestroyAccelerationStructureKHR");
+    UNIX_CALL_CHECKED(vkDestroyAccelerationStructureKHR, &params);
 }
 
 void WINAPI vkDestroyAccelerationStructureNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyAccelerationStructureNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.accelerationStructure = accelerationStructure;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyAccelerationStructureNV, &params);
-    assert(!status && "vkDestroyAccelerationStructureNV");
+    UNIX_CALL_CHECKED(vkDestroyAccelerationStructureNV, &params);
 }
 
 void WINAPI vkDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyBuffer_params params;
-    NTSTATUS status;
     params.device = device;
     params.buffer = buffer;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyBuffer, &params);
-    assert(!status && "vkDestroyBuffer");
+    UNIX_CALL_CHECKED(vkDestroyBuffer, &params);
 }
 
 void WINAPI vkDestroyBufferView(VkDevice device, VkBufferView bufferView, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyBufferView_params params;
-    NTSTATUS status;
     params.device = device;
     params.bufferView = bufferView;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyBufferView, &params);
-    assert(!status && "vkDestroyBufferView");
+    UNIX_CALL_CHECKED(vkDestroyBufferView, &params);
 }
 
 void WINAPI vkDestroyCuFunctionNVX(VkDevice device, VkCuFunctionNVX function, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyCuFunctionNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.function = function;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyCuFunctionNVX, &params);
-    assert(!status && "vkDestroyCuFunctionNVX");
+    UNIX_CALL_CHECKED(vkDestroyCuFunctionNVX, &params);
 }
 
 void WINAPI vkDestroyCuModuleNVX(VkDevice device, VkCuModuleNVX module, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyCuModuleNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.module = module;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyCuModuleNVX, &params);
-    assert(!status && "vkDestroyCuModuleNVX");
+    UNIX_CALL_CHECKED(vkDestroyCuModuleNVX, &params);
 }
 
 void WINAPI vkDestroyDataGraphPipelineSessionARM(VkDevice device, VkDataGraphPipelineSessionARM session, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDataGraphPipelineSessionARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.session = session;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDataGraphPipelineSessionARM, &params);
-    assert(!status && "vkDestroyDataGraphPipelineSessionARM");
+    UNIX_CALL_CHECKED(vkDestroyDataGraphPipelineSessionARM, &params);
 }
 
 void WINAPI vkDestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDebugReportCallbackEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.callback = callback;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDebugReportCallbackEXT, &params);
-    assert(!status && "vkDestroyDebugReportCallbackEXT");
+    UNIX_CALL_CHECKED(vkDestroyDebugReportCallbackEXT, &params);
 }
 
 void WINAPI vkDestroyDebugUtilsMessengerEXT(VkInstance instance, VkDebugUtilsMessengerEXT messenger, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDebugUtilsMessengerEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.messenger = messenger;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDebugUtilsMessengerEXT, &params);
-    assert(!status && "vkDestroyDebugUtilsMessengerEXT");
+    UNIX_CALL_CHECKED(vkDestroyDebugUtilsMessengerEXT, &params);
 }
 
 void WINAPI vkDestroyDeferredOperationKHR(VkDevice device, VkDeferredOperationKHR operation, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDeferredOperationKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.operation = operation;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDeferredOperationKHR, &params);
-    assert(!status && "vkDestroyDeferredOperationKHR");
+    UNIX_CALL_CHECKED(vkDestroyDeferredOperationKHR, &params);
 }
 
 void WINAPI vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDescriptorPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorPool = descriptorPool;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDescriptorPool, &params);
-    assert(!status && "vkDestroyDescriptorPool");
+    UNIX_CALL_CHECKED(vkDestroyDescriptorPool, &params);
 }
 
 void WINAPI vkDestroyDescriptorSetLayout(VkDevice device, VkDescriptorSetLayout descriptorSetLayout, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDescriptorSetLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorSetLayout = descriptorSetLayout;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDescriptorSetLayout, &params);
-    assert(!status && "vkDestroyDescriptorSetLayout");
+    UNIX_CALL_CHECKED(vkDestroyDescriptorSetLayout, &params);
 }
 
 void WINAPI vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDescriptorUpdateTemplate_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorUpdateTemplate = descriptorUpdateTemplate;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDescriptorUpdateTemplate, &params);
-    assert(!status && "vkDestroyDescriptorUpdateTemplate");
+    UNIX_CALL_CHECKED(vkDestroyDescriptorUpdateTemplate, &params);
 }
 
 void WINAPI vkDestroyDescriptorUpdateTemplateKHR(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyDescriptorUpdateTemplateKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorUpdateTemplate = descriptorUpdateTemplate;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyDescriptorUpdateTemplateKHR, &params);
-    assert(!status && "vkDestroyDescriptorUpdateTemplateKHR");
+    UNIX_CALL_CHECKED(vkDestroyDescriptorUpdateTemplateKHR, &params);
 }
 
 void WINAPI vkDestroyEvent(VkDevice device, VkEvent event, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyEvent_params params;
-    NTSTATUS status;
     params.device = device;
     params.event = event;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyEvent, &params);
-    assert(!status && "vkDestroyEvent");
+    UNIX_CALL_CHECKED(vkDestroyEvent, &params);
 }
 
 void WINAPI vkDestroyFence(VkDevice device, VkFence fence, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyFence_params params;
-    NTSTATUS status;
     params.device = device;
     params.fence = fence;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyFence, &params);
-    assert(!status && "vkDestroyFence");
+    UNIX_CALL_CHECKED(vkDestroyFence, &params);
 }
 
 void WINAPI vkDestroyFramebuffer(VkDevice device, VkFramebuffer framebuffer, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyFramebuffer_params params;
-    NTSTATUS status;
     params.device = device;
     params.framebuffer = framebuffer;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyFramebuffer, &params);
-    assert(!status && "vkDestroyFramebuffer");
+    UNIX_CALL_CHECKED(vkDestroyFramebuffer, &params);
 }
 
 void WINAPI vkDestroyGpaSessionAMD(VkDevice device, VkGpaSessionAMD gpaSession, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyGpaSessionAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.gpaSession = gpaSession;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyGpaSessionAMD, &params);
-    assert(!status && "vkDestroyGpaSessionAMD");
+    UNIX_CALL_CHECKED(vkDestroyGpaSessionAMD, &params);
 }
 
 void WINAPI vkDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyImage_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyImage, &params);
-    assert(!status && "vkDestroyImage");
+    UNIX_CALL_CHECKED(vkDestroyImage, &params);
 }
 
 void WINAPI vkDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyImageView_params params;
-    NTSTATUS status;
     params.device = device;
     params.imageView = imageView;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyImageView, &params);
-    assert(!status && "vkDestroyImageView");
+    UNIX_CALL_CHECKED(vkDestroyImageView, &params);
 }
 
 void WINAPI vkDestroyIndirectCommandsLayoutEXT(VkDevice device, VkIndirectCommandsLayoutEXT indirectCommandsLayout, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyIndirectCommandsLayoutEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.indirectCommandsLayout = indirectCommandsLayout;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyIndirectCommandsLayoutEXT, &params);
-    assert(!status && "vkDestroyIndirectCommandsLayoutEXT");
+    UNIX_CALL_CHECKED(vkDestroyIndirectCommandsLayoutEXT, &params);
 }
 
 void WINAPI vkDestroyIndirectCommandsLayoutNV(VkDevice device, VkIndirectCommandsLayoutNV indirectCommandsLayout, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyIndirectCommandsLayoutNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.indirectCommandsLayout = indirectCommandsLayout;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyIndirectCommandsLayoutNV, &params);
-    assert(!status && "vkDestroyIndirectCommandsLayoutNV");
+    UNIX_CALL_CHECKED(vkDestroyIndirectCommandsLayoutNV, &params);
 }
 
 void WINAPI vkDestroyIndirectExecutionSetEXT(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyIndirectExecutionSetEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.indirectExecutionSet = indirectExecutionSet;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyIndirectExecutionSetEXT, &params);
-    assert(!status && "vkDestroyIndirectExecutionSetEXT");
+    UNIX_CALL_CHECKED(vkDestroyIndirectExecutionSetEXT, &params);
 }
 
 void WINAPI vkDestroyMicromapEXT(VkDevice device, VkMicromapEXT micromap, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyMicromapEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.micromap = micromap;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyMicromapEXT, &params);
-    assert(!status && "vkDestroyMicromapEXT");
+    UNIX_CALL_CHECKED(vkDestroyMicromapEXT, &params);
 }
 
 void WINAPI vkDestroyOpticalFlowSessionNV(VkDevice device, VkOpticalFlowSessionNV session, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyOpticalFlowSessionNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.session = session;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyOpticalFlowSessionNV, &params);
-    assert(!status && "vkDestroyOpticalFlowSessionNV");
+    UNIX_CALL_CHECKED(vkDestroyOpticalFlowSessionNV, &params);
 }
 
 void WINAPI vkDestroyPipeline(VkDevice device, VkPipeline pipeline, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPipeline_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPipeline, &params);
-    assert(!status && "vkDestroyPipeline");
+    UNIX_CALL_CHECKED(vkDestroyPipeline, &params);
 }
 
 void WINAPI vkDestroyPipelineBinaryKHR(VkDevice device, VkPipelineBinaryKHR pipelineBinary, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPipelineBinaryKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineBinary = pipelineBinary;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPipelineBinaryKHR, &params);
-    assert(!status && "vkDestroyPipelineBinaryKHR");
+    UNIX_CALL_CHECKED(vkDestroyPipelineBinaryKHR, &params);
 }
 
 void WINAPI vkDestroyPipelineCache(VkDevice device, VkPipelineCache pipelineCache, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPipelineCache_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineCache = pipelineCache;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPipelineCache, &params);
-    assert(!status && "vkDestroyPipelineCache");
+    UNIX_CALL_CHECKED(vkDestroyPipelineCache, &params);
 }
 
 void WINAPI vkDestroyPipelineLayout(VkDevice device, VkPipelineLayout pipelineLayout, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPipelineLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineLayout = pipelineLayout;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPipelineLayout, &params);
-    assert(!status && "vkDestroyPipelineLayout");
+    UNIX_CALL_CHECKED(vkDestroyPipelineLayout, &params);
 }
 
 void WINAPI vkDestroyPrivateDataSlot(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPrivateDataSlot_params params;
-    NTSTATUS status;
     params.device = device;
     params.privateDataSlot = privateDataSlot;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPrivateDataSlot, &params);
-    assert(!status && "vkDestroyPrivateDataSlot");
+    UNIX_CALL_CHECKED(vkDestroyPrivateDataSlot, &params);
 }
 
 void WINAPI vkDestroyPrivateDataSlotEXT(VkDevice device, VkPrivateDataSlot privateDataSlot, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyPrivateDataSlotEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.privateDataSlot = privateDataSlot;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyPrivateDataSlotEXT, &params);
-    assert(!status && "vkDestroyPrivateDataSlotEXT");
+    UNIX_CALL_CHECKED(vkDestroyPrivateDataSlotEXT, &params);
 }
 
 void WINAPI vkDestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyQueryPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.queryPool = queryPool;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyQueryPool, &params);
-    assert(!status && "vkDestroyQueryPool");
+    UNIX_CALL_CHECKED(vkDestroyQueryPool, &params);
 }
 
 void WINAPI vkDestroyRenderPass(VkDevice device, VkRenderPass renderPass, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyRenderPass_params params;
-    NTSTATUS status;
     params.device = device;
     params.renderPass = renderPass;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyRenderPass, &params);
-    assert(!status && "vkDestroyRenderPass");
+    UNIX_CALL_CHECKED(vkDestroyRenderPass, &params);
 }
 
 void WINAPI vkDestroySampler(VkDevice device, VkSampler sampler, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySampler_params params;
-    NTSTATUS status;
     params.device = device;
     params.sampler = sampler;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySampler, &params);
-    assert(!status && "vkDestroySampler");
+    UNIX_CALL_CHECKED(vkDestroySampler, &params);
 }
 
 void WINAPI vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySamplerYcbcrConversion_params params;
-    NTSTATUS status;
     params.device = device;
     params.ycbcrConversion = ycbcrConversion;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySamplerYcbcrConversion, &params);
-    assert(!status && "vkDestroySamplerYcbcrConversion");
+    UNIX_CALL_CHECKED(vkDestroySamplerYcbcrConversion, &params);
 }
 
 void WINAPI vkDestroySamplerYcbcrConversionKHR(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySamplerYcbcrConversionKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.ycbcrConversion = ycbcrConversion;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySamplerYcbcrConversionKHR, &params);
-    assert(!status && "vkDestroySamplerYcbcrConversionKHR");
+    UNIX_CALL_CHECKED(vkDestroySamplerYcbcrConversionKHR, &params);
 }
 
 void WINAPI vkDestroySemaphore(VkDevice device, VkSemaphore semaphore, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySemaphore_params params;
-    NTSTATUS status;
     params.device = device;
     params.semaphore = semaphore;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySemaphore, &params);
-    assert(!status && "vkDestroySemaphore");
+    UNIX_CALL_CHECKED(vkDestroySemaphore, &params);
 }
 
 void WINAPI vkDestroyShaderEXT(VkDevice device, VkShaderEXT shader, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyShaderEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.shader = shader;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyShaderEXT, &params);
-    assert(!status && "vkDestroyShaderEXT");
+    UNIX_CALL_CHECKED(vkDestroyShaderEXT, &params);
 }
 
 void WINAPI vkDestroyShaderInstrumentationARM(VkDevice device, VkShaderInstrumentationARM instrumentation, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyShaderInstrumentationARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.instrumentation = instrumentation;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyShaderInstrumentationARM, &params);
-    assert(!status && "vkDestroyShaderInstrumentationARM");
+    UNIX_CALL_CHECKED(vkDestroyShaderInstrumentationARM, &params);
 }
 
 void WINAPI vkDestroyShaderModule(VkDevice device, VkShaderModule shaderModule, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyShaderModule_params params;
-    NTSTATUS status;
     params.device = device;
     params.shaderModule = shaderModule;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyShaderModule, &params);
-    assert(!status && "vkDestroyShaderModule");
+    UNIX_CALL_CHECKED(vkDestroyShaderModule, &params);
 }
 
 void WINAPI vkDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySurfaceKHR_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.surface = surface;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySurfaceKHR, &params);
-    assert(!status && "vkDestroySurfaceKHR");
+    UNIX_CALL_CHECKED(vkDestroySurfaceKHR, &params);
 }
 
 void WINAPI vkDestroySwapchainKHR(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroySwapchainKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroySwapchainKHR, &params);
-    assert(!status && "vkDestroySwapchainKHR");
+    UNIX_CALL_CHECKED(vkDestroySwapchainKHR, &params);
 }
 
 void WINAPI vkDestroyTensorARM(VkDevice device, VkTensorARM tensor, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyTensorARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.tensor = tensor;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyTensorARM, &params);
-    assert(!status && "vkDestroyTensorARM");
+    UNIX_CALL_CHECKED(vkDestroyTensorARM, &params);
 }
 
 void WINAPI vkDestroyTensorViewARM(VkDevice device, VkTensorViewARM tensorView, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyTensorViewARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.tensorView = tensorView;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyTensorViewARM, &params);
-    assert(!status && "vkDestroyTensorViewARM");
+    UNIX_CALL_CHECKED(vkDestroyTensorViewARM, &params);
 }
 
 void WINAPI vkDestroyValidationCacheEXT(VkDevice device, VkValidationCacheEXT validationCache, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyValidationCacheEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.validationCache = validationCache;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyValidationCacheEXT, &params);
-    assert(!status && "vkDestroyValidationCacheEXT");
+    UNIX_CALL_CHECKED(vkDestroyValidationCacheEXT, &params);
 }
 
 void WINAPI vkDestroyVideoSessionKHR(VkDevice device, VkVideoSessionKHR videoSession, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyVideoSessionKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.videoSession = videoSession;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyVideoSessionKHR, &params);
-    assert(!status && "vkDestroyVideoSessionKHR");
+    UNIX_CALL_CHECKED(vkDestroyVideoSessionKHR, &params);
 }
 
 void WINAPI vkDestroyVideoSessionParametersKHR(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkAllocationCallbacks *pAllocator)
 {
     struct vkDestroyVideoSessionParametersKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.videoSessionParameters = videoSessionParameters;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkDestroyVideoSessionParametersKHR, &params);
-    assert(!status && "vkDestroyVideoSessionParametersKHR");
+    UNIX_CALL_CHECKED(vkDestroyVideoSessionParametersKHR, &params);
 }
 
 VkResult WINAPI vkDeviceWaitIdle(VkDevice device)
 {
     struct vkDeviceWaitIdle_params params;
-    NTSTATUS status;
     params.device = device;
-    status = UNIX_CALL(vkDeviceWaitIdle, &params);
-    assert(!status && "vkDeviceWaitIdle");
+    UNIX_CALL_CHECKED(vkDeviceWaitIdle, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEndCommandBuffer(VkCommandBuffer commandBuffer)
 {
     struct vkEndCommandBuffer_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
-    status = UNIX_CALL(vkEndCommandBuffer, &params);
-    assert(!status && "vkEndCommandBuffer");
+    UNIX_CALL_CHECKED(vkEndCommandBuffer, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkLayerProperties *pProperties)
 {
     struct vkEnumerateDeviceLayerProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkEnumerateDeviceLayerProperties, &params);
-    assert(!status && "vkEnumerateDeviceLayerProperties");
+    UNIX_CALL_CHECKED(vkEnumerateDeviceLayerProperties, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
 {
     struct vkEnumeratePhysicalDeviceGroups_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pPhysicalDeviceGroupCount = pPhysicalDeviceGroupCount;
     params.pPhysicalDeviceGroupProperties = pPhysicalDeviceGroupProperties;
-    status = UNIX_CALL(vkEnumeratePhysicalDeviceGroups, &params);
-    assert(!status && "vkEnumeratePhysicalDeviceGroups");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDeviceGroups, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDeviceGroupsKHR(VkInstance instance, uint32_t *pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties *pPhysicalDeviceGroupProperties)
 {
     struct vkEnumeratePhysicalDeviceGroupsKHR_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pPhysicalDeviceGroupCount = pPhysicalDeviceGroupCount;
     params.pPhysicalDeviceGroupProperties = pPhysicalDeviceGroupProperties;
-    status = UNIX_CALL(vkEnumeratePhysicalDeviceGroupsKHR, &params);
-    assert(!status && "vkEnumeratePhysicalDeviceGroupsKHR");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDeviceGroupsKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pCounterCount, VkPerformanceCounterARM *pCounters, VkPerformanceCounterDescriptionARM *pCounterDescriptions)
 {
     struct vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.pCounterCount = pCounterCount;
     params.pCounters = pCounters;
     params.pCounterDescriptions = pCounterDescriptions;
-    status = UNIX_CALL(vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM, &params);
-    assert(!status && "vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDeviceQueueFamilyPerformanceCountersByRegionARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pCounterCount, VkPerformanceCounterKHR *pCounters, VkPerformanceCounterDescriptionKHR *pCounterDescriptions)
 {
     struct vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.pCounterCount = pCounterCount;
     params.pCounters = pCounters;
     params.pCounterDescriptions = pCounterDescriptions;
-    status = UNIX_CALL(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, &params);
-    assert(!status && "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM(VkPhysicalDevice physicalDevice, uint32_t *pDescriptionCount, VkShaderInstrumentationMetricDescriptionARM *pDescriptions)
 {
     struct vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pDescriptionCount = pDescriptionCount;
     params.pDescriptions = pDescriptions;
-    status = UNIX_CALL(vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM, &params);
-    assert(!status && "vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDeviceShaderInstrumentationMetricsARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkEnumeratePhysicalDevices(VkInstance instance, uint32_t *pPhysicalDeviceCount, VkPhysicalDevice *pPhysicalDevices)
 {
     struct vkEnumeratePhysicalDevices_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.pPhysicalDeviceCount = pPhysicalDeviceCount;
     params.pPhysicalDevices = pPhysicalDevices;
-    status = UNIX_CALL(vkEnumeratePhysicalDevices, &params);
-    assert(!status && "vkEnumeratePhysicalDevices");
+    UNIX_CALL_CHECKED(vkEnumeratePhysicalDevices, &params);
     return params.result;
 }
 
 VkResult WINAPI vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges)
 {
     struct vkFlushMappedMemoryRanges_params params;
-    NTSTATUS status;
     params.device = device;
     params.memoryRangeCount = memoryRangeCount;
     params.pMemoryRanges = pMemoryRanges;
-    status = UNIX_CALL(vkFlushMappedMemoryRanges, &params);
-    assert(!status && "vkFlushMappedMemoryRanges");
+    UNIX_CALL_CHECKED(vkFlushMappedMemoryRanges, &params);
     return params.result;
 }
 
 VkResult WINAPI vkFreeDescriptorSets(VkDevice device, VkDescriptorPool descriptorPool, uint32_t descriptorSetCount, const VkDescriptorSet *pDescriptorSets)
 {
     struct vkFreeDescriptorSets_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorPool = descriptorPool;
     params.descriptorSetCount = descriptorSetCount;
     params.pDescriptorSets = pDescriptorSets;
-    status = UNIX_CALL(vkFreeDescriptorSets, &params);
-    assert(!status && "vkFreeDescriptorSets");
+    UNIX_CALL_CHECKED(vkFreeDescriptorSets, &params);
     return params.result;
 }
 
 void WINAPI vkFreeMemory(VkDevice device, VkDeviceMemory memory, const VkAllocationCallbacks *pAllocator)
 {
     struct vkFreeMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.memory = memory;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkFreeMemory, &params);
-    assert(!status && "vkFreeMemory");
+    UNIX_CALL_CHECKED(vkFreeMemory, &params);
 }
 
 void WINAPI vkGetAccelerationStructureBuildSizesKHR(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkAccelerationStructureBuildGeometryInfoKHR *pBuildInfo, const uint32_t *pMaxPrimitiveCounts, VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo)
 {
     struct vkGetAccelerationStructureBuildSizesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.buildType = buildType;
     params.pBuildInfo = pBuildInfo;
     params.pMaxPrimitiveCounts = pMaxPrimitiveCounts;
     params.pSizeInfo = pSizeInfo;
-    status = UNIX_CALL(vkGetAccelerationStructureBuildSizesKHR, &params);
-    assert(!status && "vkGetAccelerationStructureBuildSizesKHR");
+    UNIX_CALL_CHECKED(vkGetAccelerationStructureBuildSizesKHR, &params);
 }
 
 VkDeviceAddress WINAPI vkGetAccelerationStructureDeviceAddressKHR(VkDevice device, const VkAccelerationStructureDeviceAddressInfoKHR *pInfo)
 {
     struct vkGetAccelerationStructureDeviceAddressKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetAccelerationStructureDeviceAddressKHR, &params);
-    assert(!status && "vkGetAccelerationStructureDeviceAddressKHR");
+    UNIX_CALL_CHECKED(vkGetAccelerationStructureDeviceAddressKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetAccelerationStructureHandleNV(VkDevice device, VkAccelerationStructureNV accelerationStructure, size_t dataSize, void *pData)
 {
     struct vkGetAccelerationStructureHandleNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.accelerationStructure = accelerationStructure;
     params.dataSize = dataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetAccelerationStructureHandleNV, &params);
-    assert(!status && "vkGetAccelerationStructureHandleNV");
+    UNIX_CALL_CHECKED(vkGetAccelerationStructureHandleNV, &params);
     return params.result;
 }
 
 void WINAPI vkGetAccelerationStructureMemoryRequirementsNV(VkDevice device, const VkAccelerationStructureMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetAccelerationStructureMemoryRequirementsNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetAccelerationStructureMemoryRequirementsNV, &params);
-    assert(!status && "vkGetAccelerationStructureMemoryRequirementsNV");
+    UNIX_CALL_CHECKED(vkGetAccelerationStructureMemoryRequirementsNV, &params);
 }
 
 VkResult WINAPI vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkAccelerationStructureCaptureDescriptorDataInfoEXT *pInfo, void *pData)
 {
     struct vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, &params);
-    assert(!status && "vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT");
+    UNIX_CALL_CHECKED(vkGetAccelerationStructureOpaqueCaptureDescriptorDataEXT, &params);
     return params.result;
 }
 
 VkDeviceAddress WINAPI vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo)
 {
     struct vkGetBufferDeviceAddress_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetBufferDeviceAddress, &params);
-    assert(!status && "vkGetBufferDeviceAddress");
+    UNIX_CALL_CHECKED(vkGetBufferDeviceAddress, &params);
     return params.result;
 }
 
 VkDeviceAddress WINAPI vkGetBufferDeviceAddressEXT(VkDevice device, const VkBufferDeviceAddressInfo *pInfo)
 {
     struct vkGetBufferDeviceAddressEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetBufferDeviceAddressEXT, &params);
-    assert(!status && "vkGetBufferDeviceAddressEXT");
+    UNIX_CALL_CHECKED(vkGetBufferDeviceAddressEXT, &params);
     return params.result;
 }
 
 VkDeviceAddress WINAPI vkGetBufferDeviceAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo)
 {
     struct vkGetBufferDeviceAddressKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetBufferDeviceAddressKHR, &params);
-    assert(!status && "vkGetBufferDeviceAddressKHR");
+    UNIX_CALL_CHECKED(vkGetBufferDeviceAddressKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetBufferMemoryRequirements(VkDevice device, VkBuffer buffer, VkMemoryRequirements *pMemoryRequirements)
 {
     struct vkGetBufferMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.buffer = buffer;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetBufferMemoryRequirements, &params);
-    assert(!status && "vkGetBufferMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetBufferMemoryRequirements, &params);
 }
 
 void WINAPI vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetBufferMemoryRequirements2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetBufferMemoryRequirements2, &params);
-    assert(!status && "vkGetBufferMemoryRequirements2");
+    UNIX_CALL_CHECKED(vkGetBufferMemoryRequirements2, &params);
 }
 
 void WINAPI vkGetBufferMemoryRequirements2KHR(VkDevice device, const VkBufferMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetBufferMemoryRequirements2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetBufferMemoryRequirements2KHR, &params);
-    assert(!status && "vkGetBufferMemoryRequirements2KHR");
+    UNIX_CALL_CHECKED(vkGetBufferMemoryRequirements2KHR, &params);
 }
 
 uint64_t WINAPI vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo *pInfo)
 {
     struct vkGetBufferOpaqueCaptureAddress_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetBufferOpaqueCaptureAddress, &params);
-    assert(!status && "vkGetBufferOpaqueCaptureAddress");
+    UNIX_CALL_CHECKED(vkGetBufferOpaqueCaptureAddress, &params);
     return params.result;
 }
 
 uint64_t WINAPI vkGetBufferOpaqueCaptureAddressKHR(VkDevice device, const VkBufferDeviceAddressInfo *pInfo)
 {
     struct vkGetBufferOpaqueCaptureAddressKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetBufferOpaqueCaptureAddressKHR, &params);
-    assert(!status && "vkGetBufferOpaqueCaptureAddressKHR");
+    UNIX_CALL_CHECKED(vkGetBufferOpaqueCaptureAddressKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetBufferOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkBufferCaptureDescriptorDataInfoEXT *pInfo, void *pData)
 {
     struct vkGetBufferOpaqueCaptureDescriptorDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetBufferOpaqueCaptureDescriptorDataEXT, &params);
-    assert(!status && "vkGetBufferOpaqueCaptureDescriptorDataEXT");
+    UNIX_CALL_CHECKED(vkGetBufferOpaqueCaptureDescriptorDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetCalibratedTimestampsEXT(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation)
 {
     struct vkGetCalibratedTimestampsEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.timestampCount = timestampCount;
     params.pTimestampInfos = pTimestampInfos;
     params.pTimestamps = pTimestamps;
     params.pMaxDeviation = pMaxDeviation;
-    status = UNIX_CALL(vkGetCalibratedTimestampsEXT, &params);
-    assert(!status && "vkGetCalibratedTimestampsEXT");
+    UNIX_CALL_CHECKED(vkGetCalibratedTimestampsEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetCalibratedTimestampsKHR(VkDevice device, uint32_t timestampCount, const VkCalibratedTimestampInfoKHR *pTimestampInfos, uint64_t *pTimestamps, uint64_t *pMaxDeviation)
 {
     struct vkGetCalibratedTimestampsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.timestampCount = timestampCount;
     params.pTimestampInfos = pTimestampInfos;
     params.pTimestamps = pTimestamps;
     params.pMaxDeviation = pMaxDeviation;
-    status = UNIX_CALL(vkGetCalibratedTimestampsKHR, &params);
-    assert(!status && "vkGetCalibratedTimestampsKHR");
+    UNIX_CALL_CHECKED(vkGetCalibratedTimestampsKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetClusterAccelerationStructureBuildSizesNV(VkDevice device, const VkClusterAccelerationStructureInputInfoNV *pInfo, VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo)
 {
     struct vkGetClusterAccelerationStructureBuildSizesNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSizeInfo = pSizeInfo;
-    status = UNIX_CALL(vkGetClusterAccelerationStructureBuildSizesNV, &params);
-    assert(!status && "vkGetClusterAccelerationStructureBuildSizesNV");
+    UNIX_CALL_CHECKED(vkGetClusterAccelerationStructureBuildSizesNV, &params);
 }
 
 VkResult WINAPI vkGetDataGraphPipelineAvailablePropertiesARM(VkDevice device, const VkDataGraphPipelineInfoARM *pPipelineInfo, uint32_t *pPropertiesCount, VkDataGraphPipelinePropertyARM *pProperties)
 {
     struct vkGetDataGraphPipelineAvailablePropertiesARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPipelineInfo = pPipelineInfo;
     params.pPropertiesCount = pPropertiesCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetDataGraphPipelineAvailablePropertiesARM, &params);
-    assert(!status && "vkGetDataGraphPipelineAvailablePropertiesARM");
+    UNIX_CALL_CHECKED(vkGetDataGraphPipelineAvailablePropertiesARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDataGraphPipelinePropertiesARM(VkDevice device, const VkDataGraphPipelineInfoARM *pPipelineInfo, uint32_t propertiesCount, VkDataGraphPipelinePropertyQueryResultARM *pProperties)
 {
     struct vkGetDataGraphPipelinePropertiesARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPipelineInfo = pPipelineInfo;
     params.propertiesCount = propertiesCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetDataGraphPipelinePropertiesARM, &params);
-    assert(!status && "vkGetDataGraphPipelinePropertiesARM");
+    UNIX_CALL_CHECKED(vkGetDataGraphPipelinePropertiesARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDataGraphPipelineSessionBindPointRequirementsARM(VkDevice device, const VkDataGraphPipelineSessionBindPointRequirementsInfoARM *pInfo, uint32_t *pBindPointRequirementCount, VkDataGraphPipelineSessionBindPointRequirementARM *pBindPointRequirements)
 {
     struct vkGetDataGraphPipelineSessionBindPointRequirementsARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pBindPointRequirementCount = pBindPointRequirementCount;
     params.pBindPointRequirements = pBindPointRequirements;
-    status = UNIX_CALL(vkGetDataGraphPipelineSessionBindPointRequirementsARM, &params);
-    assert(!status && "vkGetDataGraphPipelineSessionBindPointRequirementsARM");
+    UNIX_CALL_CHECKED(vkGetDataGraphPipelineSessionBindPointRequirementsARM, &params);
     return params.result;
 }
 
 void WINAPI vkGetDataGraphPipelineSessionMemoryRequirementsARM(VkDevice device, const VkDataGraphPipelineSessionMemoryRequirementsInfoARM *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDataGraphPipelineSessionMemoryRequirementsARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDataGraphPipelineSessionMemoryRequirementsARM, &params);
-    assert(!status && "vkGetDataGraphPipelineSessionMemoryRequirementsARM");
+    UNIX_CALL_CHECKED(vkGetDataGraphPipelineSessionMemoryRequirementsARM, &params);
 }
 
 uint32_t WINAPI vkGetDeferredOperationMaxConcurrencyKHR(VkDevice device, VkDeferredOperationKHR operation)
 {
     struct vkGetDeferredOperationMaxConcurrencyKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.operation = operation;
-    status = UNIX_CALL(vkGetDeferredOperationMaxConcurrencyKHR, &params);
-    assert(!status && "vkGetDeferredOperationMaxConcurrencyKHR");
+    UNIX_CALL_CHECKED(vkGetDeferredOperationMaxConcurrencyKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDeferredOperationResultKHR(VkDevice device, VkDeferredOperationKHR operation)
 {
     struct vkGetDeferredOperationResultKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.operation = operation;
-    status = UNIX_CALL(vkGetDeferredOperationResultKHR, &params);
-    assert(!status && "vkGetDeferredOperationResultKHR");
+    UNIX_CALL_CHECKED(vkGetDeferredOperationResultKHR, &params);
     return params.result;
 }
 
@@ -5075,1012 +4711,837 @@ void WINAPI vkGetDescriptorEXT(VkDevice device, const VkDescriptorGetInfoEXT *pD
 void WINAPI vkGetDescriptorSetHostMappingVALVE(VkDevice device, VkDescriptorSet descriptorSet, void **ppData)
 {
     struct vkGetDescriptorSetHostMappingVALVE_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorSet = descriptorSet;
     params.ppData = ppData;
-    status = UNIX_CALL(vkGetDescriptorSetHostMappingVALVE, &params);
-    assert(!status && "vkGetDescriptorSetHostMappingVALVE");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetHostMappingVALVE, &params);
 }
 
 void WINAPI vkGetDescriptorSetLayoutBindingOffsetEXT(VkDevice device, VkDescriptorSetLayout layout, uint32_t binding, VkDeviceSize *pOffset)
 {
     struct vkGetDescriptorSetLayoutBindingOffsetEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.layout = layout;
     params.binding = binding;
     params.pOffset = pOffset;
-    status = UNIX_CALL(vkGetDescriptorSetLayoutBindingOffsetEXT, &params);
-    assert(!status && "vkGetDescriptorSetLayoutBindingOffsetEXT");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetLayoutBindingOffsetEXT, &params);
 }
 
 void WINAPI vkGetDescriptorSetLayoutHostMappingInfoVALVE(VkDevice device, const VkDescriptorSetBindingReferenceVALVE *pBindingReference, VkDescriptorSetLayoutHostMappingInfoVALVE *pHostMapping)
 {
     struct vkGetDescriptorSetLayoutHostMappingInfoVALVE_params params;
-    NTSTATUS status;
     params.device = device;
     params.pBindingReference = pBindingReference;
     params.pHostMapping = pHostMapping;
-    status = UNIX_CALL(vkGetDescriptorSetLayoutHostMappingInfoVALVE, &params);
-    assert(!status && "vkGetDescriptorSetLayoutHostMappingInfoVALVE");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetLayoutHostMappingInfoVALVE, &params);
 }
 
 void WINAPI vkGetDescriptorSetLayoutSizeEXT(VkDevice device, VkDescriptorSetLayout layout, VkDeviceSize *pLayoutSizeInBytes)
 {
     struct vkGetDescriptorSetLayoutSizeEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.layout = layout;
     params.pLayoutSizeInBytes = pLayoutSizeInBytes;
-    status = UNIX_CALL(vkGetDescriptorSetLayoutSizeEXT, &params);
-    assert(!status && "vkGetDescriptorSetLayoutSizeEXT");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetLayoutSizeEXT, &params);
 }
 
 void WINAPI vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport)
 {
     struct vkGetDescriptorSetLayoutSupport_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pSupport = pSupport;
-    status = UNIX_CALL(vkGetDescriptorSetLayoutSupport, &params);
-    assert(!status && "vkGetDescriptorSetLayoutSupport");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetLayoutSupport, &params);
 }
 
 void WINAPI vkGetDescriptorSetLayoutSupportKHR(VkDevice device, const VkDescriptorSetLayoutCreateInfo *pCreateInfo, VkDescriptorSetLayoutSupport *pSupport)
 {
     struct vkGetDescriptorSetLayoutSupportKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pSupport = pSupport;
-    status = UNIX_CALL(vkGetDescriptorSetLayoutSupportKHR, &params);
-    assert(!status && "vkGetDescriptorSetLayoutSupportKHR");
+    UNIX_CALL_CHECKED(vkGetDescriptorSetLayoutSupportKHR, &params);
 }
 
 void WINAPI vkGetDeviceAccelerationStructureCompatibilityKHR(VkDevice device, const VkAccelerationStructureVersionInfoKHR *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility)
 {
     struct vkGetDeviceAccelerationStructureCompatibilityKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pVersionInfo = pVersionInfo;
     params.pCompatibility = pCompatibility;
-    status = UNIX_CALL(vkGetDeviceAccelerationStructureCompatibilityKHR, &params);
-    assert(!status && "vkGetDeviceAccelerationStructureCompatibilityKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceAccelerationStructureCompatibilityKHR, &params);
 }
 
 void WINAPI vkGetDeviceBufferMemoryRequirements(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDeviceBufferMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceBufferMemoryRequirements, &params);
-    assert(!status && "vkGetDeviceBufferMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetDeviceBufferMemoryRequirements, &params);
 }
 
 void WINAPI vkGetDeviceBufferMemoryRequirementsKHR(VkDevice device, const VkDeviceBufferMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDeviceBufferMemoryRequirementsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceBufferMemoryRequirementsKHR, &params);
-    assert(!status && "vkGetDeviceBufferMemoryRequirementsKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceBufferMemoryRequirementsKHR, &params);
 }
 
 uint64_t WINAPI vkGetDeviceCombinedImageSamplerIndexNVX(VkDevice device, uint64_t imageViewIndex, uint64_t samplerIndex)
 {
     struct vkGetDeviceCombinedImageSamplerIndexNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.imageViewIndex = imageViewIndex;
     params.samplerIndex = samplerIndex;
-    status = UNIX_CALL(vkGetDeviceCombinedImageSamplerIndexNVX, &params);
-    assert(!status && "vkGetDeviceCombinedImageSamplerIndexNVX");
+    UNIX_CALL_CHECKED(vkGetDeviceCombinedImageSamplerIndexNVX, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDeviceFaultDebugInfoKHR(VkDevice device, VkDeviceFaultDebugInfoKHR *pDebugInfo)
 {
     struct vkGetDeviceFaultDebugInfoKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pDebugInfo = pDebugInfo;
-    status = UNIX_CALL(vkGetDeviceFaultDebugInfoKHR, &params);
-    assert(!status && "vkGetDeviceFaultDebugInfoKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceFaultDebugInfoKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDeviceFaultInfoEXT(VkDevice device, VkDeviceFaultCountsEXT *pFaultCounts, VkDeviceFaultInfoEXT *pFaultInfo)
 {
     struct vkGetDeviceFaultInfoEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pFaultCounts = pFaultCounts;
     params.pFaultInfo = pFaultInfo;
-    status = UNIX_CALL(vkGetDeviceFaultInfoEXT, &params);
-    assert(!status && "vkGetDeviceFaultInfoEXT");
+    UNIX_CALL_CHECKED(vkGetDeviceFaultInfoEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDeviceFaultReportsKHR(VkDevice device, uint64_t timeout, uint32_t *pFaultCounts, VkDeviceFaultInfoKHR *pFaultInfo)
 {
     struct vkGetDeviceFaultReportsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.timeout = timeout;
     params.pFaultCounts = pFaultCounts;
     params.pFaultInfo = pFaultInfo;
-    status = UNIX_CALL(vkGetDeviceFaultReportsKHR, &params);
-    assert(!status && "vkGetDeviceFaultReportsKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceFaultReportsKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
 {
     struct vkGetDeviceGroupPeerMemoryFeatures_params params;
-    NTSTATUS status;
     params.device = device;
     params.heapIndex = heapIndex;
     params.localDeviceIndex = localDeviceIndex;
     params.remoteDeviceIndex = remoteDeviceIndex;
     params.pPeerMemoryFeatures = pPeerMemoryFeatures;
-    status = UNIX_CALL(vkGetDeviceGroupPeerMemoryFeatures, &params);
-    assert(!status && "vkGetDeviceGroupPeerMemoryFeatures");
+    UNIX_CALL_CHECKED(vkGetDeviceGroupPeerMemoryFeatures, &params);
 }
 
 void WINAPI vkGetDeviceGroupPeerMemoryFeaturesKHR(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags *pPeerMemoryFeatures)
 {
     struct vkGetDeviceGroupPeerMemoryFeaturesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.heapIndex = heapIndex;
     params.localDeviceIndex = localDeviceIndex;
     params.remoteDeviceIndex = remoteDeviceIndex;
     params.pPeerMemoryFeatures = pPeerMemoryFeatures;
-    status = UNIX_CALL(vkGetDeviceGroupPeerMemoryFeaturesKHR, &params);
-    assert(!status && "vkGetDeviceGroupPeerMemoryFeaturesKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceGroupPeerMemoryFeaturesKHR, &params);
 }
 
 VkResult WINAPI vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR *pDeviceGroupPresentCapabilities)
 {
     struct vkGetDeviceGroupPresentCapabilitiesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pDeviceGroupPresentCapabilities = pDeviceGroupPresentCapabilities;
-    status = UNIX_CALL(vkGetDeviceGroupPresentCapabilitiesKHR, &params);
-    assert(!status && "vkGetDeviceGroupPresentCapabilitiesKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceGroupPresentCapabilitiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR *pModes)
 {
     struct vkGetDeviceGroupSurfacePresentModesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.surface = surface;
     params.pModes = pModes;
-    status = UNIX_CALL(vkGetDeviceGroupSurfacePresentModesKHR, &params);
-    assert(!status && "vkGetDeviceGroupSurfacePresentModesKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceGroupSurfacePresentModesKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetDeviceImageMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDeviceImageMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceImageMemoryRequirements, &params);
-    assert(!status && "vkGetDeviceImageMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetDeviceImageMemoryRequirements, &params);
 }
 
 void WINAPI vkGetDeviceImageMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDeviceImageMemoryRequirementsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceImageMemoryRequirementsKHR, &params);
-    assert(!status && "vkGetDeviceImageMemoryRequirementsKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceImageMemoryRequirementsKHR, &params);
 }
 
 void WINAPI vkGetDeviceImageSparseMemoryRequirements(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
 {
     struct vkGetDeviceImageSparseMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount;
     params.pSparseMemoryRequirements = pSparseMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceImageSparseMemoryRequirements, &params);
-    assert(!status && "vkGetDeviceImageSparseMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetDeviceImageSparseMemoryRequirements, &params);
 }
 
 void WINAPI vkGetDeviceImageSparseMemoryRequirementsKHR(VkDevice device, const VkDeviceImageMemoryRequirements *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
 {
     struct vkGetDeviceImageSparseMemoryRequirementsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount;
     params.pSparseMemoryRequirements = pSparseMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceImageSparseMemoryRequirementsKHR, &params);
-    assert(!status && "vkGetDeviceImageSparseMemoryRequirementsKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceImageSparseMemoryRequirementsKHR, &params);
 }
 
 void WINAPI vkGetDeviceImageSubresourceLayout(VkDevice device, const VkDeviceImageSubresourceInfo *pInfo, VkSubresourceLayout2 *pLayout)
 {
     struct vkGetDeviceImageSubresourceLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetDeviceImageSubresourceLayout, &params);
-    assert(!status && "vkGetDeviceImageSubresourceLayout");
+    UNIX_CALL_CHECKED(vkGetDeviceImageSubresourceLayout, &params);
 }
 
 void WINAPI vkGetDeviceImageSubresourceLayoutKHR(VkDevice device, const VkDeviceImageSubresourceInfo *pInfo, VkSubresourceLayout2 *pLayout)
 {
     struct vkGetDeviceImageSubresourceLayoutKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetDeviceImageSubresourceLayoutKHR, &params);
-    assert(!status && "vkGetDeviceImageSubresourceLayoutKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceImageSubresourceLayoutKHR, &params);
 }
 
 void WINAPI vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize *pCommittedMemoryInBytes)
 {
     struct vkGetDeviceMemoryCommitment_params params;
-    NTSTATUS status;
     params.device = device;
     params.memory = memory;
     params.pCommittedMemoryInBytes = pCommittedMemoryInBytes;
-    status = UNIX_CALL(vkGetDeviceMemoryCommitment, &params);
-    assert(!status && "vkGetDeviceMemoryCommitment");
+    UNIX_CALL_CHECKED(vkGetDeviceMemoryCommitment, &params);
 }
 
 uint64_t WINAPI vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)
 {
     struct vkGetDeviceMemoryOpaqueCaptureAddress_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetDeviceMemoryOpaqueCaptureAddress, &params);
-    assert(!status && "vkGetDeviceMemoryOpaqueCaptureAddress");
+    UNIX_CALL_CHECKED(vkGetDeviceMemoryOpaqueCaptureAddress, &params);
     return params.result;
 }
 
 uint64_t WINAPI vkGetDeviceMemoryOpaqueCaptureAddressKHR(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo *pInfo)
 {
     struct vkGetDeviceMemoryOpaqueCaptureAddressKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetDeviceMemoryOpaqueCaptureAddressKHR, &params);
-    assert(!status && "vkGetDeviceMemoryOpaqueCaptureAddressKHR");
+    UNIX_CALL_CHECKED(vkGetDeviceMemoryOpaqueCaptureAddressKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetDeviceMicromapCompatibilityEXT(VkDevice device, const VkMicromapVersionInfoEXT *pVersionInfo, VkAccelerationStructureCompatibilityKHR *pCompatibility)
 {
     struct vkGetDeviceMicromapCompatibilityEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pVersionInfo = pVersionInfo;
     params.pCompatibility = pCompatibility;
-    status = UNIX_CALL(vkGetDeviceMicromapCompatibilityEXT, &params);
-    assert(!status && "vkGetDeviceMicromapCompatibilityEXT");
+    UNIX_CALL_CHECKED(vkGetDeviceMicromapCompatibilityEXT, &params);
 }
 
 void WINAPI vkGetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue *pQueue)
 {
     struct vkGetDeviceQueue_params params;
-    NTSTATUS status;
     params.device = device;
     params.queueFamilyIndex = queueFamilyIndex;
     params.queueIndex = queueIndex;
     params.pQueue = pQueue;
-    status = UNIX_CALL(vkGetDeviceQueue, &params);
-    assert(!status && "vkGetDeviceQueue");
+    UNIX_CALL_CHECKED(vkGetDeviceQueue, &params);
 }
 
 void WINAPI vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2 *pQueueInfo, VkQueue *pQueue)
 {
     struct vkGetDeviceQueue2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pQueueInfo = pQueueInfo;
     params.pQueue = pQueue;
-    status = UNIX_CALL(vkGetDeviceQueue2, &params);
-    assert(!status && "vkGetDeviceQueue2");
+    UNIX_CALL_CHECKED(vkGetDeviceQueue2, &params);
 }
 
 VkResult WINAPI vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI(VkDevice device, VkRenderPass renderpass, VkExtent2D *pMaxWorkgroupSize)
 {
     struct vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI_params params;
-    NTSTATUS status;
     params.device = device;
     params.renderpass = renderpass;
     params.pMaxWorkgroupSize = pMaxWorkgroupSize;
-    status = UNIX_CALL(vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, &params);
-    assert(!status && "vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI");
+    UNIX_CALL_CHECKED(vkGetDeviceSubpassShadingMaxWorkgroupSizeHUAWEI, &params);
     return params.result;
 }
 
 void WINAPI vkGetDeviceTensorMemoryRequirementsARM(VkDevice device, const VkDeviceTensorMemoryRequirementsARM *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetDeviceTensorMemoryRequirementsARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetDeviceTensorMemoryRequirementsARM, &params);
-    assert(!status && "vkGetDeviceTensorMemoryRequirementsARM");
+    UNIX_CALL_CHECKED(vkGetDeviceTensorMemoryRequirementsARM, &params);
 }
 
 VkResult WINAPI vkGetDynamicRenderingTilePropertiesQCOM(VkDevice device, const VkRenderingInfo *pRenderingInfo, VkTilePropertiesQCOM *pProperties)
 {
     struct vkGetDynamicRenderingTilePropertiesQCOM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pRenderingInfo = pRenderingInfo;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetDynamicRenderingTilePropertiesQCOM, &params);
-    assert(!status && "vkGetDynamicRenderingTilePropertiesQCOM");
+    UNIX_CALL_CHECKED(vkGetDynamicRenderingTilePropertiesQCOM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetEncodedVideoSessionParametersKHR(VkDevice device, const VkVideoEncodeSessionParametersGetInfoKHR *pVideoSessionParametersInfo, VkVideoEncodeSessionParametersFeedbackInfoKHR *pFeedbackInfo, size_t *pDataSize, void *pData)
 {
     struct vkGetEncodedVideoSessionParametersKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pVideoSessionParametersInfo = pVideoSessionParametersInfo;
     params.pFeedbackInfo = pFeedbackInfo;
     params.pDataSize = pDataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetEncodedVideoSessionParametersKHR, &params);
-    assert(!status && "vkGetEncodedVideoSessionParametersKHR");
+    UNIX_CALL_CHECKED(vkGetEncodedVideoSessionParametersKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetEventStatus(VkDevice device, VkEvent event)
 {
     struct vkGetEventStatus_params params;
-    NTSTATUS status;
     params.device = device;
     params.event = event;
-    status = UNIX_CALL(vkGetEventStatus, &params);
-    assert(!status && "vkGetEventStatus");
+    UNIX_CALL_CHECKED(vkGetEventStatus, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetFenceStatus(VkDevice device, VkFence fence)
 {
     struct vkGetFenceStatus_params params;
-    NTSTATUS status;
     params.device = device;
     params.fence = fence;
-    status = UNIX_CALL(vkGetFenceStatus, &params);
-    assert(!status && "vkGetFenceStatus");
+    UNIX_CALL_CHECKED(vkGetFenceStatus, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetFenceWin32HandleKHR(VkDevice device, const VkFenceGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle)
 {
     struct vkGetFenceWin32HandleKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pGetWin32HandleInfo = pGetWin32HandleInfo;
     params.pHandle = pHandle;
-    status = UNIX_CALL(vkGetFenceWin32HandleKHR, &params);
-    assert(!status && "vkGetFenceWin32HandleKHR");
+    UNIX_CALL_CHECKED(vkGetFenceWin32HandleKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetFramebufferTilePropertiesQCOM(VkDevice device, VkFramebuffer framebuffer, uint32_t *pPropertiesCount, VkTilePropertiesQCOM *pProperties)
 {
     struct vkGetFramebufferTilePropertiesQCOM_params params;
-    NTSTATUS status;
     params.device = device;
     params.framebuffer = framebuffer;
     params.pPropertiesCount = pPropertiesCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetFramebufferTilePropertiesQCOM, &params);
-    assert(!status && "vkGetFramebufferTilePropertiesQCOM");
+    UNIX_CALL_CHECKED(vkGetFramebufferTilePropertiesQCOM, &params);
     return params.result;
 }
 
 void WINAPI vkGetGeneratedCommandsMemoryRequirementsEXT(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoEXT *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetGeneratedCommandsMemoryRequirementsEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetGeneratedCommandsMemoryRequirementsEXT, &params);
-    assert(!status && "vkGetGeneratedCommandsMemoryRequirementsEXT");
+    UNIX_CALL_CHECKED(vkGetGeneratedCommandsMemoryRequirementsEXT, &params);
 }
 
 void WINAPI vkGetGeneratedCommandsMemoryRequirementsNV(VkDevice device, const VkGeneratedCommandsMemoryRequirementsInfoNV *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetGeneratedCommandsMemoryRequirementsNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetGeneratedCommandsMemoryRequirementsNV, &params);
-    assert(!status && "vkGetGeneratedCommandsMemoryRequirementsNV");
+    UNIX_CALL_CHECKED(vkGetGeneratedCommandsMemoryRequirementsNV, &params);
 }
 
 VkResult WINAPI vkGetGpaDeviceClockInfoAMD(VkDevice device, VkGpaDeviceGetClockInfoAMD *pInfo)
 {
     struct vkGetGpaDeviceClockInfoAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetGpaDeviceClockInfoAMD, &params);
-    assert(!status && "vkGetGpaDeviceClockInfoAMD");
+    UNIX_CALL_CHECKED(vkGetGpaDeviceClockInfoAMD, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetGpaSessionResultsAMD(VkDevice device, VkGpaSessionAMD gpaSession, uint32_t sampleID, size_t *pSizeInBytes, void *pData)
 {
     struct vkGetGpaSessionResultsAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.gpaSession = gpaSession;
     params.sampleID = sampleID;
     params.pSizeInBytes = pSizeInBytes;
     params.pData = pData;
-    status = UNIX_CALL(vkGetGpaSessionResultsAMD, &params);
-    assert(!status && "vkGetGpaSessionResultsAMD");
+    UNIX_CALL_CHECKED(vkGetGpaSessionResultsAMD, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetGpaSessionStatusAMD(VkDevice device, VkGpaSessionAMD gpaSession)
 {
     struct vkGetGpaSessionStatusAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.gpaSession = gpaSession;
-    status = UNIX_CALL(vkGetGpaSessionStatusAMD, &params);
-    assert(!status && "vkGetGpaSessionStatusAMD");
+    UNIX_CALL_CHECKED(vkGetGpaSessionStatusAMD, &params);
     return params.result;
 }
 
 void WINAPI vkGetImageMemoryRequirements(VkDevice device, VkImage image, VkMemoryRequirements *pMemoryRequirements)
 {
     struct vkGetImageMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetImageMemoryRequirements, &params);
-    assert(!status && "vkGetImageMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetImageMemoryRequirements, &params);
 }
 
 void WINAPI vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetImageMemoryRequirements2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetImageMemoryRequirements2, &params);
-    assert(!status && "vkGetImageMemoryRequirements2");
+    UNIX_CALL_CHECKED(vkGetImageMemoryRequirements2, &params);
 }
 
 void WINAPI vkGetImageMemoryRequirements2KHR(VkDevice device, const VkImageMemoryRequirementsInfo2 *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetImageMemoryRequirements2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetImageMemoryRequirements2KHR, &params);
-    assert(!status && "vkGetImageMemoryRequirements2KHR");
+    UNIX_CALL_CHECKED(vkGetImageMemoryRequirements2KHR, &params);
 }
 
 VkResult WINAPI vkGetImageOpaqueCaptureDataEXT(VkDevice device, uint32_t imageCount, const VkImage *pImages, VkHostAddressRangeEXT *pDatas)
 {
     struct vkGetImageOpaqueCaptureDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.imageCount = imageCount;
     params.pImages = pImages;
     params.pDatas = pDatas;
-    status = UNIX_CALL(vkGetImageOpaqueCaptureDataEXT, &params);
-    assert(!status && "vkGetImageOpaqueCaptureDataEXT");
+    UNIX_CALL_CHECKED(vkGetImageOpaqueCaptureDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetImageOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageCaptureDescriptorDataInfoEXT *pInfo, void *pData)
 {
     struct vkGetImageOpaqueCaptureDescriptorDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetImageOpaqueCaptureDescriptorDataEXT, &params);
-    assert(!status && "vkGetImageOpaqueCaptureDescriptorDataEXT");
+    UNIX_CALL_CHECKED(vkGetImageOpaqueCaptureDescriptorDataEXT, &params);
     return params.result;
 }
 
 void WINAPI vkGetImageSparseMemoryRequirements(VkDevice device, VkImage image, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements *pSparseMemoryRequirements)
 {
     struct vkGetImageSparseMemoryRequirements_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount;
     params.pSparseMemoryRequirements = pSparseMemoryRequirements;
-    status = UNIX_CALL(vkGetImageSparseMemoryRequirements, &params);
-    assert(!status && "vkGetImageSparseMemoryRequirements");
+    UNIX_CALL_CHECKED(vkGetImageSparseMemoryRequirements, &params);
 }
 
 void WINAPI vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
 {
     struct vkGetImageSparseMemoryRequirements2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount;
     params.pSparseMemoryRequirements = pSparseMemoryRequirements;
-    status = UNIX_CALL(vkGetImageSparseMemoryRequirements2, &params);
-    assert(!status && "vkGetImageSparseMemoryRequirements2");
+    UNIX_CALL_CHECKED(vkGetImageSparseMemoryRequirements2, &params);
 }
 
 void WINAPI vkGetImageSparseMemoryRequirements2KHR(VkDevice device, const VkImageSparseMemoryRequirementsInfo2 *pInfo, uint32_t *pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2 *pSparseMemoryRequirements)
 {
     struct vkGetImageSparseMemoryRequirements2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSparseMemoryRequirementCount = pSparseMemoryRequirementCount;
     params.pSparseMemoryRequirements = pSparseMemoryRequirements;
-    status = UNIX_CALL(vkGetImageSparseMemoryRequirements2KHR, &params);
-    assert(!status && "vkGetImageSparseMemoryRequirements2KHR");
+    UNIX_CALL_CHECKED(vkGetImageSparseMemoryRequirements2KHR, &params);
 }
 
 void WINAPI vkGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout)
 {
     struct vkGetImageSubresourceLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pSubresource = pSubresource;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetImageSubresourceLayout, &params);
-    assert(!status && "vkGetImageSubresourceLayout");
+    UNIX_CALL_CHECKED(vkGetImageSubresourceLayout, &params);
 }
 
 void WINAPI vkGetImageSubresourceLayout2(VkDevice device, VkImage image, const VkImageSubresource2 *pSubresource, VkSubresourceLayout2 *pLayout)
 {
     struct vkGetImageSubresourceLayout2_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pSubresource = pSubresource;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetImageSubresourceLayout2, &params);
-    assert(!status && "vkGetImageSubresourceLayout2");
+    UNIX_CALL_CHECKED(vkGetImageSubresourceLayout2, &params);
 }
 
 void WINAPI vkGetImageSubresourceLayout2EXT(VkDevice device, VkImage image, const VkImageSubresource2 *pSubresource, VkSubresourceLayout2 *pLayout)
 {
     struct vkGetImageSubresourceLayout2EXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pSubresource = pSubresource;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetImageSubresourceLayout2EXT, &params);
-    assert(!status && "vkGetImageSubresourceLayout2EXT");
+    UNIX_CALL_CHECKED(vkGetImageSubresourceLayout2EXT, &params);
 }
 
 void WINAPI vkGetImageSubresourceLayout2KHR(VkDevice device, VkImage image, const VkImageSubresource2 *pSubresource, VkSubresourceLayout2 *pLayout)
 {
     struct vkGetImageSubresourceLayout2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.image = image;
     params.pSubresource = pSubresource;
     params.pLayout = pLayout;
-    status = UNIX_CALL(vkGetImageSubresourceLayout2KHR, &params);
-    assert(!status && "vkGetImageSubresourceLayout2KHR");
+    UNIX_CALL_CHECKED(vkGetImageSubresourceLayout2KHR, &params);
 }
 
 VkResult WINAPI vkGetImageViewAddressNVX(VkDevice device, VkImageView imageView, VkImageViewAddressPropertiesNVX *pProperties)
 {
     struct vkGetImageViewAddressNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.imageView = imageView;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetImageViewAddressNVX, &params);
-    assert(!status && "vkGetImageViewAddressNVX");
+    UNIX_CALL_CHECKED(vkGetImageViewAddressNVX, &params);
     return params.result;
 }
 
 uint64_t WINAPI vkGetImageViewHandle64NVX(VkDevice device, const VkImageViewHandleInfoNVX *pInfo)
 {
     struct vkGetImageViewHandle64NVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetImageViewHandle64NVX, &params);
-    assert(!status && "vkGetImageViewHandle64NVX");
+    UNIX_CALL_CHECKED(vkGetImageViewHandle64NVX, &params);
     return params.result;
 }
 
 uint32_t WINAPI vkGetImageViewHandleNVX(VkDevice device, const VkImageViewHandleInfoNVX *pInfo)
 {
     struct vkGetImageViewHandleNVX_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetImageViewHandleNVX, &params);
-    assert(!status && "vkGetImageViewHandleNVX");
+    UNIX_CALL_CHECKED(vkGetImageViewHandleNVX, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetImageViewOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkImageViewCaptureDescriptorDataInfoEXT *pInfo, void *pData)
 {
     struct vkGetImageViewOpaqueCaptureDescriptorDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetImageViewOpaqueCaptureDescriptorDataEXT, &params);
-    assert(!status && "vkGetImageViewOpaqueCaptureDescriptorDataEXT");
+    UNIX_CALL_CHECKED(vkGetImageViewOpaqueCaptureDescriptorDataEXT, &params);
     return params.result;
 }
 
 void WINAPI vkGetLatencyTimingsNV(VkDevice device, VkSwapchainKHR swapchain, VkGetLatencyMarkerInfoNV *pLatencyMarkerInfo)
 {
     struct vkGetLatencyTimingsNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pLatencyMarkerInfo = pLatencyMarkerInfo;
-    status = UNIX_CALL(vkGetLatencyTimingsNV, &params);
-    assert(!status && "vkGetLatencyTimingsNV");
+    UNIX_CALL_CHECKED(vkGetLatencyTimingsNV, &params);
 }
 
 VkResult WINAPI vkGetMemoryHostPointerPropertiesEXT(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, const void *pHostPointer, VkMemoryHostPointerPropertiesEXT *pMemoryHostPointerProperties)
 {
     struct vkGetMemoryHostPointerPropertiesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.handleType = handleType;
     params.pHostPointer = pHostPointer;
     params.pMemoryHostPointerProperties = pMemoryHostPointerProperties;
-    status = UNIX_CALL(vkGetMemoryHostPointerPropertiesEXT, &params);
-    assert(!status && "vkGetMemoryHostPointerPropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetMemoryHostPointerPropertiesEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetMemoryWin32HandleKHR(VkDevice device, const VkMemoryGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle)
 {
     struct vkGetMemoryWin32HandleKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pGetWin32HandleInfo = pGetWin32HandleInfo;
     params.pHandle = pHandle;
-    status = UNIX_CALL(vkGetMemoryWin32HandleKHR, &params);
-    assert(!status && "vkGetMemoryWin32HandleKHR");
+    UNIX_CALL_CHECKED(vkGetMemoryWin32HandleKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetMemoryWin32HandlePropertiesKHR(VkDevice device, VkExternalMemoryHandleTypeFlagBits handleType, HANDLE handle, VkMemoryWin32HandlePropertiesKHR *pMemoryWin32HandleProperties)
 {
     struct vkGetMemoryWin32HandlePropertiesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.handleType = handleType;
     params.handle = handle;
     params.pMemoryWin32HandleProperties = pMemoryWin32HandleProperties;
-    status = UNIX_CALL(vkGetMemoryWin32HandlePropertiesKHR, &params);
-    assert(!status && "vkGetMemoryWin32HandlePropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetMemoryWin32HandlePropertiesKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetMicromapBuildSizesEXT(VkDevice device, VkAccelerationStructureBuildTypeKHR buildType, const VkMicromapBuildInfoEXT *pBuildInfo, VkMicromapBuildSizesInfoEXT *pSizeInfo)
 {
     struct vkGetMicromapBuildSizesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.buildType = buildType;
     params.pBuildInfo = pBuildInfo;
     params.pSizeInfo = pSizeInfo;
-    status = UNIX_CALL(vkGetMicromapBuildSizesEXT, &params);
-    assert(!status && "vkGetMicromapBuildSizesEXT");
+    UNIX_CALL_CHECKED(vkGetMicromapBuildSizesEXT, &params);
 }
 
 void WINAPI vkGetPartitionedAccelerationStructuresBuildSizesNV(VkDevice device, const VkPartitionedAccelerationStructureInstancesInputNV *pInfo, VkAccelerationStructureBuildSizesInfoKHR *pSizeInfo)
 {
     struct vkGetPartitionedAccelerationStructuresBuildSizesNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pSizeInfo = pSizeInfo;
-    status = UNIX_CALL(vkGetPartitionedAccelerationStructuresBuildSizesNV, &params);
-    assert(!status && "vkGetPartitionedAccelerationStructuresBuildSizesNV");
+    UNIX_CALL_CHECKED(vkGetPartitionedAccelerationStructuresBuildSizesNV, &params);
 }
 
 VkResult WINAPI vkGetPastPresentationTimingEXT(VkDevice device, const VkPastPresentationTimingInfoEXT *pPastPresentationTimingInfo, VkPastPresentationTimingPropertiesEXT *pPastPresentationTimingProperties)
 {
     struct vkGetPastPresentationTimingEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPastPresentationTimingInfo = pPastPresentationTimingInfo;
     params.pPastPresentationTimingProperties = pPastPresentationTimingProperties;
-    status = UNIX_CALL(vkGetPastPresentationTimingEXT, &params);
-    assert(!status && "vkGetPastPresentationTimingEXT");
+    UNIX_CALL_CHECKED(vkGetPastPresentationTimingEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPerformanceParameterINTEL(VkDevice device, VkPerformanceParameterTypeINTEL parameter, VkPerformanceValueINTEL *pValue)
 {
     struct vkGetPerformanceParameterINTEL_params params;
-    NTSTATUS status;
     params.device = device;
     params.parameter = parameter;
     params.pValue = pValue;
-    status = UNIX_CALL(vkGetPerformanceParameterINTEL, &params);
-    assert(!status && "vkGetPerformanceParameterINTEL");
+    UNIX_CALL_CHECKED(vkGetPerformanceParameterINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainKHR *pTimeDomains)
 {
     struct vkGetPhysicalDeviceCalibrateableTimeDomainsEXT_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pTimeDomainCount = pTimeDomainCount;
     params.pTimeDomains = pTimeDomains;
-    status = UNIX_CALL(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, &params);
-    assert(!status && "vkGetPhysicalDeviceCalibrateableTimeDomainsEXT");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCalibrateableTimeDomainsEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCalibrateableTimeDomainsKHR(VkPhysicalDevice physicalDevice, uint32_t *pTimeDomainCount, VkTimeDomainKHR *pTimeDomains)
 {
     struct vkGetPhysicalDeviceCalibrateableTimeDomainsKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pTimeDomainCount = pTimeDomainCount;
     params.pTimeDomains = pTimeDomains;
-    status = UNIX_CALL(vkGetPhysicalDeviceCalibrateableTimeDomainsKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceCalibrateableTimeDomainsKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCalibrateableTimeDomainsKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeMatrixFlexibleDimensionsPropertiesNV *pProperties)
 {
     struct vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV, &params);
-    assert(!status && "vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCooperativeMatrixFlexibleDimensionsPropertiesNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeMatrixPropertiesKHR *pProperties)
 {
     struct vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCooperativeMatrixPropertiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCooperativeMatrixPropertiesNV(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeMatrixPropertiesNV *pProperties)
 {
     struct vkGetPhysicalDeviceCooperativeMatrixPropertiesNV_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, &params);
-    assert(!status && "vkGetPhysicalDeviceCooperativeMatrixPropertiesNV");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCooperativeMatrixPropertiesNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceCooperativeVectorPropertiesNV(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount, VkCooperativeVectorPropertiesNV *pProperties)
 {
     struct vkGetPhysicalDeviceCooperativeVectorPropertiesNV_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceCooperativeVectorPropertiesNV, &params);
-    assert(!status && "vkGetPhysicalDeviceCooperativeVectorPropertiesNV");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceCooperativeVectorPropertiesNV, &params);
     return params.result;
 }
 
 VkDeviceSize WINAPI vkGetPhysicalDeviceDescriptorSizeEXT(VkPhysicalDevice physicalDevice, VkDescriptorType descriptorType)
 {
     struct vkGetPhysicalDeviceDescriptorSizeEXT_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.descriptorType = descriptorType;
-    status = UNIX_CALL(vkGetPhysicalDeviceDescriptorSizeEXT, &params);
-    assert(!status && "vkGetPhysicalDeviceDescriptorSizeEXT");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceDescriptorSizeEXT, &params);
     return params.result;
 }
 
 void WINAPI vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties)
 {
     struct vkGetPhysicalDeviceExternalBufferProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalBufferInfo = pExternalBufferInfo;
     params.pExternalBufferProperties = pExternalBufferProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalBufferProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalBufferProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalBufferProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalBufferPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo *pExternalBufferInfo, VkExternalBufferProperties *pExternalBufferProperties)
 {
     struct vkGetPhysicalDeviceExternalBufferPropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalBufferInfo = pExternalBufferInfo;
     params.pExternalBufferProperties = pExternalBufferProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalBufferPropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalBufferPropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalBufferPropertiesKHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties)
 {
     struct vkGetPhysicalDeviceExternalFenceProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalFenceInfo = pExternalFenceInfo;
     params.pExternalFenceProperties = pExternalFenceProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalFenceProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalFenceProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalFenceProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalFencePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo *pExternalFenceInfo, VkExternalFenceProperties *pExternalFenceProperties)
 {
     struct vkGetPhysicalDeviceExternalFencePropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalFenceInfo = pExternalFenceInfo;
     params.pExternalFenceProperties = pExternalFenceProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalFencePropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalFencePropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalFencePropertiesKHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
 {
     struct vkGetPhysicalDeviceExternalSemaphoreProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalSemaphoreInfo = pExternalSemaphoreInfo;
     params.pExternalSemaphoreProperties = pExternalSemaphoreProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalSemaphoreProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalSemaphoreProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalSemaphoreProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo *pExternalSemaphoreInfo, VkExternalSemaphoreProperties *pExternalSemaphoreProperties)
 {
     struct vkGetPhysicalDeviceExternalSemaphorePropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalSemaphoreInfo = pExternalSemaphoreInfo;
     params.pExternalSemaphoreProperties = pExternalSemaphoreProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalSemaphorePropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalSemaphorePropertiesKHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceExternalTensorPropertiesARM(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalTensorInfoARM *pExternalTensorInfo, VkExternalTensorPropertiesARM *pExternalTensorProperties)
 {
     struct vkGetPhysicalDeviceExternalTensorPropertiesARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pExternalTensorInfo = pExternalTensorInfo;
     params.pExternalTensorProperties = pExternalTensorProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceExternalTensorPropertiesARM, &params);
-    assert(!status && "vkGetPhysicalDeviceExternalTensorPropertiesARM");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceExternalTensorPropertiesARM, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFeatures(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures *pFeatures)
 {
     struct vkGetPhysicalDeviceFeatures_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFeatures = pFeatures;
-    status = UNIX_CALL(vkGetPhysicalDeviceFeatures, &params);
-    assert(!status && "vkGetPhysicalDeviceFeatures");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFeatures, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures)
 {
     struct vkGetPhysicalDeviceFeatures2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFeatures = pFeatures;
-    status = UNIX_CALL(vkGetPhysicalDeviceFeatures2, &params);
-    assert(!status && "vkGetPhysicalDeviceFeatures2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFeatures2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2 *pFeatures)
 {
     struct vkGetPhysicalDeviceFeatures2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFeatures = pFeatures;
-    status = UNIX_CALL(vkGetPhysicalDeviceFeatures2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceFeatures2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFeatures2KHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties *pFormatProperties)
 {
     struct vkGetPhysicalDeviceFormatProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.format = format;
     params.pFormatProperties = pFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceFormatProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFormatProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties)
 {
     struct vkGetPhysicalDeviceFormatProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.format = format;
     params.pFormatProperties = pFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceFormatProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFormatProperties2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2 *pFormatProperties)
 {
     struct vkGetPhysicalDeviceFormatProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.format = format;
     params.pFormatProperties = pFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceFormatProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceFormatProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFormatProperties2KHR, &params);
 }
 
 VkResult WINAPI vkGetPhysicalDeviceFragmentShadingRatesKHR(VkPhysicalDevice physicalDevice, uint32_t *pFragmentShadingRateCount, VkPhysicalDeviceFragmentShadingRateKHR *pFragmentShadingRates)
 {
     struct vkGetPhysicalDeviceFragmentShadingRatesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFragmentShadingRateCount = pFragmentShadingRateCount;
     params.pFragmentShadingRates = pFragmentShadingRates;
-    status = UNIX_CALL(vkGetPhysicalDeviceFragmentShadingRatesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceFragmentShadingRatesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceFragmentShadingRatesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties *pImageFormatProperties)
 {
     struct vkGetPhysicalDeviceImageFormatProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.format = format;
     params.type = type;
@@ -6088,232 +5549,192 @@ VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physic
     params.usage = usage;
     params.flags = flags;
     params.pImageFormatProperties = pImageFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceImageFormatProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceImageFormatProperties, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties)
 {
     struct vkGetPhysicalDeviceImageFormatProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pImageFormatInfo = pImageFormatInfo;
     params.pImageFormatProperties = pImageFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceImageFormatProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceImageFormatProperties2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2 *pImageFormatInfo, VkImageFormatProperties2 *pImageFormatProperties)
 {
     struct vkGetPhysicalDeviceImageFormatProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pImageFormatInfo = pImageFormatInfo;
     params.pImageFormatProperties = pImageFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceImageFormatProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceImageFormatProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceImageFormatProperties2KHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetPhysicalDeviceMemoryProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties *pMemoryProperties)
 {
     struct vkGetPhysicalDeviceMemoryProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pMemoryProperties = pMemoryProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceMemoryProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceMemoryProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
 {
     struct vkGetPhysicalDeviceMemoryProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pMemoryProperties = pMemoryProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceMemoryProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceMemoryProperties2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2 *pMemoryProperties)
 {
     struct vkGetPhysicalDeviceMemoryProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pMemoryProperties = pMemoryProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceMemoryProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceMemoryProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceMemoryProperties2KHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceMultisamplePropertiesEXT(VkPhysicalDevice physicalDevice, VkSampleCountFlagBits samples, VkMultisamplePropertiesEXT *pMultisampleProperties)
 {
     struct vkGetPhysicalDeviceMultisamplePropertiesEXT_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.samples = samples;
     params.pMultisampleProperties = pMultisampleProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceMultisamplePropertiesEXT, &params);
-    assert(!status && "vkGetPhysicalDeviceMultisamplePropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceMultisamplePropertiesEXT, &params);
 }
 
 VkResult WINAPI vkGetPhysicalDeviceOpticalFlowImageFormatsNV(VkPhysicalDevice physicalDevice, const VkOpticalFlowImageFormatInfoNV *pOpticalFlowImageFormatInfo, uint32_t *pFormatCount, VkOpticalFlowImageFormatPropertiesNV *pImageFormatProperties)
 {
     struct vkGetPhysicalDeviceOpticalFlowImageFormatsNV_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pOpticalFlowImageFormatInfo = pOpticalFlowImageFormatInfo;
     params.pFormatCount = pFormatCount;
     params.pImageFormatProperties = pImageFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceOpticalFlowImageFormatsNV, &params);
-    assert(!status && "vkGetPhysicalDeviceOpticalFlowImageFormatsNV");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceOpticalFlowImageFormatsNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pRectCount, VkRect2D *pRects)
 {
     struct vkGetPhysicalDevicePresentRectanglesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.surface = surface;
     params.pRectCount = pRectCount;
     params.pRects = pRects;
-    status = UNIX_CALL(vkGetPhysicalDevicePresentRectanglesKHR, &params);
-    assert(!status && "vkGetPhysicalDevicePresentRectanglesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDevicePresentRectanglesKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetPhysicalDeviceProperties(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties *pProperties)
 {
     struct vkGetPhysicalDeviceProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
 {
     struct vkGetPhysicalDeviceProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceProperties2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2 *pProperties)
 {
     struct vkGetPhysicalDeviceProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceProperties2KHR, &params);
 }
 
 VkResult WINAPI vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkQueueFamilyDataGraphPropertiesARM *pQueueFamilyDataGraphProperties, VkBaseOutStructure *pProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.pQueueFamilyDataGraphProperties = pQueueFamilyDataGraphProperties;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyDataGraphEngineOperationPropertiesARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, const VkQueueFamilyDataGraphPropertiesARM *pQueueFamilyDataGraphProperties, const VkDataGraphOpticalFlowImageFormatInfoARM *pOpticalFlowImageFormatInfo, uint32_t *pFormatCount, VkDataGraphOpticalFlowImageFormatPropertiesARM *pImageFormatProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.pQueueFamilyDataGraphProperties = pQueueFamilyDataGraphProperties;
     params.pOpticalFlowImageFormatInfo = pOpticalFlowImageFormatInfo;
     params.pFormatCount = pFormatCount;
     params.pImageFormatProperties = pImageFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyDataGraphOpticalFlowImageFormatsARM, &params);
     return params.result;
 }
 
 void WINAPI vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceQueueFamilyDataGraphProcessingEngineInfoARM *pQueueFamilyDataGraphProcessingEngineInfo, VkQueueFamilyDataGraphProcessingEnginePropertiesARM *pQueueFamilyDataGraphProcessingEngineProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pQueueFamilyDataGraphProcessingEngineInfo = pQueueFamilyDataGraphProcessingEngineInfo;
     params.pQueueFamilyDataGraphProcessingEngineProperties = pQueueFamilyDataGraphProcessingEngineProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyDataGraphProcessingEnginePropertiesARM, &params);
 }
 
 VkResult WINAPI vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, uint32_t *pQueueFamilyDataGraphPropertyCount, VkQueueFamilyDataGraphPropertiesARM *pQueueFamilyDataGraphProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.pQueueFamilyDataGraphPropertyCount = pQueueFamilyDataGraphPropertyCount;
     params.pQueueFamilyDataGraphProperties = pQueueFamilyDataGraphProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyDataGraphPropertiesARM, &params);
     return params.result;
 }
 
 void WINAPI vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR(VkPhysicalDevice physicalDevice, const VkQueryPoolPerformanceCreateInfoKHR *pPerformanceQueryCreateInfo, uint32_t *pNumPasses)
 {
     struct vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pPerformanceQueryCreateInfo = pPerformanceQueryCreateInfo;
     params.pNumPasses = pNumPasses;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceQueueFamilyProperties(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties *pQueueFamilyProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount;
     params.pQueueFamilyProperties = pQueueFamilyProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount;
     params.pQueueFamilyProperties = pQueueFamilyProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyProperties2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t *pQueueFamilyPropertyCount, VkQueueFamilyProperties2 *pQueueFamilyProperties)
 {
     struct vkGetPhysicalDeviceQueueFamilyProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pQueueFamilyPropertyCount = pQueueFamilyPropertyCount;
     params.pQueueFamilyProperties = pQueueFamilyProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceQueueFamilyProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceQueueFamilyProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceQueueFamilyProperties2KHR, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkSampleCountFlagBits samples, VkImageUsageFlags usage, VkImageTiling tiling, uint32_t *pPropertyCount, VkSparseImageFormatProperties *pProperties)
 {
     struct vkGetPhysicalDeviceSparseImageFormatProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.format = format;
     params.type = type;
@@ -6322,336 +5743,282 @@ void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties(VkPhysicalDevice phys
     params.tiling = tiling;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceSparseImageFormatProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSparseImageFormatProperties, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
 {
     struct vkGetPhysicalDeviceSparseImageFormatProperties2_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFormatInfo = pFormatInfo;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties2, &params);
-    assert(!status && "vkGetPhysicalDeviceSparseImageFormatProperties2");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSparseImageFormatProperties2, &params);
 }
 
 void WINAPI vkGetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2 *pFormatInfo, uint32_t *pPropertyCount, VkSparseImageFormatProperties2 *pProperties)
 {
     struct vkGetPhysicalDeviceSparseImageFormatProperties2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pFormatInfo = pFormatInfo;
     params.pPropertyCount = pPropertyCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceSparseImageFormatProperties2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSparseImageFormatProperties2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSparseImageFormatProperties2KHR, &params);
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV(VkPhysicalDevice physicalDevice, uint32_t *pCombinationCount, VkFramebufferMixedSamplesCombinationNV *pCombinations)
 {
     struct vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pCombinationCount = pCombinationCount;
     params.pCombinations = pCombinations;
-    status = UNIX_CALL(vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, &params);
-    assert(!status && "vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSupportedFramebufferMixedSamplesCombinationsNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfaceCapabilities2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities)
 {
     struct vkGetPhysicalDeviceSurfaceCapabilities2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pSurfaceInfo = pSurfaceInfo;
     params.pSurfaceCapabilities = pSurfaceCapabilities;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfaceCapabilities2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfaceCapabilities2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfaceCapabilities2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR *pSurfaceCapabilities)
 {
     struct vkGetPhysicalDeviceSurfaceCapabilitiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.surface = surface;
     params.pSurfaceCapabilities = pSurfaceCapabilities;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfaceCapabilitiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfaceCapabilitiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, uint32_t *pSurfaceFormatCount, VkSurfaceFormat2KHR *pSurfaceFormats)
 {
     struct vkGetPhysicalDeviceSurfaceFormats2KHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pSurfaceInfo = pSurfaceInfo;
     params.pSurfaceFormatCount = pSurfaceFormatCount;
     params.pSurfaceFormats = pSurfaceFormats;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfaceFormats2KHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfaceFormats2KHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfaceFormats2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pSurfaceFormatCount, VkSurfaceFormatKHR *pSurfaceFormats)
 {
     struct vkGetPhysicalDeviceSurfaceFormatsKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.surface = surface;
     params.pSurfaceFormatCount = pSurfaceFormatCount;
     params.pSurfaceFormats = pSurfaceFormats;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfaceFormatsKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfaceFormatsKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfaceFormatsKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t *pPresentModeCount, VkPresentModeKHR *pPresentModes)
 {
     struct vkGetPhysicalDeviceSurfacePresentModesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.surface = surface;
     params.pPresentModeCount = pPresentModeCount;
     params.pPresentModes = pPresentModes;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfacePresentModesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfacePresentModesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfacePresentModesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32 *pSupported)
 {
     struct vkGetPhysicalDeviceSurfaceSupportKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
     params.surface = surface;
     params.pSupported = pSupported;
-    status = UNIX_CALL(vkGetPhysicalDeviceSurfaceSupportKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceSurfaceSupportKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceSurfaceSupportKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceToolProperties(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties)
 {
     struct vkGetPhysicalDeviceToolProperties_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pToolCount = pToolCount;
     params.pToolProperties = pToolProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceToolProperties, &params);
-    assert(!status && "vkGetPhysicalDeviceToolProperties");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceToolProperties, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceToolPropertiesEXT(VkPhysicalDevice physicalDevice, uint32_t *pToolCount, VkPhysicalDeviceToolProperties *pToolProperties)
 {
     struct vkGetPhysicalDeviceToolPropertiesEXT_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pToolCount = pToolCount;
     params.pToolProperties = pToolProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceToolPropertiesEXT, &params);
-    assert(!status && "vkGetPhysicalDeviceToolPropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceToolPropertiesEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceVideoCapabilitiesKHR(VkPhysicalDevice physicalDevice, const VkVideoProfileInfoKHR *pVideoProfile, VkVideoCapabilitiesKHR *pCapabilities)
 {
     struct vkGetPhysicalDeviceVideoCapabilitiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pVideoProfile = pVideoProfile;
     params.pCapabilities = pCapabilities;
-    status = UNIX_CALL(vkGetPhysicalDeviceVideoCapabilitiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceVideoCapabilitiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceVideoCapabilitiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoEncodeQualityLevelInfoKHR *pQualityLevelInfo, VkVideoEncodeQualityLevelPropertiesKHR *pQualityLevelProperties)
 {
     struct vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pQualityLevelInfo = pQualityLevelInfo;
     params.pQualityLevelProperties = pQualityLevelProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceVideoEncodeQualityLevelPropertiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPhysicalDeviceVideoFormatPropertiesKHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceVideoFormatInfoKHR *pVideoFormatInfo, uint32_t *pVideoFormatPropertyCount, VkVideoFormatPropertiesKHR *pVideoFormatProperties)
 {
     struct vkGetPhysicalDeviceVideoFormatPropertiesKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.pVideoFormatInfo = pVideoFormatInfo;
     params.pVideoFormatPropertyCount = pVideoFormatPropertyCount;
     params.pVideoFormatProperties = pVideoFormatProperties;
-    status = UNIX_CALL(vkGetPhysicalDeviceVideoFormatPropertiesKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceVideoFormatPropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceVideoFormatPropertiesKHR, &params);
     return params.result;
 }
 
 VkBool32 WINAPI vkGetPhysicalDeviceWin32PresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex)
 {
     struct vkGetPhysicalDeviceWin32PresentationSupportKHR_params params;
-    NTSTATUS status;
     params.physicalDevice = physicalDevice;
     params.queueFamilyIndex = queueFamilyIndex;
-    status = UNIX_CALL(vkGetPhysicalDeviceWin32PresentationSupportKHR, &params);
-    assert(!status && "vkGetPhysicalDeviceWin32PresentationSupportKHR");
+    UNIX_CALL_CHECKED(vkGetPhysicalDeviceWin32PresentationSupportKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelineBinaryDataKHR(VkDevice device, const VkPipelineBinaryDataInfoKHR *pInfo, VkPipelineBinaryKeyKHR *pPipelineBinaryKey, size_t *pPipelineBinaryDataSize, void *pPipelineBinaryData)
 {
     struct vkGetPipelineBinaryDataKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pPipelineBinaryKey = pPipelineBinaryKey;
     params.pPipelineBinaryDataSize = pPipelineBinaryDataSize;
     params.pPipelineBinaryData = pPipelineBinaryData;
-    status = UNIX_CALL(vkGetPipelineBinaryDataKHR, &params);
-    assert(!status && "vkGetPipelineBinaryDataKHR");
+    UNIX_CALL_CHECKED(vkGetPipelineBinaryDataKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelineCacheData(VkDevice device, VkPipelineCache pipelineCache, size_t *pDataSize, void *pData)
 {
     struct vkGetPipelineCacheData_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipelineCache = pipelineCache;
     params.pDataSize = pDataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetPipelineCacheData, &params);
-    assert(!status && "vkGetPipelineCacheData");
+    UNIX_CALL_CHECKED(vkGetPipelineCacheData, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelineExecutableInternalRepresentationsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pInternalRepresentationCount, VkPipelineExecutableInternalRepresentationKHR *pInternalRepresentations)
 {
     struct vkGetPipelineExecutableInternalRepresentationsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pExecutableInfo = pExecutableInfo;
     params.pInternalRepresentationCount = pInternalRepresentationCount;
     params.pInternalRepresentations = pInternalRepresentations;
-    status = UNIX_CALL(vkGetPipelineExecutableInternalRepresentationsKHR, &params);
-    assert(!status && "vkGetPipelineExecutableInternalRepresentationsKHR");
+    UNIX_CALL_CHECKED(vkGetPipelineExecutableInternalRepresentationsKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelineExecutablePropertiesKHR(VkDevice device, const VkPipelineInfoKHR *pPipelineInfo, uint32_t *pExecutableCount, VkPipelineExecutablePropertiesKHR *pProperties)
 {
     struct vkGetPipelineExecutablePropertiesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPipelineInfo = pPipelineInfo;
     params.pExecutableCount = pExecutableCount;
     params.pProperties = pProperties;
-    status = UNIX_CALL(vkGetPipelineExecutablePropertiesKHR, &params);
-    assert(!status && "vkGetPipelineExecutablePropertiesKHR");
+    UNIX_CALL_CHECKED(vkGetPipelineExecutablePropertiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelineExecutableStatisticsKHR(VkDevice device, const VkPipelineExecutableInfoKHR *pExecutableInfo, uint32_t *pStatisticCount, VkPipelineExecutableStatisticKHR *pStatistics)
 {
     struct vkGetPipelineExecutableStatisticsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pExecutableInfo = pExecutableInfo;
     params.pStatisticCount = pStatisticCount;
     params.pStatistics = pStatistics;
-    status = UNIX_CALL(vkGetPipelineExecutableStatisticsKHR, &params);
-    assert(!status && "vkGetPipelineExecutableStatisticsKHR");
+    UNIX_CALL_CHECKED(vkGetPipelineExecutableStatisticsKHR, &params);
     return params.result;
 }
 
 VkDeviceAddress WINAPI vkGetPipelineIndirectDeviceAddressNV(VkDevice device, const VkPipelineIndirectDeviceAddressInfoNV *pInfo)
 {
     struct vkGetPipelineIndirectDeviceAddressNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetPipelineIndirectDeviceAddressNV, &params);
-    assert(!status && "vkGetPipelineIndirectDeviceAddressNV");
+    UNIX_CALL_CHECKED(vkGetPipelineIndirectDeviceAddressNV, &params);
     return params.result;
 }
 
 void WINAPI vkGetPipelineIndirectMemoryRequirementsNV(VkDevice device, const VkComputePipelineCreateInfo *pCreateInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetPipelineIndirectMemoryRequirementsNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetPipelineIndirectMemoryRequirementsNV, &params);
-    assert(!status && "vkGetPipelineIndirectMemoryRequirementsNV");
+    UNIX_CALL_CHECKED(vkGetPipelineIndirectMemoryRequirementsNV, &params);
 }
 
 VkResult WINAPI vkGetPipelineKeyKHR(VkDevice device, const VkPipelineCreateInfoKHR *pPipelineCreateInfo, VkPipelineBinaryKeyKHR *pPipelineKey)
 {
     struct vkGetPipelineKeyKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPipelineCreateInfo = pPipelineCreateInfo;
     params.pPipelineKey = pPipelineKey;
-    status = UNIX_CALL(vkGetPipelineKeyKHR, &params);
-    assert(!status && "vkGetPipelineKeyKHR");
+    UNIX_CALL_CHECKED(vkGetPipelineKeyKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetPipelinePropertiesEXT(VkDevice device, const VkPipelineInfoKHR *pPipelineInfo, VkBaseOutStructure *pPipelineProperties)
 {
     struct vkGetPipelinePropertiesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pPipelineInfo = pPipelineInfo;
     params.pPipelineProperties = pPipelineProperties;
-    status = UNIX_CALL(vkGetPipelinePropertiesEXT, &params);
-    assert(!status && "vkGetPipelinePropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetPipelinePropertiesEXT, &params);
     return params.result;
 }
 
 void WINAPI vkGetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData)
 {
     struct vkGetPrivateData_params params;
-    NTSTATUS status;
     params.device = device;
     params.objectType = objectType;
     params.objectHandle = objectHandle;
     params.privateDataSlot = privateDataSlot;
     params.pData = pData;
-    status = UNIX_CALL(vkGetPrivateData, &params);
-    assert(!status && "vkGetPrivateData");
+    UNIX_CALL_CHECKED(vkGetPrivateData, &params);
 }
 
 void WINAPI vkGetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t *pData)
 {
     struct vkGetPrivateDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.objectType = objectType;
     params.objectHandle = objectHandle;
     params.privateDataSlot = privateDataSlot;
     params.pData = pData;
-    status = UNIX_CALL(vkGetPrivateDataEXT, &params);
-    assert(!status && "vkGetPrivateDataEXT");
+    UNIX_CALL_CHECKED(vkGetPrivateDataEXT, &params);
 }
 
 VkResult WINAPI vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void *pData, VkDeviceSize stride, VkQueryResultFlags flags)
 {
     struct vkGetQueryPoolResults_params params;
-    NTSTATUS status;
     params.device = device;
     params.queryPool = queryPool;
     params.firstQuery = firstQuery;
@@ -6660,1024 +6027,851 @@ VkResult WINAPI vkGetQueryPoolResults(VkDevice device, VkQueryPool queryPool, ui
     params.pData = pData;
     params.stride = stride;
     params.flags = flags;
-    status = UNIX_CALL(vkGetQueryPoolResults, &params);
-    assert(!status && "vkGetQueryPoolResults");
+    UNIX_CALL_CHECKED(vkGetQueryPoolResults, &params);
     return params.result;
 }
 
 void WINAPI vkGetQueueCheckpointData2NV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointData2NV *pCheckpointData)
 {
     struct vkGetQueueCheckpointData2NV_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pCheckpointDataCount = pCheckpointDataCount;
     params.pCheckpointData = pCheckpointData;
-    status = UNIX_CALL(vkGetQueueCheckpointData2NV, &params);
-    assert(!status && "vkGetQueueCheckpointData2NV");
+    UNIX_CALL_CHECKED(vkGetQueueCheckpointData2NV, &params);
 }
 
 void WINAPI vkGetQueueCheckpointDataNV(VkQueue queue, uint32_t *pCheckpointDataCount, VkCheckpointDataNV *pCheckpointData)
 {
     struct vkGetQueueCheckpointDataNV_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pCheckpointDataCount = pCheckpointDataCount;
     params.pCheckpointData = pCheckpointData;
-    status = UNIX_CALL(vkGetQueueCheckpointDataNV, &params);
-    assert(!status && "vkGetQueueCheckpointDataNV");
+    UNIX_CALL_CHECKED(vkGetQueueCheckpointDataNV, &params);
 }
 
 VkResult WINAPI vkGetRayTracingCaptureReplayShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData)
 {
     struct vkGetRayTracingCaptureReplayShaderGroupHandlesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.firstGroup = firstGroup;
     params.groupCount = groupCount;
     params.dataSize = dataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, &params);
-    assert(!status && "vkGetRayTracingCaptureReplayShaderGroupHandlesKHR");
+    UNIX_CALL_CHECKED(vkGetRayTracingCaptureReplayShaderGroupHandlesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetRayTracingShaderGroupHandlesKHR(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData)
 {
     struct vkGetRayTracingShaderGroupHandlesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.firstGroup = firstGroup;
     params.groupCount = groupCount;
     params.dataSize = dataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetRayTracingShaderGroupHandlesKHR, &params);
-    assert(!status && "vkGetRayTracingShaderGroupHandlesKHR");
+    UNIX_CALL_CHECKED(vkGetRayTracingShaderGroupHandlesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetRayTracingShaderGroupHandlesNV(VkDevice device, VkPipeline pipeline, uint32_t firstGroup, uint32_t groupCount, size_t dataSize, void *pData)
 {
     struct vkGetRayTracingShaderGroupHandlesNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.firstGroup = firstGroup;
     params.groupCount = groupCount;
     params.dataSize = dataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetRayTracingShaderGroupHandlesNV, &params);
-    assert(!status && "vkGetRayTracingShaderGroupHandlesNV");
+    UNIX_CALL_CHECKED(vkGetRayTracingShaderGroupHandlesNV, &params);
     return params.result;
 }
 
 VkDeviceSize WINAPI vkGetRayTracingShaderGroupStackSizeKHR(VkDevice device, VkPipeline pipeline, uint32_t group, VkShaderGroupShaderKHR groupShader)
 {
     struct vkGetRayTracingShaderGroupStackSizeKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.group = group;
     params.groupShader = groupShader;
-    status = UNIX_CALL(vkGetRayTracingShaderGroupStackSizeKHR, &params);
-    assert(!status && "vkGetRayTracingShaderGroupStackSizeKHR");
+    UNIX_CALL_CHECKED(vkGetRayTracingShaderGroupStackSizeKHR, &params);
     return params.result;
 }
 
 void WINAPI vkGetRenderAreaGranularity(VkDevice device, VkRenderPass renderPass, VkExtent2D *pGranularity)
 {
     struct vkGetRenderAreaGranularity_params params;
-    NTSTATUS status;
     params.device = device;
     params.renderPass = renderPass;
     params.pGranularity = pGranularity;
-    status = UNIX_CALL(vkGetRenderAreaGranularity, &params);
-    assert(!status && "vkGetRenderAreaGranularity");
+    UNIX_CALL_CHECKED(vkGetRenderAreaGranularity, &params);
 }
 
 void WINAPI vkGetRenderingAreaGranularity(VkDevice device, const VkRenderingAreaInfo *pRenderingAreaInfo, VkExtent2D *pGranularity)
 {
     struct vkGetRenderingAreaGranularity_params params;
-    NTSTATUS status;
     params.device = device;
     params.pRenderingAreaInfo = pRenderingAreaInfo;
     params.pGranularity = pGranularity;
-    status = UNIX_CALL(vkGetRenderingAreaGranularity, &params);
-    assert(!status && "vkGetRenderingAreaGranularity");
+    UNIX_CALL_CHECKED(vkGetRenderingAreaGranularity, &params);
 }
 
 void WINAPI vkGetRenderingAreaGranularityKHR(VkDevice device, const VkRenderingAreaInfo *pRenderingAreaInfo, VkExtent2D *pGranularity)
 {
     struct vkGetRenderingAreaGranularityKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pRenderingAreaInfo = pRenderingAreaInfo;
     params.pGranularity = pGranularity;
-    status = UNIX_CALL(vkGetRenderingAreaGranularityKHR, &params);
-    assert(!status && "vkGetRenderingAreaGranularityKHR");
+    UNIX_CALL_CHECKED(vkGetRenderingAreaGranularityKHR, &params);
 }
 
 VkResult WINAPI vkGetSamplerOpaqueCaptureDescriptorDataEXT(VkDevice device, const VkSamplerCaptureDescriptorDataInfoEXT *pInfo, void *pData)
 {
     struct vkGetSamplerOpaqueCaptureDescriptorDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetSamplerOpaqueCaptureDescriptorDataEXT, &params);
-    assert(!status && "vkGetSamplerOpaqueCaptureDescriptorDataEXT");
+    UNIX_CALL_CHECKED(vkGetSamplerOpaqueCaptureDescriptorDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t *pValue)
 {
     struct vkGetSemaphoreCounterValue_params params;
-    NTSTATUS status;
     params.device = device;
     params.semaphore = semaphore;
     params.pValue = pValue;
-    status = UNIX_CALL(vkGetSemaphoreCounterValue, &params);
-    assert(!status && "vkGetSemaphoreCounterValue");
+    UNIX_CALL_CHECKED(vkGetSemaphoreCounterValue, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetSemaphoreCounterValueKHR(VkDevice device, VkSemaphore semaphore, uint64_t *pValue)
 {
     struct vkGetSemaphoreCounterValueKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.semaphore = semaphore;
     params.pValue = pValue;
-    status = UNIX_CALL(vkGetSemaphoreCounterValueKHR, &params);
-    assert(!status && "vkGetSemaphoreCounterValueKHR");
+    UNIX_CALL_CHECKED(vkGetSemaphoreCounterValueKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetSemaphoreWin32HandleKHR(VkDevice device, const VkSemaphoreGetWin32HandleInfoKHR *pGetWin32HandleInfo, HANDLE *pHandle)
 {
     struct vkGetSemaphoreWin32HandleKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pGetWin32HandleInfo = pGetWin32HandleInfo;
     params.pHandle = pHandle;
-    status = UNIX_CALL(vkGetSemaphoreWin32HandleKHR, &params);
-    assert(!status && "vkGetSemaphoreWin32HandleKHR");
+    UNIX_CALL_CHECKED(vkGetSemaphoreWin32HandleKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetShaderBinaryDataEXT(VkDevice device, VkShaderEXT shader, size_t *pDataSize, void *pData)
 {
     struct vkGetShaderBinaryDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.shader = shader;
     params.pDataSize = pDataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetShaderBinaryDataEXT, &params);
-    assert(!status && "vkGetShaderBinaryDataEXT");
+    UNIX_CALL_CHECKED(vkGetShaderBinaryDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetShaderInfoAMD(VkDevice device, VkPipeline pipeline, VkShaderStageFlagBits shaderStage, VkShaderInfoTypeAMD infoType, size_t *pInfoSize, void *pInfo)
 {
     struct vkGetShaderInfoAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.pipeline = pipeline;
     params.shaderStage = shaderStage;
     params.infoType = infoType;
     params.pInfoSize = pInfoSize;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkGetShaderInfoAMD, &params);
-    assert(!status && "vkGetShaderInfoAMD");
+    UNIX_CALL_CHECKED(vkGetShaderInfoAMD, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetShaderInstrumentationValuesARM(VkDevice device, VkShaderInstrumentationARM instrumentation, uint32_t *pMetricBlockCount, void *pMetricValues, VkShaderInstrumentationValuesFlagsARM flags)
 {
     struct vkGetShaderInstrumentationValuesARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.instrumentation = instrumentation;
     params.pMetricBlockCount = pMetricBlockCount;
     params.pMetricValues = pMetricValues;
     params.flags = flags;
-    status = UNIX_CALL(vkGetShaderInstrumentationValuesARM, &params);
-    assert(!status && "vkGetShaderInstrumentationValuesARM");
+    UNIX_CALL_CHECKED(vkGetShaderInstrumentationValuesARM, &params);
     return params.result;
 }
 
 void WINAPI vkGetShaderModuleCreateInfoIdentifierEXT(VkDevice device, const VkShaderModuleCreateInfo *pCreateInfo, VkShaderModuleIdentifierEXT *pIdentifier)
 {
     struct vkGetShaderModuleCreateInfoIdentifierEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pCreateInfo = pCreateInfo;
     params.pIdentifier = pIdentifier;
-    status = UNIX_CALL(vkGetShaderModuleCreateInfoIdentifierEXT, &params);
-    assert(!status && "vkGetShaderModuleCreateInfoIdentifierEXT");
+    UNIX_CALL_CHECKED(vkGetShaderModuleCreateInfoIdentifierEXT, &params);
 }
 
 void WINAPI vkGetShaderModuleIdentifierEXT(VkDevice device, VkShaderModule shaderModule, VkShaderModuleIdentifierEXT *pIdentifier)
 {
     struct vkGetShaderModuleIdentifierEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.shaderModule = shaderModule;
     params.pIdentifier = pIdentifier;
-    status = UNIX_CALL(vkGetShaderModuleIdentifierEXT, &params);
-    assert(!status && "vkGetShaderModuleIdentifierEXT");
+    UNIX_CALL_CHECKED(vkGetShaderModuleIdentifierEXT, &params);
 }
 
 VkResult WINAPI vkGetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages)
 {
     struct vkGetSwapchainImagesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pSwapchainImageCount = pSwapchainImageCount;
     params.pSwapchainImages = pSwapchainImages;
-    status = UNIX_CALL(vkGetSwapchainImagesKHR, &params);
-    assert(!status && "vkGetSwapchainImagesKHR");
+    UNIX_CALL_CHECKED(vkGetSwapchainImagesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetSwapchainTimeDomainPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimeDomainPropertiesEXT *pSwapchainTimeDomainProperties, uint64_t *pTimeDomainsCounter)
 {
     struct vkGetSwapchainTimeDomainPropertiesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pSwapchainTimeDomainProperties = pSwapchainTimeDomainProperties;
     params.pTimeDomainsCounter = pTimeDomainsCounter;
-    status = UNIX_CALL(vkGetSwapchainTimeDomainPropertiesEXT, &params);
-    assert(!status && "vkGetSwapchainTimeDomainPropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetSwapchainTimeDomainPropertiesEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetSwapchainTimingPropertiesEXT(VkDevice device, VkSwapchainKHR swapchain, VkSwapchainTimingPropertiesEXT *pSwapchainTimingProperties, uint64_t *pSwapchainTimingPropertiesCounter)
 {
     struct vkGetSwapchainTimingPropertiesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pSwapchainTimingProperties = pSwapchainTimingProperties;
     params.pSwapchainTimingPropertiesCounter = pSwapchainTimingPropertiesCounter;
-    status = UNIX_CALL(vkGetSwapchainTimingPropertiesEXT, &params);
-    assert(!status && "vkGetSwapchainTimingPropertiesEXT");
+    UNIX_CALL_CHECKED(vkGetSwapchainTimingPropertiesEXT, &params);
     return params.result;
 }
 
 void WINAPI vkGetTensorMemoryRequirementsARM(VkDevice device, const VkTensorMemoryRequirementsInfoARM *pInfo, VkMemoryRequirements2 *pMemoryRequirements)
 {
     struct vkGetTensorMemoryRequirementsARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetTensorMemoryRequirementsARM, &params);
-    assert(!status && "vkGetTensorMemoryRequirementsARM");
+    UNIX_CALL_CHECKED(vkGetTensorMemoryRequirementsARM, &params);
 }
 
 VkResult WINAPI vkGetTensorOpaqueCaptureDataARM(VkDevice device, uint32_t tensorCount, const VkTensorARM *pTensors, VkHostAddressRangeEXT *pDatas)
 {
     struct vkGetTensorOpaqueCaptureDataARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.tensorCount = tensorCount;
     params.pTensors = pTensors;
     params.pDatas = pDatas;
-    status = UNIX_CALL(vkGetTensorOpaqueCaptureDataARM, &params);
-    assert(!status && "vkGetTensorOpaqueCaptureDataARM");
+    UNIX_CALL_CHECKED(vkGetTensorOpaqueCaptureDataARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetTensorOpaqueCaptureDescriptorDataARM(VkDevice device, const VkTensorCaptureDescriptorDataInfoARM *pInfo, void *pData)
 {
     struct vkGetTensorOpaqueCaptureDescriptorDataARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetTensorOpaqueCaptureDescriptorDataARM, &params);
-    assert(!status && "vkGetTensorOpaqueCaptureDescriptorDataARM");
+    UNIX_CALL_CHECKED(vkGetTensorOpaqueCaptureDescriptorDataARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetTensorViewOpaqueCaptureDescriptorDataARM(VkDevice device, const VkTensorViewCaptureDescriptorDataInfoARM *pInfo, void *pData)
 {
     struct vkGetTensorViewOpaqueCaptureDescriptorDataARM_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pData = pData;
-    status = UNIX_CALL(vkGetTensorViewOpaqueCaptureDescriptorDataARM, &params);
-    assert(!status && "vkGetTensorViewOpaqueCaptureDescriptorDataARM");
+    UNIX_CALL_CHECKED(vkGetTensorViewOpaqueCaptureDescriptorDataARM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetValidationCacheDataEXT(VkDevice device, VkValidationCacheEXT validationCache, size_t *pDataSize, void *pData)
 {
     struct vkGetValidationCacheDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.validationCache = validationCache;
     params.pDataSize = pDataSize;
     params.pData = pData;
-    status = UNIX_CALL(vkGetValidationCacheDataEXT, &params);
-    assert(!status && "vkGetValidationCacheDataEXT");
+    UNIX_CALL_CHECKED(vkGetValidationCacheDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkGetVideoSessionMemoryRequirementsKHR(VkDevice device, VkVideoSessionKHR videoSession, uint32_t *pMemoryRequirementsCount, VkVideoSessionMemoryRequirementsKHR *pMemoryRequirements)
 {
     struct vkGetVideoSessionMemoryRequirementsKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.videoSession = videoSession;
     params.pMemoryRequirementsCount = pMemoryRequirementsCount;
     params.pMemoryRequirements = pMemoryRequirements;
-    status = UNIX_CALL(vkGetVideoSessionMemoryRequirementsKHR, &params);
-    assert(!status && "vkGetVideoSessionMemoryRequirementsKHR");
+    UNIX_CALL_CHECKED(vkGetVideoSessionMemoryRequirementsKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkImportFenceWin32HandleKHR(VkDevice device, const VkImportFenceWin32HandleInfoKHR *pImportFenceWin32HandleInfo)
 {
     struct vkImportFenceWin32HandleKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pImportFenceWin32HandleInfo = pImportFenceWin32HandleInfo;
-    status = UNIX_CALL(vkImportFenceWin32HandleKHR, &params);
-    assert(!status && "vkImportFenceWin32HandleKHR");
+    UNIX_CALL_CHECKED(vkImportFenceWin32HandleKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkImportSemaphoreWin32HandleKHR(VkDevice device, const VkImportSemaphoreWin32HandleInfoKHR *pImportSemaphoreWin32HandleInfo)
 {
     struct vkImportSemaphoreWin32HandleKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pImportSemaphoreWin32HandleInfo = pImportSemaphoreWin32HandleInfo;
-    status = UNIX_CALL(vkImportSemaphoreWin32HandleKHR, &params);
-    assert(!status && "vkImportSemaphoreWin32HandleKHR");
+    UNIX_CALL_CHECKED(vkImportSemaphoreWin32HandleKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkInitializePerformanceApiINTEL(VkDevice device, const VkInitializePerformanceApiInfoINTEL *pInitializeInfo)
 {
     struct vkInitializePerformanceApiINTEL_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInitializeInfo = pInitializeInfo;
-    status = UNIX_CALL(vkInitializePerformanceApiINTEL, &params);
-    assert(!status && "vkInitializePerformanceApiINTEL");
+    UNIX_CALL_CHECKED(vkInitializePerformanceApiINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkInvalidateMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges)
 {
     struct vkInvalidateMappedMemoryRanges_params params;
-    NTSTATUS status;
     params.device = device;
     params.memoryRangeCount = memoryRangeCount;
     params.pMemoryRanges = pMemoryRanges;
-    status = UNIX_CALL(vkInvalidateMappedMemoryRanges, &params);
-    assert(!status && "vkInvalidateMappedMemoryRanges");
+    UNIX_CALL_CHECKED(vkInvalidateMappedMemoryRanges, &params);
     return params.result;
 }
 
 VkResult WINAPI vkLatencySleepNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepInfoNV *pSleepInfo)
 {
     struct vkLatencySleepNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pSleepInfo = pSleepInfo;
-    status = UNIX_CALL(vkLatencySleepNV, &params);
-    assert(!status && "vkLatencySleepNV");
+    UNIX_CALL_CHECKED(vkLatencySleepNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDeviceSize size, VkMemoryMapFlags flags, void **ppData)
 {
     struct vkMapMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.memory = memory;
     params.offset = offset;
     params.size = size;
     params.flags = flags;
     params.ppData = ppData;
-    status = UNIX_CALL(vkMapMemory, &params);
-    assert(!status && "vkMapMemory");
+    UNIX_CALL_CHECKED(vkMapMemory, &params);
     return params.result;
 }
 
 VkResult WINAPI vkMapMemory2(VkDevice device, const VkMemoryMapInfo *pMemoryMapInfo, void **ppData)
 {
     struct vkMapMemory2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pMemoryMapInfo = pMemoryMapInfo;
     params.ppData = ppData;
-    status = UNIX_CALL(vkMapMemory2, &params);
-    assert(!status && "vkMapMemory2");
+    UNIX_CALL_CHECKED(vkMapMemory2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkMapMemory2KHR(VkDevice device, const VkMemoryMapInfo *pMemoryMapInfo, void **ppData)
 {
     struct vkMapMemory2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pMemoryMapInfo = pMemoryMapInfo;
     params.ppData = ppData;
-    status = UNIX_CALL(vkMapMemory2KHR, &params);
-    assert(!status && "vkMapMemory2KHR");
+    UNIX_CALL_CHECKED(vkMapMemory2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkMergePipelineCaches(VkDevice device, VkPipelineCache dstCache, uint32_t srcCacheCount, const VkPipelineCache *pSrcCaches)
 {
     struct vkMergePipelineCaches_params params;
-    NTSTATUS status;
     params.device = device;
     params.dstCache = dstCache;
     params.srcCacheCount = srcCacheCount;
     params.pSrcCaches = pSrcCaches;
-    status = UNIX_CALL(vkMergePipelineCaches, &params);
-    assert(!status && "vkMergePipelineCaches");
+    UNIX_CALL_CHECKED(vkMergePipelineCaches, &params);
     return params.result;
 }
 
 VkResult WINAPI vkMergeValidationCachesEXT(VkDevice device, VkValidationCacheEXT dstCache, uint32_t srcCacheCount, const VkValidationCacheEXT *pSrcCaches)
 {
     struct vkMergeValidationCachesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.dstCache = dstCache;
     params.srcCacheCount = srcCacheCount;
     params.pSrcCaches = pSrcCaches;
-    status = UNIX_CALL(vkMergeValidationCachesEXT, &params);
-    assert(!status && "vkMergeValidationCachesEXT");
+    UNIX_CALL_CHECKED(vkMergeValidationCachesEXT, &params);
     return params.result;
 }
 
 void WINAPI vkQueueBeginDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo)
 {
     struct vkQueueBeginDebugUtilsLabelEXT_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pLabelInfo = pLabelInfo;
-    status = UNIX_CALL(vkQueueBeginDebugUtilsLabelEXT, &params);
-    assert(!status && "vkQueueBeginDebugUtilsLabelEXT");
+    UNIX_CALL_CHECKED(vkQueueBeginDebugUtilsLabelEXT, &params);
 }
 
 VkResult WINAPI vkQueueBindSparse(VkQueue queue, uint32_t bindInfoCount, const VkBindSparseInfo *pBindInfo, VkFence fence)
 {
     struct vkQueueBindSparse_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.bindInfoCount = bindInfoCount;
     params.pBindInfo = pBindInfo;
     params.fence = fence;
-    status = UNIX_CALL(vkQueueBindSparse, &params);
-    assert(!status && "vkQueueBindSparse");
+    UNIX_CALL_CHECKED(vkQueueBindSparse, &params);
     return params.result;
 }
 
 void WINAPI vkQueueEndDebugUtilsLabelEXT(VkQueue queue)
 {
     struct vkQueueEndDebugUtilsLabelEXT_params params;
-    NTSTATUS status;
     params.queue = queue;
-    status = UNIX_CALL(vkQueueEndDebugUtilsLabelEXT, &params);
-    assert(!status && "vkQueueEndDebugUtilsLabelEXT");
+    UNIX_CALL_CHECKED(vkQueueEndDebugUtilsLabelEXT, &params);
 }
 
 void WINAPI vkQueueInsertDebugUtilsLabelEXT(VkQueue queue, const VkDebugUtilsLabelEXT *pLabelInfo)
 {
     struct vkQueueInsertDebugUtilsLabelEXT_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pLabelInfo = pLabelInfo;
-    status = UNIX_CALL(vkQueueInsertDebugUtilsLabelEXT, &params);
-    assert(!status && "vkQueueInsertDebugUtilsLabelEXT");
+    UNIX_CALL_CHECKED(vkQueueInsertDebugUtilsLabelEXT, &params);
 }
 
 void WINAPI vkQueueNotifyOutOfBandNV(VkQueue queue, const VkOutOfBandQueueTypeInfoNV *pQueueTypeInfo)
 {
     struct vkQueueNotifyOutOfBandNV_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pQueueTypeInfo = pQueueTypeInfo;
-    status = UNIX_CALL(vkQueueNotifyOutOfBandNV, &params);
-    assert(!status && "vkQueueNotifyOutOfBandNV");
+    UNIX_CALL_CHECKED(vkQueueNotifyOutOfBandNV, &params);
 }
 
 VkResult WINAPI vkQueuePresentKHR(VkQueue queue, const VkPresentInfoKHR *pPresentInfo)
 {
     struct vkQueuePresentKHR_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pPresentInfo = pPresentInfo;
-    status = UNIX_CALL(vkQueuePresentKHR, &params);
-    assert(!status && "vkQueuePresentKHR");
+    UNIX_CALL_CHECKED(vkQueuePresentKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueSetPerfHintQCOM(VkQueue queue, const VkPerfHintInfoQCOM *pPerfHintInfo)
 {
     struct vkQueueSetPerfHintQCOM_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.pPerfHintInfo = pPerfHintInfo;
-    status = UNIX_CALL(vkQueueSetPerfHintQCOM, &params);
-    assert(!status && "vkQueueSetPerfHintQCOM");
+    UNIX_CALL_CHECKED(vkQueueSetPerfHintQCOM, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueSetPerformanceConfigurationINTEL(VkQueue queue, VkPerformanceConfigurationINTEL configuration)
 {
     struct vkQueueSetPerformanceConfigurationINTEL_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.configuration = configuration;
-    status = UNIX_CALL(vkQueueSetPerformanceConfigurationINTEL, &params);
-    assert(!status && "vkQueueSetPerformanceConfigurationINTEL");
+    UNIX_CALL_CHECKED(vkQueueSetPerformanceConfigurationINTEL, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo *pSubmits, VkFence fence)
 {
     struct vkQueueSubmit_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.submitCount = submitCount;
     params.pSubmits = pSubmits;
     params.fence = fence;
-    status = UNIX_CALL(vkQueueSubmit, &params);
-    assert(!status && "vkQueueSubmit");
+    UNIX_CALL_CHECKED(vkQueueSubmit, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueSubmit2(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence)
 {
     struct vkQueueSubmit2_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.submitCount = submitCount;
     params.pSubmits = pSubmits;
     params.fence = fence;
-    status = UNIX_CALL(vkQueueSubmit2, &params);
-    assert(!status && "vkQueueSubmit2");
+    UNIX_CALL_CHECKED(vkQueueSubmit2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueSubmit2KHR(VkQueue queue, uint32_t submitCount, const VkSubmitInfo2 *pSubmits, VkFence fence)
 {
     struct vkQueueSubmit2KHR_params params;
-    NTSTATUS status;
     params.queue = queue;
     params.submitCount = submitCount;
     params.pSubmits = pSubmits;
     params.fence = fence;
-    status = UNIX_CALL(vkQueueSubmit2KHR, &params);
-    assert(!status && "vkQueueSubmit2KHR");
+    UNIX_CALL_CHECKED(vkQueueSubmit2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkQueueWaitIdle(VkQueue queue)
 {
     struct vkQueueWaitIdle_params params;
-    NTSTATUS status;
     params.queue = queue;
-    status = UNIX_CALL(vkQueueWaitIdle, &params);
-    assert(!status && "vkQueueWaitIdle");
+    UNIX_CALL_CHECKED(vkQueueWaitIdle, &params);
     return params.result;
 }
 
 VkResult WINAPI vkRegisterCustomBorderColorEXT(VkDevice device, const VkSamplerCustomBorderColorCreateInfoEXT *pBorderColor, VkBool32 requestIndex, uint32_t *pIndex)
 {
     struct vkRegisterCustomBorderColorEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pBorderColor = pBorderColor;
     params.requestIndex = requestIndex;
     params.pIndex = pIndex;
-    status = UNIX_CALL(vkRegisterCustomBorderColorEXT, &params);
-    assert(!status && "vkRegisterCustomBorderColorEXT");
+    UNIX_CALL_CHECKED(vkRegisterCustomBorderColorEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkReleaseCapturedPipelineDataKHR(VkDevice device, const VkReleaseCapturedPipelineDataInfoKHR *pInfo, const VkAllocationCallbacks *pAllocator)
 {
     struct vkReleaseCapturedPipelineDataKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
     params.pAllocator = pAllocator;
-    status = UNIX_CALL(vkReleaseCapturedPipelineDataKHR, &params);
-    assert(!status && "vkReleaseCapturedPipelineDataKHR");
+    UNIX_CALL_CHECKED(vkReleaseCapturedPipelineDataKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkReleasePerformanceConfigurationINTEL(VkDevice device, VkPerformanceConfigurationINTEL configuration)
 {
     struct vkReleasePerformanceConfigurationINTEL_params params;
-    NTSTATUS status;
     params.device = device;
     params.configuration = configuration;
-    status = UNIX_CALL(vkReleasePerformanceConfigurationINTEL, &params);
-    assert(!status && "vkReleasePerformanceConfigurationINTEL");
+    UNIX_CALL_CHECKED(vkReleasePerformanceConfigurationINTEL, &params);
     return params.result;
 }
 
 void WINAPI vkReleaseProfilingLockKHR(VkDevice device)
 {
     struct vkReleaseProfilingLockKHR_params params;
-    NTSTATUS status;
     params.device = device;
-    status = UNIX_CALL(vkReleaseProfilingLockKHR, &params);
-    assert(!status && "vkReleaseProfilingLockKHR");
+    UNIX_CALL_CHECKED(vkReleaseProfilingLockKHR, &params);
 }
 
 VkResult WINAPI vkReleaseSwapchainImagesEXT(VkDevice device, const VkReleaseSwapchainImagesInfoKHR *pReleaseInfo)
 {
     struct vkReleaseSwapchainImagesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pReleaseInfo = pReleaseInfo;
-    status = UNIX_CALL(vkReleaseSwapchainImagesEXT, &params);
-    assert(!status && "vkReleaseSwapchainImagesEXT");
+    UNIX_CALL_CHECKED(vkReleaseSwapchainImagesEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkReleaseSwapchainImagesKHR(VkDevice device, const VkReleaseSwapchainImagesInfoKHR *pReleaseInfo)
 {
     struct vkReleaseSwapchainImagesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pReleaseInfo = pReleaseInfo;
-    status = UNIX_CALL(vkReleaseSwapchainImagesKHR, &params);
-    assert(!status && "vkReleaseSwapchainImagesKHR");
+    UNIX_CALL_CHECKED(vkReleaseSwapchainImagesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetCommandBuffer(VkCommandBuffer commandBuffer, VkCommandBufferResetFlags flags)
 {
     struct vkResetCommandBuffer_params params;
-    NTSTATUS status;
     params.commandBuffer = commandBuffer;
     params.flags = flags;
-    status = UNIX_CALL(vkResetCommandBuffer, &params);
-    assert(!status && "vkResetCommandBuffer");
+    UNIX_CALL_CHECKED(vkResetCommandBuffer, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags)
 {
     struct vkResetCommandPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.commandPool = commandPool;
     params.flags = flags;
-    status = UNIX_CALL(vkResetCommandPool, &params);
-    assert(!status && "vkResetCommandPool");
+    UNIX_CALL_CHECKED(vkResetCommandPool, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags)
 {
     struct vkResetDescriptorPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorPool = descriptorPool;
     params.flags = flags;
-    status = UNIX_CALL(vkResetDescriptorPool, &params);
-    assert(!status && "vkResetDescriptorPool");
+    UNIX_CALL_CHECKED(vkResetDescriptorPool, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetEvent(VkDevice device, VkEvent event)
 {
     struct vkResetEvent_params params;
-    NTSTATUS status;
     params.device = device;
     params.event = event;
-    status = UNIX_CALL(vkResetEvent, &params);
-    assert(!status && "vkResetEvent");
+    UNIX_CALL_CHECKED(vkResetEvent, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences)
 {
     struct vkResetFences_params params;
-    NTSTATUS status;
     params.device = device;
     params.fenceCount = fenceCount;
     params.pFences = pFences;
-    status = UNIX_CALL(vkResetFences, &params);
-    assert(!status && "vkResetFences");
+    UNIX_CALL_CHECKED(vkResetFences, &params);
     return params.result;
 }
 
 VkResult WINAPI vkResetGpaSessionAMD(VkDevice device, VkGpaSessionAMD gpaSession)
 {
     struct vkResetGpaSessionAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.gpaSession = gpaSession;
-    status = UNIX_CALL(vkResetGpaSessionAMD, &params);
-    assert(!status && "vkResetGpaSessionAMD");
+    UNIX_CALL_CHECKED(vkResetGpaSessionAMD, &params);
     return params.result;
 }
 
 void WINAPI vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount)
 {
     struct vkResetQueryPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.queryPool = queryPool;
     params.firstQuery = firstQuery;
     params.queryCount = queryCount;
-    status = UNIX_CALL(vkResetQueryPool, &params);
-    assert(!status && "vkResetQueryPool");
+    UNIX_CALL_CHECKED(vkResetQueryPool, &params);
 }
 
 void WINAPI vkResetQueryPoolEXT(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount)
 {
     struct vkResetQueryPoolEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.queryPool = queryPool;
     params.firstQuery = firstQuery;
     params.queryCount = queryCount;
-    status = UNIX_CALL(vkResetQueryPoolEXT, &params);
-    assert(!status && "vkResetQueryPoolEXT");
+    UNIX_CALL_CHECKED(vkResetQueryPoolEXT, &params);
 }
 
 VkResult WINAPI vkSetDebugUtilsObjectNameEXT(VkDevice device, const VkDebugUtilsObjectNameInfoEXT *pNameInfo)
 {
     struct vkSetDebugUtilsObjectNameEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pNameInfo = pNameInfo;
-    status = UNIX_CALL(vkSetDebugUtilsObjectNameEXT, &params);
-    assert(!status && "vkSetDebugUtilsObjectNameEXT");
+    UNIX_CALL_CHECKED(vkSetDebugUtilsObjectNameEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSetDebugUtilsObjectTagEXT(VkDevice device, const VkDebugUtilsObjectTagInfoEXT *pTagInfo)
 {
     struct vkSetDebugUtilsObjectTagEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.pTagInfo = pTagInfo;
-    status = UNIX_CALL(vkSetDebugUtilsObjectTagEXT, &params);
-    assert(!status && "vkSetDebugUtilsObjectTagEXT");
+    UNIX_CALL_CHECKED(vkSetDebugUtilsObjectTagEXT, &params);
     return params.result;
 }
 
 void WINAPI vkSetDeviceMemoryPriorityEXT(VkDevice device, VkDeviceMemory memory, float priority)
 {
     struct vkSetDeviceMemoryPriorityEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.memory = memory;
     params.priority = priority;
-    status = UNIX_CALL(vkSetDeviceMemoryPriorityEXT, &params);
-    assert(!status && "vkSetDeviceMemoryPriorityEXT");
+    UNIX_CALL_CHECKED(vkSetDeviceMemoryPriorityEXT, &params);
 }
 
 VkResult WINAPI vkSetEvent(VkDevice device, VkEvent event)
 {
     struct vkSetEvent_params params;
-    NTSTATUS status;
     params.device = device;
     params.event = event;
-    status = UNIX_CALL(vkSetEvent, &params);
-    assert(!status && "vkSetEvent");
+    UNIX_CALL_CHECKED(vkSetEvent, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSetGpaDeviceClockModeAMD(VkDevice device, VkGpaDeviceClockModeInfoAMD *pInfo)
 {
     struct vkSetGpaDeviceClockModeAMD_params params;
-    NTSTATUS status;
     params.device = device;
     params.pInfo = pInfo;
-    status = UNIX_CALL(vkSetGpaDeviceClockModeAMD, &params);
-    assert(!status && "vkSetGpaDeviceClockModeAMD");
+    UNIX_CALL_CHECKED(vkSetGpaDeviceClockModeAMD, &params);
     return params.result;
 }
 
 void WINAPI vkSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR *pSwapchains, const VkHdrMetadataEXT *pMetadata)
 {
     struct vkSetHdrMetadataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchainCount = swapchainCount;
     params.pSwapchains = pSwapchains;
     params.pMetadata = pMetadata;
-    status = UNIX_CALL(vkSetHdrMetadataEXT, &params);
-    assert(!status && "vkSetHdrMetadataEXT");
+    UNIX_CALL_CHECKED(vkSetHdrMetadataEXT, &params);
 }
 
 void WINAPI vkSetLatencyMarkerNV(VkDevice device, VkSwapchainKHR swapchain, const VkSetLatencyMarkerInfoNV *pLatencyMarkerInfo)
 {
     struct vkSetLatencyMarkerNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pLatencyMarkerInfo = pLatencyMarkerInfo;
-    status = UNIX_CALL(vkSetLatencyMarkerNV, &params);
-    assert(!status && "vkSetLatencyMarkerNV");
+    UNIX_CALL_CHECKED(vkSetLatencyMarkerNV, &params);
 }
 
 VkResult WINAPI vkSetLatencySleepModeNV(VkDevice device, VkSwapchainKHR swapchain, const VkLatencySleepModeInfoNV *pSleepModeInfo)
 {
     struct vkSetLatencySleepModeNV_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pSleepModeInfo = pSleepModeInfo;
-    status = UNIX_CALL(vkSetLatencySleepModeNV, &params);
-    assert(!status && "vkSetLatencySleepModeNV");
+    UNIX_CALL_CHECKED(vkSetLatencySleepModeNV, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSetPrivateData(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data)
 {
     struct vkSetPrivateData_params params;
-    NTSTATUS status;
     params.device = device;
     params.objectType = objectType;
     params.objectHandle = objectHandle;
     params.privateDataSlot = privateDataSlot;
     params.data = data;
-    status = UNIX_CALL(vkSetPrivateData, &params);
-    assert(!status && "vkSetPrivateData");
+    UNIX_CALL_CHECKED(vkSetPrivateData, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSetPrivateDataEXT(VkDevice device, VkObjectType objectType, uint64_t objectHandle, VkPrivateDataSlot privateDataSlot, uint64_t data)
 {
     struct vkSetPrivateDataEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.objectType = objectType;
     params.objectHandle = objectHandle;
     params.privateDataSlot = privateDataSlot;
     params.data = data;
-    status = UNIX_CALL(vkSetPrivateDataEXT, &params);
-    assert(!status && "vkSetPrivateDataEXT");
+    UNIX_CALL_CHECKED(vkSetPrivateDataEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSetSwapchainPresentTimingQueueSizeEXT(VkDevice device, VkSwapchainKHR swapchain, uint32_t size)
 {
     struct vkSetSwapchainPresentTimingQueueSizeEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.size = size;
-    status = UNIX_CALL(vkSetSwapchainPresentTimingQueueSizeEXT, &params);
-    assert(!status && "vkSetSwapchainPresentTimingQueueSizeEXT");
+    UNIX_CALL_CHECKED(vkSetSwapchainPresentTimingQueueSizeEXT, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
 {
     struct vkSignalSemaphore_params params;
-    NTSTATUS status;
     params.device = device;
     params.pSignalInfo = pSignalInfo;
-    status = UNIX_CALL(vkSignalSemaphore, &params);
-    assert(!status && "vkSignalSemaphore");
+    UNIX_CALL_CHECKED(vkSignalSemaphore, &params);
     return params.result;
 }
 
 VkResult WINAPI vkSignalSemaphoreKHR(VkDevice device, const VkSemaphoreSignalInfo *pSignalInfo)
 {
     struct vkSignalSemaphoreKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pSignalInfo = pSignalInfo;
-    status = UNIX_CALL(vkSignalSemaphoreKHR, &params);
-    assert(!status && "vkSignalSemaphoreKHR");
+    UNIX_CALL_CHECKED(vkSignalSemaphoreKHR, &params);
     return params.result;
 }
 
 void WINAPI vkSubmitDebugUtilsMessageEXT(VkInstance instance, VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkDebugUtilsMessageTypeFlagsEXT messageTypes, const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData)
 {
     struct vkSubmitDebugUtilsMessageEXT_params params;
-    NTSTATUS status;
     params.instance = instance;
     params.messageSeverity = messageSeverity;
     params.messageTypes = messageTypes;
     params.pCallbackData = pCallbackData;
-    status = UNIX_CALL(vkSubmitDebugUtilsMessageEXT, &params);
-    assert(!status && "vkSubmitDebugUtilsMessageEXT");
+    UNIX_CALL_CHECKED(vkSubmitDebugUtilsMessageEXT, &params);
 }
 
 VkResult WINAPI vkTransitionImageLayout(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo *pTransitions)
 {
     struct vkTransitionImageLayout_params params;
-    NTSTATUS status;
     params.device = device;
     params.transitionCount = transitionCount;
     params.pTransitions = pTransitions;
-    status = UNIX_CALL(vkTransitionImageLayout, &params);
-    assert(!status && "vkTransitionImageLayout");
+    UNIX_CALL_CHECKED(vkTransitionImageLayout, &params);
     return params.result;
 }
 
 VkResult WINAPI vkTransitionImageLayoutEXT(VkDevice device, uint32_t transitionCount, const VkHostImageLayoutTransitionInfo *pTransitions)
 {
     struct vkTransitionImageLayoutEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.transitionCount = transitionCount;
     params.pTransitions = pTransitions;
-    status = UNIX_CALL(vkTransitionImageLayoutEXT, &params);
-    assert(!status && "vkTransitionImageLayoutEXT");
+    UNIX_CALL_CHECKED(vkTransitionImageLayoutEXT, &params);
     return params.result;
 }
 
 void WINAPI vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags)
 {
     struct vkTrimCommandPool_params params;
-    NTSTATUS status;
     params.device = device;
     params.commandPool = commandPool;
     params.flags = flags;
-    status = UNIX_CALL(vkTrimCommandPool, &params);
-    assert(!status && "vkTrimCommandPool");
+    UNIX_CALL_CHECKED(vkTrimCommandPool, &params);
 }
 
 void WINAPI vkTrimCommandPoolKHR(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags)
 {
     struct vkTrimCommandPoolKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.commandPool = commandPool;
     params.flags = flags;
-    status = UNIX_CALL(vkTrimCommandPoolKHR, &params);
-    assert(!status && "vkTrimCommandPoolKHR");
+    UNIX_CALL_CHECKED(vkTrimCommandPoolKHR, &params);
 }
 
 void WINAPI vkUninitializePerformanceApiINTEL(VkDevice device)
 {
     struct vkUninitializePerformanceApiINTEL_params params;
-    NTSTATUS status;
     params.device = device;
-    status = UNIX_CALL(vkUninitializePerformanceApiINTEL, &params);
-    assert(!status && "vkUninitializePerformanceApiINTEL");
+    UNIX_CALL_CHECKED(vkUninitializePerformanceApiINTEL, &params);
 }
 
 void WINAPI vkUnmapMemory(VkDevice device, VkDeviceMemory memory)
 {
     struct vkUnmapMemory_params params;
-    NTSTATUS status;
     params.device = device;
     params.memory = memory;
-    status = UNIX_CALL(vkUnmapMemory, &params);
-    assert(!status && "vkUnmapMemory");
+    UNIX_CALL_CHECKED(vkUnmapMemory, &params);
 }
 
 VkResult WINAPI vkUnmapMemory2(VkDevice device, const VkMemoryUnmapInfo *pMemoryUnmapInfo)
 {
     struct vkUnmapMemory2_params params;
-    NTSTATUS status;
     params.device = device;
     params.pMemoryUnmapInfo = pMemoryUnmapInfo;
-    status = UNIX_CALL(vkUnmapMemory2, &params);
-    assert(!status && "vkUnmapMemory2");
+    UNIX_CALL_CHECKED(vkUnmapMemory2, &params);
     return params.result;
 }
 
 VkResult WINAPI vkUnmapMemory2KHR(VkDevice device, const VkMemoryUnmapInfo *pMemoryUnmapInfo)
 {
     struct vkUnmapMemory2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pMemoryUnmapInfo = pMemoryUnmapInfo;
-    status = UNIX_CALL(vkUnmapMemory2KHR, &params);
-    assert(!status && "vkUnmapMemory2KHR");
+    UNIX_CALL_CHECKED(vkUnmapMemory2KHR, &params);
     return params.result;
 }
 
 void WINAPI vkUnregisterCustomBorderColorEXT(VkDevice device, uint32_t index)
 {
     struct vkUnregisterCustomBorderColorEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.index = index;
-    status = UNIX_CALL(vkUnregisterCustomBorderColorEXT, &params);
-    assert(!status && "vkUnregisterCustomBorderColorEXT");
+    UNIX_CALL_CHECKED(vkUnregisterCustomBorderColorEXT, &params);
 }
 
 void WINAPI vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData)
@@ -7693,13 +6887,11 @@ void WINAPI vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet d
 void WINAPI vkUpdateDescriptorSetWithTemplateKHR(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void *pData)
 {
     struct vkUpdateDescriptorSetWithTemplateKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.descriptorSet = descriptorSet;
     params.descriptorUpdateTemplate = descriptorUpdateTemplate;
     params.pData = pData;
-    status = UNIX_CALL(vkUpdateDescriptorSetWithTemplateKHR, &params);
-    assert(!status && "vkUpdateDescriptorSetWithTemplateKHR");
+    UNIX_CALL_CHECKED(vkUpdateDescriptorSetWithTemplateKHR, &params);
 }
 
 void WINAPI vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCount, const VkWriteDescriptorSet *pDescriptorWrites, uint32_t descriptorCopyCount, const VkCopyDescriptorSet *pDescriptorCopies)
@@ -7716,106 +6908,89 @@ void WINAPI vkUpdateDescriptorSets(VkDevice device, uint32_t descriptorWriteCoun
 void WINAPI vkUpdateIndirectExecutionSetPipelineEXT(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetPipelineEXT *pExecutionSetWrites)
 {
     struct vkUpdateIndirectExecutionSetPipelineEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.indirectExecutionSet = indirectExecutionSet;
     params.executionSetWriteCount = executionSetWriteCount;
     params.pExecutionSetWrites = pExecutionSetWrites;
-    status = UNIX_CALL(vkUpdateIndirectExecutionSetPipelineEXT, &params);
-    assert(!status && "vkUpdateIndirectExecutionSetPipelineEXT");
+    UNIX_CALL_CHECKED(vkUpdateIndirectExecutionSetPipelineEXT, &params);
 }
 
 void WINAPI vkUpdateIndirectExecutionSetShaderEXT(VkDevice device, VkIndirectExecutionSetEXT indirectExecutionSet, uint32_t executionSetWriteCount, const VkWriteIndirectExecutionSetShaderEXT *pExecutionSetWrites)
 {
     struct vkUpdateIndirectExecutionSetShaderEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.indirectExecutionSet = indirectExecutionSet;
     params.executionSetWriteCount = executionSetWriteCount;
     params.pExecutionSetWrites = pExecutionSetWrites;
-    status = UNIX_CALL(vkUpdateIndirectExecutionSetShaderEXT, &params);
-    assert(!status && "vkUpdateIndirectExecutionSetShaderEXT");
+    UNIX_CALL_CHECKED(vkUpdateIndirectExecutionSetShaderEXT, &params);
 }
 
 VkResult WINAPI vkUpdateVideoSessionParametersKHR(VkDevice device, VkVideoSessionParametersKHR videoSessionParameters, const VkVideoSessionParametersUpdateInfoKHR *pUpdateInfo)
 {
     struct vkUpdateVideoSessionParametersKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.videoSessionParameters = videoSessionParameters;
     params.pUpdateInfo = pUpdateInfo;
-    status = UNIX_CALL(vkUpdateVideoSessionParametersKHR, &params);
-    assert(!status && "vkUpdateVideoSessionParametersKHR");
+    UNIX_CALL_CHECKED(vkUpdateVideoSessionParametersKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWaitForFences(VkDevice device, uint32_t fenceCount, const VkFence *pFences, VkBool32 waitAll, uint64_t timeout)
 {
     struct vkWaitForFences_params params;
-    NTSTATUS status;
     params.device = device;
     params.fenceCount = fenceCount;
     params.pFences = pFences;
     params.waitAll = waitAll;
     params.timeout = timeout;
-    status = UNIX_CALL(vkWaitForFences, &params);
-    assert(!status && "vkWaitForFences");
+    UNIX_CALL_CHECKED(vkWaitForFences, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWaitForPresent2KHR(VkDevice device, VkSwapchainKHR swapchain, const VkPresentWait2InfoKHR *pPresentWait2Info)
 {
     struct vkWaitForPresent2KHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.pPresentWait2Info = pPresentWait2Info;
-    status = UNIX_CALL(vkWaitForPresent2KHR, &params);
-    assert(!status && "vkWaitForPresent2KHR");
+    UNIX_CALL_CHECKED(vkWaitForPresent2KHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWaitForPresentKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t presentId, uint64_t timeout)
 {
     struct vkWaitForPresentKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.swapchain = swapchain;
     params.presentId = presentId;
     params.timeout = timeout;
-    status = UNIX_CALL(vkWaitForPresentKHR, &params);
-    assert(!status && "vkWaitForPresentKHR");
+    UNIX_CALL_CHECKED(vkWaitForPresentKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout)
 {
     struct vkWaitSemaphores_params params;
-    NTSTATUS status;
     params.device = device;
     params.pWaitInfo = pWaitInfo;
     params.timeout = timeout;
-    status = UNIX_CALL(vkWaitSemaphores, &params);
-    assert(!status && "vkWaitSemaphores");
+    UNIX_CALL_CHECKED(vkWaitSemaphores, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWaitSemaphoresKHR(VkDevice device, const VkSemaphoreWaitInfo *pWaitInfo, uint64_t timeout)
 {
     struct vkWaitSemaphoresKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.pWaitInfo = pWaitInfo;
     params.timeout = timeout;
-    status = UNIX_CALL(vkWaitSemaphoresKHR, &params);
-    assert(!status && "vkWaitSemaphoresKHR");
+    UNIX_CALL_CHECKED(vkWaitSemaphoresKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint32_t accelerationStructureCount, const VkAccelerationStructureKHR *pAccelerationStructures, VkQueryType queryType, size_t dataSize, void *pData, size_t stride)
 {
     struct vkWriteAccelerationStructuresPropertiesKHR_params params;
-    NTSTATUS status;
     params.device = device;
     params.accelerationStructureCount = accelerationStructureCount;
     params.pAccelerationStructures = pAccelerationStructures;
@@ -7823,15 +6998,13 @@ VkResult WINAPI vkWriteAccelerationStructuresPropertiesKHR(VkDevice device, uint
     params.dataSize = dataSize;
     params.pData = pData;
     params.stride = stride;
-    status = UNIX_CALL(vkWriteAccelerationStructuresPropertiesKHR, &params);
-    assert(!status && "vkWriteAccelerationStructuresPropertiesKHR");
+    UNIX_CALL_CHECKED(vkWriteAccelerationStructuresPropertiesKHR, &params);
     return params.result;
 }
 
 VkResult WINAPI vkWriteMicromapsPropertiesEXT(VkDevice device, uint32_t micromapCount, const VkMicromapEXT *pMicromaps, VkQueryType queryType, size_t dataSize, void *pData, size_t stride)
 {
     struct vkWriteMicromapsPropertiesEXT_params params;
-    NTSTATUS status;
     params.device = device;
     params.micromapCount = micromapCount;
     params.pMicromaps = pMicromaps;
@@ -7839,8 +7012,7 @@ VkResult WINAPI vkWriteMicromapsPropertiesEXT(VkDevice device, uint32_t micromap
     params.dataSize = dataSize;
     params.pData = pData;
     params.stride = stride;
-    status = UNIX_CALL(vkWriteMicromapsPropertiesEXT, &params);
-    assert(!status && "vkWriteMicromapsPropertiesEXT");
+    UNIX_CALL_CHECKED(vkWriteMicromapsPropertiesEXT, &params);
     return params.result;
 }
 
diff --git a/dlls/winevulkan/make_vulkan b/dlls/winevulkan/make_vulkan
index 70273a192235..71994e45788c 100755
--- a/dlls/winevulkan/make_vulkan
+++ b/dlls/winevulkan/make_vulkan
@@ -884,8 +884,6 @@ class Function(Type):
         thunk += u"{\n"
         thunk += f"    struct {self.name}_params params;\n"
 
-        if not self.is_perf_critical():
-            thunk += u"    NTSTATUS status;\n"
         for p in self.params:
             thunk += f"    params.{p.name} = {p.name};\n"
 
@@ -893,8 +891,7 @@ class Function(Type):
         if self.is_perf_critical():
             thunk += f"    UNIX_CALL({self.name}, &params);\n"
         else:
-            thunk += f"    status = UNIX_CALL({self.name}, &params);\n"
-            thunk += f"    assert(!status && \"{self.name}\");\n"
+            thunk += f"    UNIX_CALL_CHECKED({self.name}, &params);\n"
 
         if self.type != "void":
             thunk += u"    return params.result;\n"
diff --git a/dlls/winevulkan/vulkan.c b/dlls/winevulkan/vulkan.c
index 11bb4a7f6227..2dac08a3a890 100644
--- a/dlls/winevulkan/vulkan.c
+++ b/dlls/winevulkan/vulkan.c
@@ -32,7 +32,6 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
-static PFN_vkCreateInstance p_vkCreateInstance;
 static PFN_vkEnumerateInstanceVersion p_vkEnumerateInstanceVersion;
 static PFN_vkEnumerateInstanceExtensionProperties p_vkEnumerateInstanceExtensionProperties;
 
@@ -262,7 +261,6 @@ NTSTATUS init_vulkan(void *arg)
     call_vulkan_debug_report_callback = params->call_vulkan_debug_report_callback;
     call_vulkan_debug_utils_callback = params->call_vulkan_debug_utils_callback;
 
-    p_vkCreateInstance = (PFN_vkCreateInstance)vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkCreateInstance");
     p_vkEnumerateInstanceVersion = (PFN_vkEnumerateInstanceVersion)vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceVersion");
     p_vkEnumerateInstanceExtensionProperties = (PFN_vkEnumerateInstanceExtensionProperties)vk_funcs->p_vkGetInstanceProcAddr(NULL, "vkEnumerateInstanceExtensionProperties");
 
diff --git a/dlls/winevulkan/vulkan_loader.h b/dlls/winevulkan/vulkan_loader.h
index 9066e0329ef0..9b0580673e7d 100644
--- a/dlls/winevulkan/vulkan_loader.h
+++ b/dlls/winevulkan/vulkan_loader.h
@@ -23,7 +23,6 @@
 #include "ntstatus.h"
 #include <stdarg.h>
 #include <stdlib.h>
-#include <assert.h>
 #include "windef.h"
 #include "winbase.h"
 #include "winternl.h"
@@ -145,5 +144,14 @@ struct is_available_device_function_params
 };
 
 #define UNIX_CALL(code, params) WINE_UNIX_CALL(unix_ ## code, params)
+#define UNIX_CALL_CHECKED(code, params)                           \
+    do {                                                          \
+        NTSTATUS status = UNIX_CALL(code, params);                \
+        if (status)                                               \
+        {                                                         \
+            ERR("Exception %#lx in Unix call.\n", status);        \
+            ExitProcess(3);                                       \
+        }                                                         \
+    } while (0)
 
 #endif /* __WINE_VULKAN_LOADER_H */
diff --git a/dlls/winewayland.drv/Makefile.in b/dlls/winewayland.drv/Makefile.in
index ef38cf272c90..00dd00559712 100644
--- a/dlls/winewayland.drv/Makefile.in
+++ b/dlls/winewayland.drv/Makefile.in
@@ -11,6 +11,7 @@ SOURCES = \
 	cursor-shape-v1.xml \
 	display.c \
 	dllmain.c \
+	fractional-scale-v1.xml \
 	opengl.c \
 	pointer-constraints-unstable-v1.xml \
 	pointer-warp-v1.xml \
diff --git a/dlls/winewayland.drv/display.c b/dlls/winewayland.drv/display.c
index b0b3d116147e..1d46d64df6f3 100644
--- a/dlls/winewayland.drv/display.c
+++ b/dlls/winewayland.drv/display.c
@@ -205,13 +205,15 @@ static void wayland_add_device_source(const struct gdi_device_manager *device_ma
 }
 
 static void wayland_add_device_monitor(const struct gdi_device_manager *device_manager,
-                                       void *param, struct output_info *output_info)
+                                       void *param, struct output_info *output_info,
+                                       struct output_info *primary)
 {
     struct gdi_monitor monitor = {0};
 
     SetRect(&monitor.rc_monitor, output_info->x, output_info->y,
             output_info->x + output_info->output->current_mode->width,
             output_info->y + output_info->output->current_mode->height);
+    OffsetRect(&monitor.rc_monitor, -primary->x, -primary->y);
 
     /* We don't have a direct way to get the work area in Wayland. */
     monitor.rc_work = monitor.rc_monitor;
@@ -236,7 +238,8 @@ static void populate_devmode(struct wayland_output_mode *output_mode, DEVMODEW *
 }
 
 static void wayland_add_device_modes(const struct gdi_device_manager *device_manager,
-                                     void *param, struct output_info *output_info)
+                                     void *param, struct output_info *output_info,
+                                     struct output_info *primary)
 {
     DEVMODEW *modes, current = {.dmSize = sizeof(current)};
     struct wayland_output_mode *output_mode;
@@ -247,8 +250,8 @@ static void wayland_add_device_modes(const struct gdi_device_manager *device_man
 
     populate_devmode(output_info->output->current_mode, &current);
     current.dmFields |= DM_POSITION;
-    current.dmPosition.x = output_info->x;
-    current.dmPosition.y = output_info->y;
+    current.dmPosition.x = output_info->x - primary->x;
+    current.dmPosition.y = output_info->y - primary->y;
 
     RB_FOR_EACH_ENTRY(output_mode, &output_info->output->modes,
                       struct wayland_output_mode, entry)
@@ -269,8 +272,8 @@ UINT WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
 {
     struct wayland_output *output;
     DWORD state_flags = DISPLAY_DEVICE_ATTACHED_TO_DESKTOP | DISPLAY_DEVICE_PRIMARY_DEVICE;
+    struct output_info *primary = NULL, *output_info;
     struct wl_array output_info_array;
-    struct output_info *output_info;
 
     TRACE("\n");
 
@@ -293,9 +296,10 @@ UINT WAYLAND_UpdateDisplayDevices(const struct gdi_device_manager *device_manage
 
     wl_array_for_each(output_info, &output_info_array)
     {
+        if (!primary) primary = output_info;
         wayland_add_device_source(device_manager, param, state_flags, output_info);
-        wayland_add_device_monitor(device_manager, param, output_info);
-        wayland_add_device_modes(device_manager, param, output_info);
+        wayland_add_device_monitor(device_manager, param, output_info, primary);
+        wayland_add_device_modes(device_manager, param, output_info, primary);
         state_flags &= ~DISPLAY_DEVICE_PRIMARY_DEVICE;
     }
 
diff --git a/dlls/winewayland.drv/fractional-scale-v1.xml b/dlls/winewayland.drv/fractional-scale-v1.xml
new file mode 100644
index 000000000000..350bfc01eafa
--- /dev/null
+++ b/dlls/winewayland.drv/fractional-scale-v1.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fractional_scale_v1">
+  <copyright>
+    Copyright © 2022 Kenny Levinsen
+
+    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 (including the next
+    paragraph) 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.
+  </copyright>
+
+  <description summary="Protocol for requesting fractional surface scales">
+    This protocol allows a compositor to suggest for surfaces to render at
+    fractional scales.
+
+    A client can submit scaled content by utilizing wp_viewport. This is done by
+    creating a wp_viewport object for the surface and setting the destination
+    rectangle to the surface size before the scale factor is applied.
+
+    The buffer size is calculated by multiplying the surface size by the
+    intended scale.
+
+    The wl_surface buffer scale should remain set to 1.
+
+    If a surface has a surface-local size of 100 px by 50 px and wishes to
+    submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should
+    be used and the wp_viewport destination rectangle should be 100 px by 50 px.
+
+    For toplevel surfaces, the size is rounded halfway away from zero. The
+    rounding algorithm for subsurface position and size is not defined.
+  </description>
+
+  <interface name="wp_fractional_scale_manager_v1" version="1">
+    <description summary="fractional surface scale information">
+      A global interface for requesting surfaces to use fractional scales.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind the fractional surface scale interface">
+        Informs the server that the client will not be using this protocol
+        object anymore. This does not affect any other objects,
+        wp_fractional_scale_v1 objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="fractional_scale_exists" value="0"
+        summary="the surface already has a fractional_scale object associated"/>
+    </enum>
+
+    <request name="get_fractional_scale">
+      <description summary="extend surface interface for scale information">
+        Create an add-on object for the the wl_surface to let the compositor
+        request fractional scales. If the given wl_surface already has a
+        wp_fractional_scale_v1 object associated, the fractional_scale_exists
+        protocol error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_fractional_scale_v1"
+           summary="the new surface scale info interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_fractional_scale_v1" version="1">
+    <description summary="fractional scale interface to a wl_surface">
+      An additional interface to a wl_surface object which allows the compositor
+      to inform the client of the preferred scale.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove surface scale information for surface">
+        Destroy the fractional scale object. When this object is destroyed,
+        preferred_scale events will no longer be sent.
+      </description>
+    </request>
+
+    <event name="preferred_scale">
+      <description summary="notify of new preferred scale">
+        Notification of a new preferred scale for this surface that the
+        compositor suggests that the client should use.
+
+        The sent scale is the numerator of a fraction with a denominator of 120.
+      </description>
+      <arg name="scale" type="uint" summary="the new preferred scale"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/dlls/winewayland.drv/opengl.c b/dlls/winewayland.drv/opengl.c
index 66457e1aea5d..14cb4ce5a258 100644
--- a/dlls/winewayland.drv/opengl.c
+++ b/dlls/winewayland.drv/opengl.c
@@ -80,18 +80,16 @@ static void wayland_gl_drawable_sync_size(struct wayland_gl_drawable *gl)
     wl_egl_window_resize(gl->wl_egl_window, client_width, client_height, 0, 0);
 }
 
-static BOOL wayland_opengl_surface_create(HWND hwnd, int format, struct opengl_drawable **drawable)
+static BOOL wayland_opengl_surface_create(struct client_surface *client, int format, struct opengl_drawable **drawable)
 {
+    struct wayland_client_surface *surface = impl_from_client_surface(client);
     EGLConfig config = egl_config_for_format(format);
-    struct wayland_client_surface *client;
     EGLint attribs[4], *attrib = attribs;
-    struct opengl_drawable *previous;
     struct wayland_gl_drawable *gl;
+    HWND hwnd = client->hwnd;
     RECT rect;
 
-    TRACE("hwnd=%p format=%d\n", hwnd, format);
-
-    if ((previous = *drawable) && previous->format == format) return TRUE;
+    TRACE("client=%s format=%d\n", debugstr_client_surface(client), format);
 
     NtUserGetClientRect(hwnd, &rect, NtUserGetDpiForWindow(hwnd));
     if (rect.right == rect.left) rect.right = rect.left + 1;
@@ -106,23 +104,19 @@ static BOOL wayland_opengl_surface_create(HWND hwnd, int format, struct opengl_d
     }
     *attrib++ = EGL_NONE;
 
-    if (!(client = wayland_client_surface_create(hwnd))) return FALSE;
-    gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, &client->client);
-    client_surface_release(&client->client);
-    if (!gl) return FALSE;
+    if (!(gl = opengl_drawable_create(sizeof(*gl), &wayland_drawable_funcs, format, client))) return FALSE;
 
     opengl_drawable_map_buffer(&gl->base, GL_FRONT_LEFT, GL_BACK_LEFT);
     opengl_drawable_map_buffer(&gl->base, GL_FRONT, GL_BACK);
     opengl_drawable_map_buffer(&gl->base, GL_FRONT_AND_BACK, GL_BACK);
     if (gl->base.stereo) opengl_drawable_map_buffer(&gl->base, GL_FRONT_RIGHT, GL_BACK_RIGHT);
 
-    if (!(gl->wl_egl_window = wl_egl_window_create(client->wl_surface, rect.right, rect.bottom))) goto err;
+    if (!(gl->wl_egl_window = wl_egl_window_create(surface->wl_surface, rect.right, rect.bottom))) goto err;
     if (!(gl->base.surface = funcs->p_eglCreateWindowSurface(egl->display, config, gl->wl_egl_window, attribs))) goto err;
-    set_client_surface(hwnd, client);
+    set_client_surface(hwnd, surface);
 
     TRACE("Created drawable %s with egl_surface %p\n", debugstr_opengl_drawable(&gl->base), gl->base.surface);
 
-    if (previous) opengl_drawable_release( previous );
     *drawable = &gl->base;
     return TRUE;
 
diff --git a/dlls/winewayland.drv/vulkan.c b/dlls/winewayland.drv/vulkan.c
index b2e91102f587..b2c435cb7a42 100644
--- a/dlls/winewayland.drv/vulkan.c
+++ b/dlls/winewayland.drv/vulkan.c
@@ -38,34 +38,24 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
 static const struct vulkan_driver_funcs wayland_vulkan_driver_funcs;
 
-static VkResult wayland_vulkan_surface_create(HWND hwnd, const struct vulkan_instance *instance, VkSurfaceKHR *handle,
-                                              struct client_surface **client)
+static VkResult wayland_vulkan_surface_create(struct client_surface *client, const struct vulkan_instance *instance, VkSurfaceKHR *handle)
 {
     VkResult res;
     VkWaylandSurfaceCreateInfoKHR create_info_host;
-    struct wayland_client_surface *surface;
+    struct wayland_client_surface *surface = impl_from_client_surface(client);
+    HWND hwnd = client->hwnd;
 
-    TRACE("%p %p %p %p\n", hwnd, instance, handle, client);
+    TRACE("%s %p %p\n", debugstr_client_surface(client), instance, handle);
 
-    if (!(surface = wayland_client_surface_create(hwnd))) return VK_ERROR_OUT_OF_HOST_MEMORY;
     create_info_host.sType = VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR;
     create_info_host.pNext = NULL;
     create_info_host.flags = 0; /* reserved */
     create_info_host.display = process_wayland.wl_display;
     create_info_host.surface = surface->wl_surface;
-
-    res = instance->p_vkCreateWaylandSurfaceKHR(instance->host.instance, &create_info_host, NULL /* allocator */, handle);
-    if (res != VK_SUCCESS)
-    {
-        ERR("Failed to create vulkan wayland surface, res=%d\n", res);
-        client_surface_release(&surface->client);
-        return res;
-    }
-
+    if ((res = instance->p_vkCreateWaylandSurfaceKHR(instance->host.instance, &create_info_host, NULL /* allocator */, handle))) return res;
     set_client_surface(hwnd, surface);
-    *client = &surface->client;
 
-    TRACE("Created surface=0x%s, client=%p\n", wine_dbgstr_longlong(*handle), *client);
+    TRACE("Created surface=0x%s\n", wine_dbgstr_longlong(*handle));
     return VK_SUCCESS;
 }
 
diff --git a/dlls/winewayland.drv/wayland.c b/dlls/winewayland.drv/wayland.c
index ba098685c465..5b2b0c5b25bc 100644
--- a/dlls/winewayland.drv/wayland.c
+++ b/dlls/winewayland.drv/wayland.c
@@ -210,6 +210,11 @@ static void registry_handle_global(void *data, struct wl_registry *registry,
         process_wayland.wp_alpha_modifier_v1 =
             wl_registry_bind(registry, id, &wp_alpha_modifier_v1_interface, 1);
     }
+    else if (strcmp(interface, "wp_fractional_scale_manager_v1") == 0)
+    {
+        process_wayland.wp_fractional_scale_manager_v1 =
+            wl_registry_bind(registry, id, &wp_fractional_scale_manager_v1_interface, 1);
+    }
 }
 
 static void registry_handle_global_remove(void *data, struct wl_registry *registry,
@@ -265,7 +270,12 @@ BOOL wayland_process_init(void)
 
     TRACE("wl_display=%p\n", process_wayland.wl_display);
 
+#if (WAYLAND_VERSION_MAJOR == 1 && WAYLAND_VERSION_MINOR >= 23)
+    if (!(process_wayland.wl_event_queue =
+          wl_display_create_queue_with_name(process_wayland.wl_display, process_name ? process_name : "winewayland")))
+#else
     if (!(process_wayland.wl_event_queue = wl_display_create_queue(process_wayland.wl_display)))
+#endif
     {
         ERR("Failed to create event queue\n");
         return FALSE;
@@ -343,6 +353,9 @@ BOOL wayland_process_init(void)
     if (!process_wayland.xdg_toplevel_icon_manager_v1)
         ERR("Wayland compositor doesn't support xdg_toplevel_icon_manager_v1 (window icons will not be supported)\n");
 
+    if (!process_wayland.wp_fractional_scale_manager_v1)
+        ERR("Wayland compositor doesn't support wp_fractional_scale_manager_v1 (fractional scaling will be broken)\n");
+
     process_wayland.initialized = TRUE;
 
     return TRUE;
diff --git a/dlls/winewayland.drv/wayland_pointer.c b/dlls/winewayland.drv/wayland_pointer.c
index 109dd2dd0ebe..af404994a440 100644
--- a/dlls/winewayland.drv/wayland_pointer.c
+++ b/dlls/winewayland.drv/wayland_pointer.c
@@ -34,7 +34,7 @@
 #include "waylanddrv.h"
 #include "wine/debug.h"
 
-WINE_DEFAULT_DEBUG_CHANNEL(waylanddrv);
+WINE_DEFAULT_DEBUG_CHANNEL(cursor);
 
 /* The cursor-shape-v1 protocol file references the zwp_tablet_tool_v2
  * interface object. Since we don't currently use the tablet protocol,
@@ -126,7 +126,7 @@ static void pointer_handle_motion_internal(wl_fixed_t sx, wl_fixed_t sy)
     INPUT input = {0};
     RECT *window_rect;
     HWND hwnd;
-    POINT screen;
+    POINT screen = { wl_fixed_to_double(sx), wl_fixed_to_double(sy) };
     struct wayland_surface *surface;
     struct wayland_win_data *data;
 
@@ -140,10 +140,7 @@ static void pointer_handle_motion_internal(wl_fixed_t sx, wl_fixed_t sy)
 
     window_rect = &surface->window.rect;
 
-    wayland_surface_coords_to_window(surface,
-                                     wl_fixed_to_double(sx),
-                                     wl_fixed_to_double(sy),
-                                     (int *)&screen.x, (int *)&screen.y);
+    screen = map_point_from_surface(surface, screen);
     screen.x += window_rect->left;
     screen.y += window_rect->top;
     /* Sometimes, due to rounding, we may end up with pointer coordinates
@@ -832,15 +829,8 @@ static void wayland_surface_calc_confine(struct wayland_surface *surface,
         return;
     }
 
-    OffsetRect(&window_clip,
-               -surface->window.rect.left,
-               -surface->window.rect.top);
-    wayland_surface_coords_from_window(surface,
-                                       window_clip.left, window_clip.top,
-                                       (int *)&confine->left, (int *)&confine->top);
-    wayland_surface_coords_from_window(surface,
-                                       window_clip.right, window_clip.bottom,
-                                       (int *)&confine->right, (int *)&confine->bottom);
+    OffsetRect(&window_clip, -surface->window.rect.left, -surface->window.rect.top);
+    *confine = map_rect_to_surface(surface, window_clip);
 }
 
 /**********************************************************************
@@ -1046,8 +1036,7 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset)
     struct wayland_win_data *data;
     BOOL covers_vscreen = FALSE;
     RECT confine_rect;
-    POINT cursor_pos;
-    int warp_x, warp_y;
+    POINT cursor_pos, warp;
 
     TRACE("clip=%s reset=%d\n", wine_dbgstr_rect(clip), reset);
 
@@ -1060,10 +1049,9 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset)
         wl_surface = surface->wl_surface;
         if (clip) wayland_surface_calc_confine(surface, clip, &confine_rect);
         covers_vscreen = wayland_surface_client_covers_vscreen(surface);
-        wayland_surface_coords_from_window(surface,
-                cursor_pos.x - surface->window.rect.left,
-                cursor_pos.y - surface->window.rect.top,
-                &warp_x, &warp_y);
+        warp.x = cursor_pos.x - surface->window.rect.left;
+        warp.y = cursor_pos.y - surface->window.rect.top;
+        warp = map_point_to_surface(surface, warp);
     }
     wayland_win_data_release(data);
 
@@ -1076,11 +1064,11 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset)
                     process_wayland.wp_pointer_warp_v1,
                     wl_surface,
                     pointer->wl_pointer,
-                    wl_fixed_from_int(warp_x),
-                    wl_fixed_from_int(warp_y),
+                    wl_fixed_from_int(warp.x),
+                    wl_fixed_from_int(warp.y),
                     pointer->enter_serial);
-            TRACE("warp_pointer hwnd=%p wayland_xy=%d,%d screen_xy=%d,%d\n",
-                    hwnd, warp_x, warp_y, cursor_pos.x, cursor_pos.y);
+            TRACE("warp_pointer hwnd=%p wayland_xy=%s screen_xy=%s\n",
+                    hwnd, wine_dbgstr_point(&warp), wine_dbgstr_point(&cursor_pos));
         }
         else
         {
@@ -1093,15 +1081,15 @@ BOOL WAYLAND_ClipCursor(const RECT *clip, BOOL reset)
     {
         zwp_locked_pointer_v1_set_cursor_position_hint(
                 pointer->zwp_locked_pointer_v1,
-                wl_fixed_from_int(warp_x),
-                wl_fixed_from_int(warp_y));
+                wl_fixed_from_int(warp.x),
+                wl_fixed_from_int(warp.y));
         pthread_mutex_unlock(&pointer->mutex);
 
         data = wayland_win_data_get(hwnd);
         wl_surface_commit(wl_surface);
         wayland_win_data_release(data);
-        TRACE("position hint hwnd=%p wayland_xy=%d,%d screen_xy=%d,%d\n",
-                hwnd, warp_x, warp_y, cursor_pos.x, cursor_pos.y);
+        TRACE("position hint hwnd=%p wayland_xy=%s screen_xy=%s\n",
+                hwnd, wine_dbgstr_point(&warp), wine_dbgstr_point(&cursor_pos));
         pthread_mutex_lock(&pointer->mutex);
     }
 
diff --git a/dlls/winewayland.drv/wayland_surface.c b/dlls/winewayland.drv/wayland_surface.c
index b8749478c535..0dae09221796 100644
--- a/dlls/winewayland.drv/wayland_surface.c
+++ b/dlls/winewayland.drv/wayland_surface.c
@@ -119,8 +119,7 @@ static void xdg_toplevel_handle_configure(void *private,
 
     if ((surface = data->wayland_surface) && wayland_surface_is_toplevel(surface))
     {
-        surface->pending.width = width;
-        surface->pending.height = height;
+        SetRect(&surface->pending.rect, 0, 0, width, height);
         surface->pending.state = config_state;
     }
 
@@ -138,6 +137,48 @@ static const struct xdg_toplevel_listener xdg_toplevel_listener =
     xdg_toplevel_handle_close
 };
 
+void wp_fractional_scale_handle_scale(void* user_data,
+                                      struct wp_fractional_scale_v1 *fractional_scale_v1,
+                                      uint32_t scale_fixed)
+{
+    struct wayland_win_data *data;
+    struct wayland_client_surface *client;
+    struct wayland_surface *surface;
+    double scale = scale_fixed / 120.0;
+    HWND hwnd = user_data;
+
+    TRACE("hwnd=%p scale=%lf\n", hwnd, scale);
+
+    if (!(data = wayland_win_data_get(hwnd))) return;
+    if (!(surface = data->wayland_surface) || scale == surface->window.scale)
+    {
+        wayland_win_data_release(data);
+        return;
+    }
+
+    surface->window.scale = scale;
+
+    /* reattach the client surface as its rect has changed */
+    if ((client = data->client_surface))
+        wayland_client_surface_attach(client, client->toplevel);
+
+    /* the subsurface rect has changed */
+    if (surface->role == WAYLAND_SURFACE_ROLE_SUBSURFACE)
+    {
+        surface->processing.serial = 1;
+        surface->processing.processed = TRUE;
+    }
+
+    wayland_win_data_release(data);
+
+    NtUserExposeWindowSurface(hwnd, 0, NULL, 0);
+}
+
+static const struct wp_fractional_scale_v1_listener wp_fractional_scale_listener =
+{
+    wp_fractional_scale_handle_scale
+};
+
 /**********************************************************************
  *          wayland_surface_create
  *
@@ -259,6 +300,28 @@ void wayland_surface_destroy(struct wayland_surface *surface)
     free(surface);
 }
 
+static void wayland_surface_init_fractional_scale(struct wayland_surface *surface,
+                                                  double initial_scale)
+{
+    surface->window.scale = initial_scale;
+
+    if (!process_wayland.wp_fractional_scale_manager_v1) return;
+
+    surface->wp_fractional_scale_v1 =
+        wp_fractional_scale_manager_v1_get_fractional_scale(
+            process_wayland.wp_fractional_scale_manager_v1,
+            surface->wl_surface);
+    if (!surface->wp_fractional_scale_v1)
+    {
+        ERR("Failed to create wp_fractional_scale_v1\n");
+        return;
+    }
+    wp_fractional_scale_v1_add_listener(
+        surface->wp_fractional_scale_v1,
+        &wp_fractional_scale_listener,
+        surface->hwnd);
+}
+
 /**********************************************************************
  *          wayland_surface_make_toplevel
  *
@@ -294,6 +357,8 @@ void wayland_surface_make_toplevel(struct wayland_surface *surface)
 
     wayland_surface_assign_icon(surface);
 
+    wayland_surface_init_fractional_scale(surface, 1.0);
+
     wl_surface_commit(surface->wl_surface);
     wl_display_flush(process_wayland.wl_display);
 
@@ -310,30 +375,32 @@ err:
  * Gives the subsurface role to a plain wayland surface.
  */
 void wayland_surface_make_subsurface(struct wayland_surface *surface,
-                                     struct wayland_surface *parent)
+                                     struct wayland_surface *owner)
 {
     assert(!surface->role || surface->role == WAYLAND_SURFACE_ROLE_SUBSURFACE);
-    if (surface->wl_subsurface && surface->toplevel_hwnd == parent->hwnd) return;
+    if (surface->wl_subsurface && surface->owner_hwnd == owner->hwnd) return;
 
     wayland_surface_clear_role(surface);
     surface->role = WAYLAND_SURFACE_ROLE_SUBSURFACE;
 
-    TRACE("surface=%p parent=%p\n", surface, parent);
+    TRACE("surface=%p owner=%p\n", surface, owner);
 
     surface->wl_subsurface =
         wl_subcompositor_get_subsurface(process_wayland.wl_subcompositor,
                                         surface->wl_surface,
-                                        parent->wl_surface);
+                                        owner->wl_surface);
     if (!surface->wl_subsurface)
     {
         ERR("Failed to create client wl_subsurface\n");
         goto err;
     }
 
+    wayland_surface_init_fractional_scale(surface, owner->window.scale);
+
     surface->role = WAYLAND_SURFACE_ROLE_SUBSURFACE;
-    surface->toplevel_hwnd = parent->hwnd;
+    surface->owner_hwnd = owner->hwnd;
 
-    /* Present contents independently of the parent surface. */
+    /* Present contents independently of the owner surface. */
     wl_subsurface_set_desync(surface->wl_subsurface);
 
     wl_display_flush(process_wayland.wl_display);
@@ -356,6 +423,14 @@ void wayland_surface_clear_role(struct wayland_surface *surface)
 {
     TRACE("surface=%p\n", surface);
 
+    /* some objects are shared between several roles */
+
+    if (surface->wp_fractional_scale_v1)
+    {
+        wp_fractional_scale_v1_destroy(surface->wp_fractional_scale_v1);
+        surface->wp_fractional_scale_v1 = NULL;
+    }
+
     switch (surface->role)
     {
     case WAYLAND_SURFACE_ROLE_NONE:
@@ -391,7 +466,7 @@ void wayland_surface_clear_role(struct wayland_surface *surface)
             surface->wl_subsurface = NULL;
         }
 
-        surface->toplevel_hwnd = 0;
+        surface->owner_hwnd = NULL;
         break;
     }
 
@@ -399,7 +474,6 @@ void wayland_surface_clear_role(struct wayland_surface *surface)
     memset(&surface->requested, 0, sizeof(surface->requested));
     memset(&surface->processing, 0, sizeof(surface->processing));
     memset(&surface->current, 0, sizeof(surface->current));
-    surface->toplevel_hwnd = 0;
 
     /* Ensure no buffer is attached, otherwise future role assignments may fail. */
     wl_surface_attach(surface->wl_surface, NULL, 0, 0);
@@ -477,8 +551,7 @@ void wayland_surface_attach_shm(struct wayland_surface *surface,
  * Checks whether a wayland_surface_config object is compatible with the
  * the provided arguments.
  */
-BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf,
-                                          int width, int height,
+BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, RECT rect,
                                           enum wayland_surface_config_state state)
 {
     static enum wayland_surface_config_state mask =
@@ -499,7 +572,8 @@ BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf,
      * reconfiguration we can use surface geometry to provide smaller areas
      * from larger sizes, so only smaller sizes are incompatible. */
     if ((conf->state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
-        (width < conf->width || height < conf->height))
+        (rect.right - rect.left < conf->rect.right - conf->rect.left ||
+         rect.bottom - rect.top < conf->rect.bottom - conf->rect.top))
     {
         return FALSE;
     }
@@ -536,43 +610,39 @@ static void wayland_surface_get_rect_in_monitor(struct wayland_surface *surface,
  *
  * Sets the xdg_surface geometry
  */
-static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface,
-                                                 int width, int height)
+static void wayland_surface_reconfigure_geometry(struct wayland_surface *surface, RECT rect)
 {
-    RECT rect;
-
     /* If the window size is bigger than the current state accepts, use the
      * largest visible (from Windows' perspective) subregion of the window. */
     if ((surface->current.state & (WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED |
                                    WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN)) &&
-        (width > surface->current.width || height > surface->current.height))
+        (rect.right - rect.left > surface->current.rect.right - surface->current.rect.left ||
+         rect.bottom - rect.top > surface->current.rect.bottom - surface->current.rect.top))
     {
         wayland_surface_get_rect_in_monitor(surface, &rect);
 
-        wayland_surface_coords_from_window(surface, rect.left, rect.top,
-                                           (int *)&rect.left, (int *)&rect.top);
-        wayland_surface_coords_from_window(surface, rect.right, rect.bottom,
-                                           (int *)&rect.right, (int *)&rect.bottom);
+        rect = map_rect_to_surface(surface, rect);
 
         /* If the window rect in the monitor is smaller than required,
          * fall back to an appropriately sized rect at the top-left. */
         if ((surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) &&
             !(surface->current.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) &&
-            (rect.right - rect.left < surface->current.width ||
-             rect.bottom - rect.top < surface->current.height))
+            (rect.right - rect.left < surface->current.rect.right - surface->current.rect.left ||
+             rect.bottom - rect.top < surface->current.rect.bottom - surface->current.rect.top))
         {
-            SetRect(&rect, 0, 0, surface->current.width, surface->current.height);
+            SetRect(&rect, 0, 0, surface->current.rect.right - surface->current.rect.left,
+                    surface->current.rect.bottom - surface->current.rect.top);
         }
         else
         {
-            rect.right = min(rect.right, rect.left + surface->current.width);
-            rect.bottom = min(rect.bottom, rect.top + surface->current.height);
+            rect.right = min(rect.right, rect.left + surface->current.rect.right - surface->current.rect.left);
+            rect.bottom = min(rect.bottom, rect.top + surface->current.rect.bottom - surface->current.rect.top);
         }
         TRACE("Window is too large for Wayland state, using subregion\n");
     }
     else
     {
-        SetRect(&rect, 0, 0, width, height);
+        OffsetRect(&rect, -rect.left, -rect.top);
     }
 
     TRACE("hwnd=%p geometry=%s\n", surface->hwnd, wine_dbgstr_rect(&rect));
@@ -622,30 +692,23 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface,
                                                const RECT *client_rect)
 {
     struct wayland_window_config *window = &surface->window;
-    int client_x, client_y, x, y;
-    int client_width, client_height, width, height;
+    RECT rect = *client_rect;
 
     /* The offset of the client area origin relatively to the window origin. */
-    client_x = client_rect->left + window->client_rect.left - window->rect.left;
-    client_y = client_rect->top + window->client_rect.top - window->rect.top;
-
-    client_width = client_rect->right - client_rect->left;
-    client_height = client_rect->bottom - client_rect->top;
+    OffsetRect(&rect, window->client_rect.left - window->rect.left,
+               window->client_rect.top - window->rect.top);
+    rect = map_rect_to_surface(surface, rect);
 
-    wayland_surface_coords_from_window(surface, client_x, client_y, &x, &y);
-    wayland_surface_coords_from_window(surface, client_width, client_height,
-                                       &width, &height);
-
-    TRACE("hwnd=%p subsurface=%d,%d+%dx%d\n", surface->hwnd, x, y, width, height);
+    TRACE("hwnd=%p rect=%s\n", surface->hwnd, wine_dbgstr_rect(&rect));
 
     if (client->wl_subsurface)
     {
-        wl_subsurface_set_position(client->wl_subsurface, x, y);
+        wl_subsurface_set_position(client->wl_subsurface, rect.left, rect.top);
         wl_subsurface_place_above(client->wl_subsurface, surface->wl_surface);
     }
 
-    if (width != 0 && height != 0)
-        wp_viewport_set_destination(client->wp_viewport, width, height);
+    if (rect.left != rect.right && rect.top != rect.bottom)
+        wp_viewport_set_destination(client->wp_viewport, rect.right - rect.left, rect.bottom - rect.top);
     else /* We can't have a 0x0 destination, use 1x1 instead. */
         wp_viewport_set_destination(client->wp_viewport, 1, 1);
 }
@@ -656,15 +719,13 @@ static void wayland_surface_reconfigure_client(struct wayland_surface *surface,
  * Reconfigures the xdg surface as needed to match the latest requested
  * state.
  */
-static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface,
-                                            int width, int height)
+static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface, RECT rect)
 {
     struct wayland_window_config *window = &surface->window;
 
     /* Acknowledge any compatible processed config. */
     if (surface->processing.serial && surface->processing.processed &&
-        wayland_surface_config_is_compatible(&surface->processing,
-                                             width, height,
+        wayland_surface_config_is_compatible(&surface->processing, rect,
                                              window->state))
     {
         surface->current = surface->processing;
@@ -675,8 +736,7 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface,
      * config, use that, in order to draw windows that don't go through the
      * message loop (e.g., some splash screens). */
     else if (!surface->current.serial && surface->requested.serial &&
-             wayland_surface_config_is_compatible(&surface->requested,
-                                                  width, height,
+             wayland_surface_config_is_compatible(&surface->requested, rect,
                                                   window->state))
     {
         surface->current = surface->requested;
@@ -684,14 +744,13 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface,
         xdg_surface_ack_configure(surface->xdg_surface, surface->current.serial);
     }
     else if (!surface->current.serial ||
-             !wayland_surface_config_is_compatible(&surface->current,
-                                                   width, height,
+             !wayland_surface_config_is_compatible(&surface->current, rect,
                                                    window->state))
     {
         return FALSE;
     }
 
-    wayland_surface_reconfigure_geometry(surface, width, height);
+    wayland_surface_reconfigure_geometry(surface, rect);
 
     return TRUE;
 }
@@ -704,27 +763,26 @@ static BOOL wayland_surface_reconfigure_xdg(struct wayland_surface *surface,
  */
 static void wayland_surface_reconfigure_subsurface(struct wayland_surface *surface)
 {
-    struct wayland_win_data *toplevel_data;
-    struct wayland_surface *toplevel_surface;
-    int local_x, local_y, x, y;
+    struct wayland_win_data *owner_data;
+    struct wayland_surface *owner_surface;
 
     if (surface->processing.serial && surface->processing.processed &&
-        (toplevel_data = wayland_win_data_get_nolock(surface->toplevel_hwnd)) &&
-        (toplevel_surface = toplevel_data->wayland_surface))
+        (owner_data = wayland_win_data_get_nolock(surface->owner_hwnd)) &&
+        (owner_surface = owner_data->wayland_surface))
     {
-        local_x = surface->window.rect.left - toplevel_surface->window.rect.left;
-        local_y = surface->window.rect.top - toplevel_surface->window.rect.top;
+        RECT rect = surface->window.rect;
 
-        wayland_surface_coords_from_window(surface, local_x, local_y, &x, &y);
+        OffsetRect(&rect, -owner_surface->window.rect.left, -owner_surface->window.rect.top);
+        rect = map_rect_to_surface(surface, rect);
 
-        TRACE("hwnd=%p pos=%d,%d\n", surface->hwnd, x, y);
+        TRACE("hwnd=%p rect=%s\n", surface->hwnd, wine_dbgstr_rect(&rect));
 
-        wl_subsurface_set_position(surface->wl_subsurface, x, y);
-        if (toplevel_data->client_surface && toplevel_data->client_surface->wl_subsurface)
-            wl_subsurface_place_above(surface->wl_subsurface, toplevel_data->client_surface->wl_surface);
+        wl_subsurface_set_position(surface->wl_subsurface, rect.left, rect.top);
+        if (owner_data->client_surface && owner_data->client_surface->wl_subsurface)
+            wl_subsurface_place_above(surface->wl_subsurface, owner_data->client_surface->wl_surface);
         else
-            wl_subsurface_place_above(surface->wl_subsurface, toplevel_surface->wl_surface);
-        wl_surface_commit(toplevel_surface->wl_surface);
+            wl_subsurface_place_above(surface->wl_subsurface, owner_surface->wl_surface);
+        wl_surface_commit(owner_surface->wl_surface);
 
         memset(&surface->processing, 0, sizeof(surface->processing));
     }
@@ -739,19 +797,12 @@ static void wayland_surface_reconfigure_subsurface(struct wayland_surface *surfa
 BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
 {
     struct wayland_window_config *window = &surface->window;
-    int win_width, win_height, width, height;
-
-    win_width = surface->window.rect.right - surface->window.rect.left;
-    win_height = surface->window.rect.bottom - surface->window.rect.top;
+    RECT rect = map_rect_to_surface(surface, surface->window.rect);
 
-    wayland_surface_coords_from_window(surface, win_width, win_height,
-                                       &width, &height);
-
-    TRACE("hwnd=%p window=%dx%d,%#x processing=%dx%d,%#x current=%dx%d,%#x\n",
-          surface->hwnd, win_width, win_height, window->state,
-          surface->processing.width, surface->processing.height,
-          surface->processing.state, surface->current.width,
-          surface->current.height, surface->current.state);
+    TRACE("hwnd=%p window=%s,%#x processing=%s,%#x current=%s,%#x\n",
+          surface->hwnd, wine_dbgstr_rect(&rect), window->state,
+          wine_dbgstr_rect(&surface->processing.rect), surface->processing.state,
+          wine_dbgstr_rect(&surface->current.rect), surface->current.state);
 
     switch (surface->role)
     {
@@ -759,7 +810,7 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
         break;
     case WAYLAND_SURFACE_ROLE_TOPLEVEL:
         if (!surface->xdg_surface) break; /* surface role has been cleared */
-        if (!wayland_surface_reconfigure_xdg(surface, width, height)) return FALSE;
+        if (!wayland_surface_reconfigure_xdg(surface, rect)) return FALSE;
         break;
     case WAYLAND_SURFACE_ROLE_SUBSURFACE:
         if (!surface->wl_subsurface) break; /* surface role has been cleared */
@@ -767,7 +818,7 @@ BOOL wayland_surface_reconfigure(struct wayland_surface *surface)
         break;
     }
 
-    wayland_surface_reconfigure_size(surface, width, height);
+    wayland_surface_reconfigure_size(surface, rect.right - rect.left, rect.bottom - rect.top);
 
     return TRUE;
 }
@@ -1048,34 +1099,55 @@ failed:
 }
 
 /**********************************************************************
- *          wayland_surface_coords_from_window
+ *          map_rect_to_surface
  *
  * Converts the window (logical) coordinates to wayland surface-local coordinates.
  */
-void wayland_surface_coords_from_window(struct wayland_surface *surface,
-                                        int window_x, int window_y,
-                                        int *surface_x, int *surface_y)
+RECT map_rect_to_surface(struct wayland_surface *surface, RECT rect)
 {
-    *surface_x = round(window_x / surface->window.scale);
-    *surface_y = round(window_y / surface->window.scale);
+    rect.left = round(rect.left / surface->window.scale);
+    rect.top  = round(rect.top / surface->window.scale);
+    rect.right = round(rect.right / surface->window.scale);
+    rect.bottom  = round(rect.bottom / surface->window.scale);
+    return rect;
 }
 
 /**********************************************************************
- *          wayland_surface_coords_to_window
+ *          map_point_to_surface
+ *
+ * Converts the window (logical) coordinates to wayland surface-local coordinates.
+ */
+POINT map_point_to_surface(struct wayland_surface *surface, POINT point)
+{
+    point.x = round(point.x / surface->window.scale);
+    point.y  = round(point.y / surface->window.scale);
+    return point;
+}
+
+/**********************************************************************
+ *          map_rect_from_surface
  *
  * Converts the surface-local coordinates to window (logical) coordinates.
  */
-void wayland_surface_coords_to_window(struct wayland_surface *surface,
-                                      double surface_x, double surface_y,
-                                      int *window_x, int *window_y)
+RECT map_rect_from_surface(struct wayland_surface *surface, RECT rect)
 {
-    *window_x = round(surface_x * surface->window.scale);
-    *window_y = round(surface_y * surface->window.scale);
+    rect.left = round(rect.left * surface->window.scale);
+    rect.top  = round(rect.top * surface->window.scale);
+    rect.right = round(rect.right * surface->window.scale);
+    rect.bottom  = round(rect.bottom * surface->window.scale);
+    return rect;
 }
 
-static struct wayland_client_surface *impl_from_client_surface(struct client_surface *client)
+/**********************************************************************
+ *          map_point_from_surface
+ *
+ * Converts the surface-local coordinates to window (logical) coordinates.
+ */
+POINT map_point_from_surface(struct wayland_surface *surface, POINT point)
 {
-    return CONTAINING_RECORD(client, struct wayland_client_surface, client);
+    point.x = round(point.x * surface->window.scale);
+    point.y = round(point.y * surface->window.scale);
+    return point;
 }
 
 static void wayland_client_surface_destroy(struct client_surface *client)
@@ -1137,7 +1209,13 @@ static const struct client_surface_funcs wayland_client_surface_funcs =
     .present = wayland_client_surface_present,
 };
 
-struct wayland_client_surface *wayland_client_surface_create(HWND hwnd)
+struct wayland_client_surface *impl_from_client_surface(struct client_surface *client)
+{
+    assert(client->funcs == &wayland_client_surface_funcs);
+    return CONTAINING_RECORD(client, struct wayland_client_surface, client);
+}
+
+struct client_surface *WAYLAND_CreateClientSurface(HWND hwnd, int pixel_format)
 {
     struct wayland_client_surface *client;
     struct wl_region *empty_region;
@@ -1172,7 +1250,7 @@ struct wayland_client_surface *wayland_client_surface_create(HWND hwnd)
         goto err;
     }
 
-    return client;
+    return &client->client;
 
 err:
     client_surface_release(&client->client);
diff --git a/dlls/winewayland.drv/wayland_text_input.c b/dlls/winewayland.drv/wayland_text_input.c
index f92f051f918d..980f86728c84 100644
--- a/dlls/winewayland.drv/wayland_text_input.c
+++ b/dlls/winewayland.drv/wayland_text_input.c
@@ -228,7 +228,8 @@ BOOL WAYLAND_SetIMECompositionRect(HWND hwnd, RECT rect)
     struct wayland_text_input *text_input = &process_wayland.text_input;
     struct wayland_win_data *data;
     struct wayland_surface *surface;
-    int cursor_x, cursor_y, cursor_width, cursor_height;
+    RECT surface_rect;
+
     TRACE("hwnd %p, rect %s.\n", hwnd, wine_dbgstr_rect(&rect));
 
     pthread_mutex_lock(&text_input->mutex);
@@ -245,18 +246,14 @@ BOOL WAYLAND_SetIMECompositionRect(HWND hwnd, RECT rect)
         goto err;
     }
 
-    wayland_surface_coords_from_window(surface,
-            rect.left - surface->window.rect.left,
-            rect.top - surface->window.rect.top,
-            &cursor_x, &cursor_y);
-    wayland_surface_coords_from_window(surface,
-            rect.right - rect.left,
-            rect.bottom - rect.top,
-            &cursor_width, &cursor_height);
+
+    OffsetRect(&rect, -surface->window.rect.left, -surface->window.rect.top);
+    surface_rect = map_rect_to_surface(surface, rect);
     wayland_win_data_release(data);
 
     zwp_text_input_v3_set_cursor_rectangle(text_input->zwp_text_input_v3,
-            cursor_x, cursor_y, cursor_width, cursor_height);
+            surface_rect.left, surface_rect.right, surface_rect.right - surface_rect.left,
+            surface_rect.bottom - surface_rect.top);
     zwp_text_input_v3_commit(text_input->zwp_text_input_v3);
 
     pthread_mutex_unlock(&text_input->mutex);
diff --git a/dlls/winewayland.drv/waylanddrv.h b/dlls/winewayland.drv/waylanddrv.h
index 30fb7f979698..e0df8e56bb5c 100644
--- a/dlls/winewayland.drv/waylanddrv.h
+++ b/dlls/winewayland.drv/waylanddrv.h
@@ -40,6 +40,7 @@
 #include "xdg-toplevel-icon-v1-client-protocol.h"
 #include "pointer-warp-v1-client-protocol.h"
 #include "alpha-modifier-v1-client-protocol.h"
+#include "fractional-scale-v1-client-protocol.h"
 
 #include "windef.h"
 #include "winbase.h"
@@ -173,6 +174,7 @@ struct wayland
     struct wl_shm *wl_shm;
     struct wp_viewporter *wp_viewporter;
     struct wl_subcompositor *wl_subcompositor;
+    struct wp_fractional_scale_manager_v1 *wp_fractional_scale_manager_v1;
     struct zwp_pointer_constraints_v1 *zwp_pointer_constraints_v1;
     struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
     struct zwp_text_input_manager_v3 *zwp_text_input_manager_v3;
@@ -224,7 +226,7 @@ struct wayland_output
 
 struct wayland_surface_config
 {
-    int32_t width, height;
+    RECT rect;
     enum wayland_surface_config_state state;
     uint32_t serial;
     BOOL processed;
@@ -252,6 +254,8 @@ struct wayland_client_surface
     struct wp_viewport *wp_viewport;
 };
 
+extern struct wayland_client_surface *impl_from_client_surface(struct client_surface *client);
+
 struct wayland_shm_buffer
 {
     struct wl_list link;
@@ -271,6 +275,7 @@ struct wayland_surface
 
     struct wl_surface *wl_surface;
     struct wp_viewport *wp_viewport;
+    struct wp_fractional_scale_v1 *wp_fractional_scale_v1;
     struct wayland_shm_buffer *small_icon_buffer;
     struct wayland_shm_buffer *big_icon_buffer;
 
@@ -286,7 +291,7 @@ struct wayland_surface
         struct
         {
             struct wl_subsurface *wl_subsurface;
-            HWND toplevel_hwnd;
+            HWND owner_hwnd;
         };
     };
     struct wp_alpha_modifier_surface_v1 *wp_alpha_modifier_surface_v1;
@@ -326,16 +331,12 @@ void wayland_surface_attach_shm(struct wayland_surface *surface,
                                 struct wayland_shm_buffer *shm_buffer,
                                 HRGN surface_damage_region);
 BOOL wayland_surface_reconfigure(struct wayland_surface *surface);
-BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf,
-                                          int width, int height,
+BOOL wayland_surface_config_is_compatible(struct wayland_surface_config *conf, RECT rect,
                                           enum wayland_surface_config_state state);
-void wayland_surface_coords_from_window(struct wayland_surface *surface,
-                                        int window_x, int window_y,
-                                        int *surface_x, int *surface_y);
-void wayland_surface_coords_to_window(struct wayland_surface *surface,
-                                      double surface_x, double surface_y,
-                                      int *window_x, int *window_y);
-struct wayland_client_surface *wayland_client_surface_create(HWND hwnd);
+RECT map_rect_to_surface(struct wayland_surface *surface, RECT rect);
+POINT map_point_to_surface(struct wayland_surface *surface, POINT point);
+RECT map_rect_from_surface(struct wayland_surface *surface, RECT rect);
+POINT map_point_from_surface(struct wayland_surface *surface, POINT point);
 void wayland_client_surface_attach(struct wayland_client_surface *client, HWND toplevel);
 void wayland_surface_ensure_contents(struct wayland_surface *surface);
 void wayland_surface_set_title(struct wayland_surface *surface, LPCWSTR title);
@@ -466,6 +467,7 @@ LRESULT WAYLAND_WindowMessage(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
 void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags,
                               const struct window_rects *new_rects, struct window_surface *surface);
 BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects);
+struct client_surface *WAYLAND_CreateClientSurface(HWND hwnd, int pixel_format);
 BOOL WAYLAND_CreateWindowSurface(HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface);
 UINT WAYLAND_VulkanInit(UINT version, void *vulkan_handle, const struct vulkan_driver_funcs **driver_funcs);
 UINT WAYLAND_OpenGLInit(UINT version, const struct opengl_funcs *opengl_funcs, const struct opengl_driver_funcs **driver_funcs);
diff --git a/dlls/winewayland.drv/waylanddrv_main.c b/dlls/winewayland.drv/waylanddrv_main.c
index 5fae15c81ebc..275a3907f929 100644
--- a/dlls/winewayland.drv/waylanddrv_main.c
+++ b/dlls/winewayland.drv/waylanddrv_main.c
@@ -53,6 +53,7 @@ static const struct user_driver_funcs waylanddrv_funcs =
     .pWindowMessage = WAYLAND_WindowMessage,
     .pWindowPosChanged = WAYLAND_WindowPosChanged,
     .pWindowPosChanging = WAYLAND_WindowPosChanging,
+    .pCreateClientSurface = WAYLAND_CreateClientSurface,
     .pCreateWindowSurface = WAYLAND_CreateWindowSurface,
     .pVulkanInit = WAYLAND_VulkanInit,
     .pOpenGLInit = WAYLAND_OpenGLInit,
diff --git a/dlls/winewayland.drv/window.c b/dlls/winewayland.drv/window.c
index ff58a68809b2..afef743755b0 100644
--- a/dlls/winewayland.drv/window.c
+++ b/dlls/winewayland.drv/window.c
@@ -176,7 +176,6 @@ static void wayland_win_data_get_config(struct wayland_win_data *data,
 
     conf->resizeable = data->resizeable;
     conf->state = window_state;
-    conf->scale = NtUserGetSystemDpiForProcess(0) / 96.0;
     conf->visible = (style & WS_VISIBLE) == WS_VISIBLE;
     conf->managed = data->managed;
 }
@@ -189,7 +188,7 @@ static void reapply_cursor_clipping(void)
     NtUserSetThreadDpiAwarenessContext(context);
 }
 
-static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *data, struct wayland_surface *toplevel_surface)
+static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *data, struct wayland_surface *owner_surface)
 {
     struct wayland_client_surface *client = data->client_surface;
     struct wayland_surface *surface;
@@ -204,7 +203,7 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat
                (!(exstyle & WS_EX_LAYERED) || data->layered_attribs_set);
 
     if (!visible) role = WAYLAND_SURFACE_ROLE_NONE;
-    else if (toplevel_surface) role = WAYLAND_SURFACE_ROLE_SUBSURFACE;
+    else if (owner_surface) role = WAYLAND_SURFACE_ROLE_SUBSURFACE;
     else role = WAYLAND_SURFACE_ROLE_TOPLEVEL;
 
     /* we can temporarily clear the role of a surface but cannot assign a different one after it's set */
@@ -237,7 +236,7 @@ static BOOL wayland_win_data_create_wayland_surface(struct wayland_win_data *dat
         wayland_surface_make_toplevel(surface);
         break;
     case WAYLAND_SURFACE_ROLE_SUBSURFACE:
-        wayland_surface_make_subsurface(surface, toplevel_surface);
+        wayland_surface_make_subsurface(surface, owner_surface);
         break;
     }
 
@@ -316,7 +315,7 @@ static void wayland_win_data_update_wayland_state(struct wayland_win_data *data)
         wayland_surface_update_state_toplevel(surface);
         break;
     case WAYLAND_SURFACE_ROLE_SUBSURFACE:
-        TRACE("hwnd=%p subsurface parent=%p\n", surface->hwnd, surface->toplevel_hwnd);
+        TRACE("hwnd=%p subsurface owner=%p\n", surface->hwnd, surface->owner_hwnd);
         /* Although subsurfaces don't have a dedicated surface config mechanism,
          * we use the config fields to mark them as updated. */
         surface->processing.serial = 1;
@@ -447,10 +446,10 @@ BOOL WAYLAND_WindowPosChanging(HWND hwnd, UINT swp_flags, BOOL shaped, const str
 void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UINT swp_flags,
                               const struct window_rects *new_rects, struct window_surface *surface)
 {
-    HWND toplevel = NtUserGetAncestor(hwnd, GA_ROOT);
-    struct wayland_surface *toplevel_surface;
+    HWND owner = NtUserGetAncestor(hwnd, GA_ROOT);
+    struct wayland_surface *owner_surface;
     struct wayland_client_surface *client;
-    struct wayland_win_data *data, *toplevel_data;
+    struct wayland_win_data *data, *owner_data;
     BOOL managed, fullscreen = swp_flags & WINE_SWP_FULLSCREEN;
 
     TRACE("hwnd %p new_rects %s after %p flags %08x\n", hwnd, debugstr_window_rects(new_rects), insert_after, swp_flags);
@@ -458,11 +457,11 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UIN
     /* Get the managed state with win_data unlocked, as is_window_managed
      * may need to query win_data information about other HWNDs and thus
      * acquire the lock itself internally. */
-    if (!(managed = is_window_managed(hwnd, swp_flags, fullscreen)) && surface) toplevel = owner_hint;
+    if (!(managed = is_window_managed(hwnd, swp_flags, fullscreen)) && surface) owner = owner_hint;
 
     if (!(data = wayland_win_data_get(hwnd))) return;
-    toplevel_data = toplevel && toplevel != hwnd ? wayland_win_data_get_nolock(toplevel) : NULL;
-    toplevel_surface = toplevel_data ? toplevel_data->wayland_surface : NULL;
+    owner_data = owner && owner != hwnd ? wayland_win_data_get_nolock(owner) : NULL;
+    owner_surface = owner_data ? owner_data->wayland_surface : NULL;
 
     data->rects = *new_rects;
     data->is_fullscreen = fullscreen;
@@ -473,8 +472,8 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UIN
     {
         if ((client = data->client_surface))
         {
-            if (toplevel && NtUserIsWindowVisible(hwnd))
-                wayland_client_surface_attach(client, toplevel);
+            if (owner && NtUserIsWindowVisible(hwnd))
+                wayland_client_surface_attach(client, owner);
             else
                 wayland_client_surface_attach(client, NULL);
         }
@@ -485,7 +484,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UIN
             data->wayland_surface = NULL;
         }
     }
-    else if (wayland_win_data_create_wayland_surface(data, toplevel_surface))
+    else if (wayland_win_data_create_wayland_surface(data, owner_surface))
     {
         wayland_win_data_update_wayland_state(data);
     }
@@ -496,8 +495,7 @@ void WAYLAND_WindowPosChanged(HWND hwnd, HWND insert_after, HWND owner_hint, UIN
 static void wayland_configure_window(HWND hwnd)
 {
     struct wayland_surface *surface;
-    INT width, height, window_width, window_height;
-    INT window_surf_width, window_surf_height;
+    INT width, height;
     UINT flags = 0;
     uint32_t state;
     DWORD style;
@@ -505,7 +503,7 @@ static void wayland_configure_window(HWND hwnd)
     BOOL needs_exit_size_move = FALSE;
     BOOL restoring_from_minimize = FALSE;
     struct wayland_win_data *data;
-    RECT rect;
+    RECT rect, surface_rect;
 
     if (!(data = wayland_win_data_get(hwnd))) return;
     if (!(surface = data->wayland_surface))
@@ -536,8 +534,8 @@ static void wayland_configure_window(HWND hwnd)
      * size adherence, in order to avoid spurious resizes. */
     if (state)
     {
-        width = surface->processing.width;
-        height = surface->processing.height;
+        width = surface->processing.rect.right - surface->processing.rect.left;
+        height = surface->processing.rect.bottom - surface->processing.rect.top;
     }
     else
     {
@@ -564,28 +562,19 @@ static void wayland_configure_window(HWND hwnd)
         flags |= SWP_FRAMECHANGED;
     }
 
-    wayland_surface_coords_from_window(surface,
-                                       surface->window.rect.right -
-                                           surface->window.rect.left,
-                                       surface->window.rect.bottom -
-                                           surface->window.rect.top,
-                                       &window_surf_width, &window_surf_height);
+    surface_rect = map_rect_to_surface(surface, surface->window.rect);
 
     /* If the window is already fullscreen and its size is compatible with what
      * the compositor is requesting, don't force a resize, since some applications
      * are very insistent on a particular fullscreen size (which may not match
      * the monitor size). */
     if ((surface->window.state & WAYLAND_SURFACE_CONFIG_STATE_FULLSCREEN) &&
-        wayland_surface_config_is_compatible(&surface->processing,
-                                             window_surf_width, window_surf_height,
+        wayland_surface_config_is_compatible(&surface->processing, surface_rect,
                                              surface->window.state))
     {
         flags |= SWP_NOSIZE;
     }
 
-    wayland_surface_coords_to_window(surface, width, height,
-                                     &window_width, &window_height);
-
     /* Detect a restore from an application-initiated minimize: the last
      * requested config placed the window at the offscreen sentinel position
      * with WS_MINIMIZE, and the compositor is now sending a configure. Ack
@@ -608,7 +597,8 @@ static void wayland_configure_window(HWND hwnd)
         return;
     }
 
-    SetRect(&rect, 0, 0, window_width, window_height);
+    SetRect(&rect, 0, 0, width, height);
+    rect = map_rect_from_surface(surface, rect);
     OffsetRect(&rect, data->rects.window.left, data->rects.window.top);
 
     wayland_win_data_release(data);
@@ -619,7 +609,7 @@ static void wayland_configure_window(HWND hwnd)
     if (needs_exit_size_move) send_message(hwnd, WM_EXITSIZEMOVE, 0, 0);
 
     flags |= SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOMOVE;
-    if (window_width == 0 || window_height == 0) flags |= SWP_NOSIZE;
+    if (rect.left == rect.right || rect.bottom == rect.top) flags |= SWP_NOSIZE;
 
     style = NtUserGetWindowLongW(hwnd, GWL_STYLE);
     if (!(state & WAYLAND_SURFACE_CONFIG_STATE_MAXIMIZED) != !(style & WS_MAXIMIZE)
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c
index 09ef2bf86640..d5b4fdbf0aae 100644
--- a/dlls/winex11.drv/init.c
+++ b/dlls/winex11.drv/init.c
@@ -26,6 +26,7 @@
 
 #include <stdarg.h>
 #include <string.h>
+#include <assert.h>
 
 #include "windef.h"
 #include "winbase.h"
@@ -264,25 +265,6 @@ HRGN get_dc_monitor_region( HWND hwnd, HDC hdc )
     return 0;
 }
 
-static const struct client_surface_funcs x11drv_client_surface_funcs;
-
-struct x11drv_client_surface
-{
-    struct client_surface client;
-    XWindowChanges changes;
-    Colormap colormap;
-    Window window;
-    RECT rect;
-
-    HDC hdc_src;
-    HDC hdc_dst;
-};
-
-static struct x11drv_client_surface *impl_from_client_surface( struct client_surface *client )
-{
-    return CONTAINING_RECORD( client, struct x11drv_client_surface, client );
-}
-
 static void x11drv_client_surface_destroy( struct client_surface *client )
 {
     struct x11drv_client_surface *surface = impl_from_client_surface( client );
@@ -477,17 +459,23 @@ static int visual_class_alloc( int class )
     return class == PseudoColor || class == GrayScale || class == DirectColor ? AllocAll : AllocNone;
 }
 
-Window x11drv_client_surface_create( HWND hwnd, int format, struct client_surface **client )
+struct x11drv_client_surface *impl_from_client_surface( struct client_surface *client )
+{
+    assert( client->funcs == &x11drv_client_surface_funcs );
+    return CONTAINING_RECORD( client, struct x11drv_client_surface, client );
+}
+
+struct client_surface *X11DRV_CreateClientSurface( HWND hwnd, int format )
 {
     struct x11drv_client_surface *surface;
     XVisualInfo visual = default_visual;
     Colormap colormap;
 
-    if (format && !visual_from_pixel_format( format, &visual )) return None;
+    if (format && !visual_from_pixel_format( format, &visual )) return NULL;
 
     if (visual.visualid == default_visual.visualid) colormap = default_colormap;
     else colormap = XCreateColormap( gdi_display, get_dummy_parent(), visual.visual, visual_class_alloc( visual.class ) );
-    if (!colormap) return None;
+    if (!colormap) return NULL;
 
     if (!(surface = client_surface_create( sizeof(*surface), &x11drv_client_surface_funcs, hwnd ))) goto failed;
     surface->colormap = colormap;
@@ -496,13 +484,12 @@ Window x11drv_client_surface_create( HWND hwnd, int format, struct client_surfac
     if (!(surface->window = create_client_window( hwnd, surface->rect, &visual, colormap ))) goto failed;
 
     TRACE( "Created %s for client window %lx\n", debugstr_client_surface( &surface->client ), surface->window );
-    *client = &surface->client;
-    return surface->window;
+    return &surface->client;
 
 failed:
     if (surface) client_surface_release( &surface->client );
     else if (colormap != default_colormap) XFreeColormap( gdi_display, colormap );
-    return None;
+    return NULL;
 }
 
 /**********************************************************************
@@ -711,6 +698,7 @@ static const struct user_driver_funcs x11drv_funcs =
     .pWindowPosChanging = X11DRV_WindowPosChanging,
     .pGetWindowStyleMasks = X11DRV_GetWindowStyleMasks,
     .pGetWindowStateUpdates = X11DRV_GetWindowStateUpdates,
+    .pCreateClientSurface = X11DRV_CreateClientSurface,
     .pCreateWindowSurface = X11DRV_CreateWindowSurface,
     .pMoveWindowBits = X11DRV_MoveWindowBits,
     .pWindowPosChanged = X11DRV_WindowPosChanged,
diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c
index f66ba6399371..5b36def3f17c 100644
--- a/dlls/winex11.drv/mouse.c
+++ b/dlls/winex11.drv/mouse.c
@@ -40,7 +40,6 @@ static void *xcursor_handle;
 # define MAKE_FUNCPTR(f) static typeof(f) * p##f
 MAKE_FUNCPTR(XcursorImageCreate);
 MAKE_FUNCPTR(XcursorImageDestroy);
-MAKE_FUNCPTR(XcursorImageLoadCursor);
 MAKE_FUNCPTR(XcursorImagesCreate);
 MAKE_FUNCPTR(XcursorImagesDestroy);
 MAKE_FUNCPTR(XcursorImagesLoadCursor);
@@ -155,7 +154,6 @@ void X11DRV_Xcursor_Init(void)
 
     LOAD_FUNCPTR(XcursorImageCreate);
     LOAD_FUNCPTR(XcursorImageDestroy);
-    LOAD_FUNCPTR(XcursorImageLoadCursor);
     LOAD_FUNCPTR(XcursorImagesCreate);
     LOAD_FUNCPTR(XcursorImagesDestroy);
     LOAD_FUNCPTR(XcursorImagesLoadCursor);
@@ -535,24 +533,14 @@ static void map_event_coords( HWND hwnd, Window window, Window event_root, int x
  */
 static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPUT *input )
 {
-    struct x11drv_win_data *data;
-
-    input->type = INPUT_MOUSE;
-
-    if (!hwnd)
-    {
-        struct x11drv_thread_data *thread_data = x11drv_thread_data();
-        if (!thread_data->clipping_cursor || thread_data->clip_window != window) return;
-        NtUserSendHardwareInput( hwnd, 0, input, 0 );
-        return;
-    }
+    struct x11drv_thread_data *thread_data = x11drv_thread_data();
 
-    if (!(data = get_win_data( hwnd ))) return;
-    release_win_data( data );
+    /* ignore clipping window input when not clipping or wrong clipping window */
+    if (!hwnd && (!thread_data->clipping_cursor || thread_data->clip_window != window)) return;
 
     /* update the wine server Z-order */
 
-    if (hwnd != x11drv_thread_data()->grab_hwnd &&
+    if (hwnd && hwnd != NtUserGetAncestor( get_capture_window(), GA_ROOT ) &&
         /* ignore event if a button is pressed, since the mouse is then grabbed too */
         !(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask|Button6Mask|Button7Mask)))
     {
@@ -567,6 +555,7 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU
         SERVER_END_REQ;
     }
 
+    input->type = INPUT_MOUSE;
     NtUserSendHardwareInput( hwnd, 0, input, 0 );
 }
 
@@ -1604,7 +1593,7 @@ BOOL X11DRV_MotionNotify( HWND hwnd, XEvent *xev )
     input.mi.time        = EVENT_x11_time_to_win32_time( event->time );
     input.mi.dwExtraInfo = 0;
 
-    if (!hwnd && is_old_motion_event( event->serial ))
+    if (is_old_motion_event( event->serial ))
     {
         TRACE( "pos %d,%d old serial %lu, ignoring\n", event->x, event->y, event->serial );
         return FALSE;
@@ -1627,7 +1616,7 @@ BOOL X11DRV_EnterNotify( HWND hwnd, XEvent *xev )
 
     x11drv_thread_data()->keymapnotify_hwnd = hwnd;
 
-    if (hwnd == x11drv_thread_data()->grab_hwnd) return FALSE;
+    if (hwnd == NtUserGetAncestor( get_capture_window(), GA_ROOT )) return FALSE;
 
     /* simulate a mouse motion event */
     input.mi.dx          = event->x;
diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c
index 56c22ab7ee7d..2d5608754699 100644
--- a/dlls/winex11.drv/opengl.c
+++ b/dlls/winex11.drv/opengl.c
@@ -212,7 +212,7 @@ enum glx_swap_control_method
 };
 
 static struct glx_pixel_format *pixel_formats;
-static int nb_pixel_formats, nb_onscreen_formats;
+static int nb_pixel_formats;
 static const struct egl_platform *egl;
 static BOOL (*p_egl_describe_pixel_format)( int format, struct wgl_pixel_format *pf );
 
@@ -274,7 +274,6 @@ static const char *(*pglXQueryServerString)( Display *dpy, int screen, int name
 static const char *(*pglXGetClientString)( Display *dpy, int name );
 
 /* GLX 1.3 */
-static GLXFBConfig *(*pglXChooseFBConfig)( Display *dpy, int screen, const int *attribList, int *nitems );
 static int (*pglXGetFBConfigAttrib)( Display *dpy, GLXFBConfig config, int attribute, int *value );
 static GLXFBConfig *(*pglXGetFBConfigs)( Display *dpy, int screen, int *nelements );
 static XVisualInfo *(*pglXGetVisualFromFBConfig)( Display *dpy, GLXFBConfig config );
@@ -299,7 +298,6 @@ static void* (*pglXAllocateMemoryNV)(GLsizei size, GLfloat readfreq, GLfloat wri
 static void  (*pglXFreeMemoryNV)(GLvoid *pointer);
 
 /* MESA GLX Extensions */
-static void (*pglXCopySubBufferMESA)(Display *dpy, GLXDrawable drawable, int x, int y, int width, int height);
 static int (*pglXSwapIntervalMESA)(unsigned int interval);
 static Bool (*pglXQueryCurrentRendererIntegerMESA)(int attribute, unsigned int *value);
 static const char *(*pglXQueryCurrentRendererStringMESA)(int attribute);
@@ -519,18 +517,12 @@ static BOOL x11drv_egl_describe_pixel_format( int format, struct wgl_pixel_forma
     return TRUE;
 }
 
-static BOOL x11drv_egl_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
+static BOOL x11drv_egl_surface_create( struct client_surface *client, int format, struct opengl_drawable **drawable )
 {
-    struct opengl_drawable *previous;
-    struct client_surface *client;
+    struct x11drv_client_surface *surface = impl_from_client_surface( client );
     struct gl_drawable *gl;
-    Window window;
 
-    if ((previous = *drawable) && previous->format == format) return TRUE;
-    if (!(window = x11drv_client_surface_create( hwnd, format, &client ))) return FALSE;
-    gl = opengl_drawable_create( sizeof(*gl), &x11drv_egl_surface_funcs, format, client );
-    client_surface_release( client );
-    if (!gl) return FALSE;
+    if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_egl_surface_funcs, format, client ))) return FALSE;
 
     opengl_drawable_map_buffer( &gl->base, GL_FRONT_LEFT, GL_BACK_LEFT );
     opengl_drawable_map_buffer( &gl->base, GL_FRONT, GL_BACK );
@@ -538,16 +530,15 @@ static BOOL x11drv_egl_surface_create( HWND hwnd, int format, struct opengl_draw
     if (gl->base.stereo) opengl_drawable_map_buffer( &gl->base, GL_FRONT_RIGHT, GL_BACK_RIGHT );
 
     if (!(gl->base.surface = funcs->p_eglCreateWindowSurface( egl->display, egl_config_for_format( format ),
-                                                              (void *)window, NULL )))
+                                                              (void *)surface->window, NULL )))
     {
         opengl_drawable_release( &gl->base );
         return FALSE;
     }
 
-    TRACE( "Created drawable %s with client window %lx\n", debugstr_opengl_drawable( &gl->base ), window );
+    TRACE( "Created drawable %s with client window %lx\n", debugstr_opengl_drawable( &gl->base ), surface->window );
     XFlush( gdi_display );
 
-    if (previous) opengl_drawable_release( previous );
     *drawable = &gl->base;
     return TRUE;
 }
@@ -694,12 +685,10 @@ UINT X11DRV_OpenGLInit( UINT version, const struct opengl_funcs *opengl_funcs, c
      */
 
     if(glxRequireVersion(3)) {
-        pglXChooseFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXChooseFBConfig");
         pglXGetFBConfigAttrib = pglXGetProcAddressARB((const GLubyte *) "glXGetFBConfigAttrib");
         pglXGetVisualFromFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXGetVisualFromFBConfig");
         pglXQueryDrawable = pglXGetProcAddressARB((const GLubyte *) "glXQueryDrawable");
     } else if (has_extension( glxExtensions, "GLX_SGIX_fbconfig")) {
-        pglXChooseFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXChooseFBConfigSGIX");
         pglXGetFBConfigAttrib = pglXGetProcAddressARB((const GLubyte *) "glXGetFBConfigAttribSGIX");
         pglXGetVisualFromFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXGetVisualFromFBConfigSGIX");
 
@@ -709,7 +698,6 @@ UINT X11DRV_OpenGLInit( UINT version, const struct opengl_funcs *opengl_funcs, c
         pglXQueryDrawable = NULL;
     } else if(strcmp("ATI", pglXGetClientString(gdi_display, GLX_VENDOR)) == 0) {
         TRACE("Overriding ATI GLX capabilities!\n");
-        pglXChooseFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXChooseFBConfig");
         pglXGetFBConfigAttrib = pglXGetProcAddressARB((const GLubyte *) "glXGetFBConfigAttrib");
         pglXGetVisualFromFBConfig = pglXGetProcAddressARB((const GLubyte *) "glXGetVisualFromFBConfig");
         pglXQueryDrawable = pglXGetProcAddressARB((const GLubyte *) "glXQueryDrawable");
@@ -724,10 +712,6 @@ UINT X11DRV_OpenGLInit( UINT version, const struct opengl_funcs *opengl_funcs, c
             pglXQueryServerString(gdi_display, DefaultScreen(gdi_display), GLX_VERSION));
     }
 
-    if (has_extension( glxExtensions, "GLX_MESA_copy_sub_buffer")) {
-        pglXCopySubBufferMESA = pglXGetProcAddressARB((const GLubyte *) "glXCopySubBufferMESA");
-    }
-
     if (has_extension( glxExtensions, "GLX_MESA_query_renderer" ))
     {
         pglXQueryCurrentRendererIntegerMESA = pglXGetProcAddressARB(
@@ -890,7 +874,6 @@ static UINT x11drv_init_pixel_formats( UINT *onscreen_count )
 
     pixel_formats = list;
     nb_pixel_formats = size;
-    nb_onscreen_formats = onscreen_size;
 
     *onscreen_count = onscreen_size;
     return size;
@@ -956,30 +939,22 @@ static GLXContext create_glxcontext( int format, GLXContext share, const int *at
     return ctx;
 }
 
-static BOOL x11drv_surface_create( HWND hwnd, int format, struct opengl_drawable **drawable )
+static BOOL x11drv_surface_create( struct client_surface *client, int format, struct opengl_drawable **drawable )
 {
+    struct x11drv_client_surface *surface = impl_from_client_surface( client );
     struct glx_pixel_format *fmt = glx_pixel_format_from_format( format );
-    struct opengl_drawable *previous;
-    struct client_surface *client;
     struct gl_drawable *gl;
-    Window window;
-
-    if ((previous = *drawable) && previous->format == format) return TRUE;
-    if (!(window = x11drv_client_surface_create( hwnd, format, &client ))) return FALSE;
-    gl = opengl_drawable_create( sizeof(*gl), &x11drv_surface_funcs, format, client );
-    client_surface_release( client );
-    if (!gl) return FALSE;
 
-    if (!(gl->drawable = pglXCreateWindow( gdi_display, fmt->fbconfig, window, NULL )))
+    if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_surface_funcs, format, client ))) return FALSE;
+    if (!(gl->drawable = pglXCreateWindow( gdi_display, fmt->fbconfig, surface->window, NULL )))
     {
         opengl_drawable_release( &gl->base );
         return FALSE;
     }
 
-    TRACE( "Created drawable %s with client window %lx\n", debugstr_opengl_drawable( &gl->base ), window );
+    TRACE( "Created drawable %s with client window %lx\n", debugstr_opengl_drawable( &gl->base ), surface->window );
     XFlush( gdi_display );
 
-    if (previous) opengl_drawable_release( previous );
     *drawable = &gl->base;
     return TRUE;
 }
@@ -1344,6 +1319,29 @@ static UINT x11drv_pbuffer_bind( HDC hdc, struct opengl_drawable *base, GLenum b
     return -1; /* use default implementation */
 }
 
+static BOOL x11drv_null_surface_create( int format, struct opengl_drawable **drawable )
+{
+    const struct glx_pixel_format *fmt = glx_pixel_format_from_format( format );
+    int glx_attribs[7], count = 0;
+    struct gl_drawable *gl;
+
+    glx_attribs[count++] = GLX_PBUFFER_WIDTH;
+    glx_attribs[count++] = 1;
+    glx_attribs[count++] = GLX_PBUFFER_HEIGHT;
+    glx_attribs[count++] = 1;
+    glx_attribs[count++] = 0;
+
+    if (!(gl = opengl_drawable_create( sizeof(*gl), &x11drv_pbuffer_funcs, format, NULL ))) return FALSE;
+    if (!(gl->drawable = pglXCreatePbuffer( gdi_display, fmt->fbconfig, glx_attribs )))
+    {
+        opengl_drawable_release( &gl->base );
+        return FALSE;
+    }
+
+    *drawable = &gl->base;
+    return TRUE;
+}
+
 static BOOL X11DRV_wglQueryCurrentRendererIntegerWINE( GLenum attribute, GLuint *value )
 {
     return pglXQueryCurrentRendererIntegerMESA( attribute, value );
@@ -1520,6 +1518,7 @@ static struct opengl_driver_funcs x11drv_driver_funcs =
     .p_pbuffer_create = x11drv_pbuffer_create,
     .p_pbuffer_updated = x11drv_pbuffer_updated,
     .p_pbuffer_bind = x11drv_pbuffer_bind,
+    .p_null_surface_create = x11drv_null_surface_create,
 };
 
 static const struct opengl_drawable_funcs x11drv_surface_funcs =
diff --git a/dlls/winex11.drv/vulkan.c b/dlls/winex11.drv/vulkan.c
index e11a989f02dc..1c1b9cf3ba1c 100644
--- a/dlls/winex11.drv/vulkan.c
+++ b/dlls/winex11.drv/vulkan.c
@@ -46,26 +46,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(vulkan);
 
 static const struct vulkan_driver_funcs x11drv_vulkan_driver_funcs;
 
-static VkResult X11DRV_vulkan_surface_create( HWND hwnd, const struct vulkan_instance *instance, VkSurfaceKHR *handle,
-                                              struct client_surface **client )
+static VkResult X11DRV_vulkan_surface_create( struct client_surface *client, const struct vulkan_instance *instance, VkSurfaceKHR *handle )
 {
+    struct x11drv_client_surface *surface = impl_from_client_surface( client );
     VkXlibSurfaceCreateInfoKHR info =
     {
         .sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
         .dpy = gdi_display,
+        .window = surface->window,
     };
+    VkResult res;
 
-    TRACE( "%p %p %p %p\n", hwnd, instance, handle, client );
+    TRACE( "%s %p %p\n", debugstr_client_surface( client ), instance, handle );
 
-    if (!(info.window = x11drv_client_surface_create( hwnd, 0, client ))) return VK_ERROR_OUT_OF_HOST_MEMORY;
-    if (instance->p_vkCreateXlibSurfaceKHR( instance->host.instance, &info, NULL /* allocator */, handle ))
-    {
-        ERR("Failed to create Xlib surface\n");
-        client_surface_release( *client );
-        return VK_ERROR_OUT_OF_HOST_MEMORY;
-    }
+    if ((res = instance->p_vkCreateXlibSurfaceKHR( instance->host.instance, &info, NULL /* allocator */, handle ))) return res;
+    TRACE( "Created surface 0x%s\n", wine_dbgstr_longlong( *handle ) );
 
-    TRACE( "Created surface 0x%s, client %s\n", wine_dbgstr_longlong( *handle ), debugstr_client_surface( *client ) );
     return VK_SUCCESS;
 }
 
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index c3d3312581d7..3b964baadef5 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -3108,32 +3108,31 @@ BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update )
 /***********************************************************************
  *		SetCapture  (X11DRV.@)
  */
-void X11DRV_SetCapture( HWND hwnd, UINT flags )
+void X11DRV_SetCapture( HWND hwnd, UINT flags, HWND previous )
 {
-    struct x11drv_thread_data *thread_data = x11drv_thread_data();
     struct x11drv_win_data *data;
 
+    TRACE( "hwnd %p, flags %#x, previous %p\n", hwnd, flags, previous );
+
     if (!(flags & (GUI_INMOVESIZE | GUI_INMENUMODE))) return;
 
     if (hwnd)
     {
-        if (!(data = get_win_data( NtUserGetAncestor( hwnd, GA_ROOT )))) return;
+        if (!(data = get_win_data( hwnd ))) return;
         if (data->whole_window)
         {
             XGrabPointer( data->display, data->whole_window, False,
                           PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
                           GrabModeAsync, GrabModeAsync, None, None, CurrentTime );
             XFlush( data->display );
-            thread_data->grab_hwnd = data->hwnd;
         }
         release_win_data( data );
     }
-    else  /* release capture */
+    else if (previous)  /* release capture */
     {
-        if (!(data = get_win_data( thread_data->grab_hwnd ))) return;
+        if (!(data = get_win_data( previous ))) return;
         XUngrabPointer( data->display, CurrentTime );
         XFlush( data->display );
-        thread_data->grab_hwnd = NULL;
         release_win_data( data );
     }
 }
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index 3def37a8f21a..73d778259e5f 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -233,7 +233,7 @@ extern void X11DRV_GetDC( HDC hdc, HWND hwnd, HWND top, const RECT *win_rect,
                           const RECT *top_rect, DWORD flags );
 extern void X11DRV_ReleaseDC( HWND hwnd, HDC hdc );
 extern BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update );
-extern void X11DRV_SetCapture( HWND hwnd, UINT flags );
+extern void X11DRV_SetCapture( HWND hwnd, UINT flags, HWND previous );
 extern void X11DRV_SetDesktopWindow( HWND hwnd );
 extern void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha,
                                                DWORD flags );
@@ -251,6 +251,7 @@ extern LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp )
 extern BOOL X11DRV_WindowPosChanging( HWND hwnd, UINT swp_flags, BOOL shaped, const struct window_rects *rects );
 extern BOOL X11DRV_GetWindowStyleMasks( HWND hwnd, UINT style, UINT ex_style, UINT *style_mask, UINT *ex_style_mask );
 extern BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *swp_flags, RECT *rect, HWND *foreground );
+extern struct client_surface *X11DRV_CreateClientSurface( HWND hwnd, int format );
 extern BOOL X11DRV_CreateWindowSurface( HWND hwnd, BOOL layered, const RECT *surface_rect, struct window_surface **surface );
 extern void X11DRV_MoveWindowBits( HWND hwnd, const struct window_rects *old_rects,
                                    const struct window_rects *new_rects, const RECT *valid_rects );
@@ -364,11 +365,24 @@ struct x11drv_escape_get_drawable
     RECT                     dc_rect;      /* DC rectangle relative to drawable */
 };
 
+struct x11drv_client_surface
+{
+    struct client_surface client;
+    XWindowChanges changes;
+    Colormap colormap;
+    Window window;
+    RECT rect;
+
+    HDC hdc_src;
+    HDC hdc_dst;
+};
+
+extern struct x11drv_client_surface *impl_from_client_surface( struct client_surface *client );
+
 extern BOOL needs_offscreen_rendering( HWND hwnd );
 extern void set_dc_drawable( HDC hdc, Drawable drawable, const RECT *rect, int mode );
 extern Drawable get_dc_drawable( HDC hdc, RECT *rect );
 extern HRGN get_dc_monitor_region( HWND hwnd, HDC hdc );
-extern Window x11drv_client_surface_create( HWND hwnd, int format, struct client_surface **client );
 
 /**************************************************************************
  * X11 USER driver
@@ -401,7 +415,6 @@ struct x11drv_thread_data
 {
     Display *display;
     XEvent  *current_event;        /* event currently being processed */
-    HWND     grab_hwnd;            /* window that currently grabs the mouse */
     HWND     last_focus;           /* last window that had focus */
     HWND     keymapnotify_hwnd;    /* window that should receive modifier release events */
     XIM      xim;                  /* input method */
@@ -976,6 +989,13 @@ static inline HWND get_active_window(void)
     return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndActive : 0;
 }
 
+static inline HWND get_capture_window(void)
+{
+    GUITHREADINFO info;
+    info.cbSize = sizeof(info);
+    return NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) ? info.hwndCapture : 0;
+}
+
 static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 )
 {
     dst->left   = max( src1->left, src2->left );
diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c
index 61c2da3e2286..5506c9fc5b03 100644
--- a/dlls/wow64win/user.c
+++ b/dlls/wow64win/user.c
@@ -2834,6 +2834,23 @@ NTSTATUS WINAPI wow64_NtUserGetPointerInfoList( UINT *args )
     return NtUserGetPointerInfoList( id, type, unk0, unk1, size, entry_count, pointer_count, pointer_info );
 }
 
+NTSTATUS WINAPI wow64_NtUserGetPointerType( UINT *args )
+{
+    UINT id = get_ulong( &args );
+    POINTER_INPUT_TYPE *type = get_ptr( &args );
+
+    return NtUserGetPointerType( id, type );
+}
+
+NTSTATUS WINAPI wow64_NtUserGetPointerDeviceRects( UINT *args )
+{
+    HANDLE device = get_handle( &args );
+    RECT *device_rect = get_ptr( &args );
+    RECT *display_rect = get_ptr( &args );
+
+    return NtUserGetPointerDeviceRects( device, device_rect, display_rect );
+}
+
 NTSTATUS WINAPI wow64_NtUserGetPriorityClipboardFormat( UINT *args )
 {
     UINT *list = get_ptr( &args );
diff --git a/dlls/xinput1_3/main.c b/dlls/xinput1_3/main.c
index c1ad48e3fc46..8530b028d5e6 100644
--- a/dlls/xinput1_3/main.c
+++ b/dlls/xinput1_3/main.c
@@ -53,13 +53,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(xinput);
 
 struct xinput_controller
 {
-    CRITICAL_SECTION crit;
     XINPUT_CAPABILITIES caps;
-    XINPUT_STATE state;
-    XINPUT_GAMEPAD last_keystroke;
     XINPUT_VIBRATION vibration;
     HANDLE device;
     WCHAR device_path[MAX_PATH];
+    HANDLE read_event;
     BOOL enabled;
 
     struct
@@ -73,7 +71,6 @@ struct xinput_controller
         HIDP_VALUE_CAPS ry_caps;
         HIDP_VALUE_CAPS rt_caps;
 
-        HANDLE read_event;
         OVERLAPPED read_ovl;
 
         char *input_report_buf;
@@ -86,54 +83,42 @@ struct xinput_controller
     } hid;
 };
 
-static struct xinput_controller controllers[XUSER_MAX_COUNT];
-static CRITICAL_SECTION_DEBUG controller_critsect_debug[XUSER_MAX_COUNT] =
-{
-    {
-        0, 0, &controllers[0].crit,
-        { &controller_critsect_debug[0].ProcessLocksList, &controller_critsect_debug[0].ProcessLocksList },
-          0, 0, { (DWORD_PTR)(__FILE__ ": controllers[0].crit") }
-    },
-    {
-        0, 0, &controllers[1].crit,
-        { &controller_critsect_debug[1].ProcessLocksList, &controller_critsect_debug[1].ProcessLocksList },
-          0, 0, { (DWORD_PTR)(__FILE__ ": controllers[1].crit") }
-    },
-    {
-        0, 0, &controllers[2].crit,
-        { &controller_critsect_debug[2].ProcessLocksList, &controller_critsect_debug[2].ProcessLocksList },
-          0, 0, { (DWORD_PTR)(__FILE__ ": controllers[2].crit") }
-    },
-    {
-        0, 0, &controllers[3].crit,
-        { &controller_critsect_debug[3].ProcessLocksList, &controller_critsect_debug[3].ProcessLocksList },
-          0, 0, { (DWORD_PTR)(__FILE__ ": controllers[3].crit") }
-    },
-};
-
-static struct xinput_controller controllers[XUSER_MAX_COUNT] =
+static CRITICAL_SECTION_DEBUG xinput_cs_debug;
+static CRITICAL_SECTION xinput_cs = { &xinput_cs_debug, -1, 0, 0, 0, 0 };
+static CRITICAL_SECTION_DEBUG xinput_cs_debug =
 {
-    {{ &controller_critsect_debug[0], -1, 0, 0, 0, 0 }},
-    {{ &controller_critsect_debug[1], -1, 0, 0, 0, 0 }},
-    {{ &controller_critsect_debug[2], -1, 0, 0, 0, 0 }},
-    {{ &controller_critsect_debug[3], -1, 0, 0, 0, 0 }},
+    0, 0, &xinput_cs,
+    { &xinput_cs_debug.ProcessLocksList, &xinput_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": xinput_cs") }
 };
 
+static struct xinput_controller controllers[XUSER_MAX_COUNT];
 static HMODULE xinput_instance;
 static HANDLE start_event;
 static HANDLE update_event;
 
-static BOOL find_opened_device(const WCHAR *device_path, int *free_slot)
-{
-    int i;
+static SRWLOCK state_lock = SRWLOCK_INIT;
+static XINPUT_STATE current_state[XUSER_MAX_COUNT];
 
-    *free_slot = XUSER_MAX_COUNT;
-    for (i = XUSER_MAX_COUNT; i > 0; i--)
+static void set_current_state(UINT index, const XINPUT_STATE *state)
+{
+    AcquireSRWLockExclusive(&state_lock);
+    if (!state) memset(current_state + index, 0, sizeof(*state));
+    else
     {
-        if (!controllers[i - 1].device) *free_slot = i - 1;
-        else if (!wcsicmp(device_path, controllers[i - 1].device_path)) return TRUE;
+        memcpy(current_state + index, state, sizeof(*state));
+        if (!++current_state[index].dwPacketNumber) ++current_state[index].dwPacketNumber;
     }
-    return FALSE;
+    ReleaseSRWLockExclusive(&state_lock);
+}
+
+static BOOL get_current_state(UINT index, XINPUT_STATE *state)
+{
+    AcquireSRWLockShared(&state_lock);
+    memcpy(state, current_state + index, sizeof(*state));
+    ReleaseSRWLockShared(&state_lock);
+
+    return state->dwPacketNumber;
 }
 
 static void check_value_caps(struct xinput_controller *controller, USHORT usage, HIDP_VALUE_CAPS *caps)
@@ -332,31 +317,34 @@ static DWORD HID_set_state(struct xinput_controller *controller, XINPUT_VIBRATIO
 
     ret = HidD_SetOutputReport(controller->device, report_buf, report_len);
     if (!ret) WARN("HidD_SetOutputReport failed with error %lu\n", GetLastError());
-    return 0;
 
     return ERROR_SUCCESS;
 }
 
 static void controller_destroy(struct xinput_controller *controller, BOOL already_removed);
 
-static void controller_enable(struct xinput_controller *controller)
+/* enable an opened controller, xinput_cs must be held */
+static BOOL controller_enable(struct xinput_controller *controller)
 {
     ULONG report_len = controller->hid.caps.InputReportByteLength;
     char *report_buf = controller->hid.input_report_buf;
     XINPUT_VIBRATION state = controller->vibration;
     BOOL ret;
 
-    if (controller->enabled) return;
+    if (controller->enabled) return TRUE;
     if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state);
-    controller->enabled = TRUE;
 
     memset(&controller->hid.read_ovl, 0, sizeof(controller->hid.read_ovl));
-    controller->hid.read_ovl.hEvent = controller->hid.read_event;
+    controller->hid.read_ovl.hEvent = controller->read_event;
     ret = ReadFile(controller->device, report_buf, report_len, NULL, &controller->hid.read_ovl);
-    if (!ret && GetLastError() != ERROR_IO_PENDING) controller_destroy(controller, TRUE);
-    else SetEvent(update_event);
+    if (!ret && GetLastError() != ERROR_IO_PENDING) return FALSE;
+
+    controller->enabled = TRUE;
+    SetEvent(update_event);
+    return TRUE;
 }
 
+/* disable an opened controller, xinput_cs must be held */
 static void controller_disable(struct xinput_controller *controller)
 {
     XINPUT_VIBRATION state = {0};
@@ -365,37 +353,35 @@ static void controller_disable(struct xinput_controller *controller)
     if (controller->caps.Flags & XINPUT_CAPS_FFB_SUPPORTED) HID_set_state(controller, &state);
     controller->enabled = FALSE;
 
-    CancelIoEx(controller->device, &controller->hid.read_ovl);
-    WaitForSingleObject(controller->hid.read_ovl.hEvent, INFINITE);
+    if (CancelIoEx(controller->device, &controller->hid.read_ovl))
+        WaitForSingleObject(controller->hid.read_ovl.hEvent, INFINITE);
     SetEvent(update_event);
 }
 
+/* opened a new controller device, xinput_cs must be held */
 static BOOL controller_init(struct xinput_controller *controller, PHIDP_PREPARSED_DATA preparsed,
                             HIDP_CAPS *caps, HANDLE device, const WCHAR *device_path)
 {
-    HANDLE event = NULL;
+    XINPUT_STATE state = {0};
 
     controller->hid.caps = *caps;
     if (!(controller->hid.feature_report_buf = calloc(1, controller->hid.caps.FeatureReportByteLength))) goto failed;
     if (!controller_check_caps(controller, device, preparsed)) goto failed;
-    if (!(event = CreateEventW(NULL, TRUE, FALSE, NULL))) goto failed;
 
     TRACE("Found gamepad %s\n", debugstr_w(device_path));
 
     controller->hid.preparsed = preparsed;
-    controller->hid.read_event = event;
     if (!(controller->hid.input_report_buf = calloc(1, controller->hid.caps.InputReportByteLength))) goto failed;
     if (!(controller->hid.output_report_buf = calloc(1, controller->hid.caps.OutputReportByteLength))) goto failed;
 
-    memset(&controller->state, 0, sizeof(controller->state));
     memset(&controller->vibration, 0, sizeof(controller->vibration));
     lstrcpynW(controller->device_path, device_path, MAX_PATH);
     controller->enabled = FALSE;
 
-    EnterCriticalSection(&controller->crit);
     controller->device = device;
-    controller_enable(controller);
-    LeaveCriticalSection(&controller->crit);
+    if (!controller_enable(controller)) goto failed;
+
+    set_current_state(controller - controllers, &state);
     return TRUE;
 
 failed:
@@ -403,7 +389,7 @@ failed:
     free(controller->hid.output_report_buf);
     free(controller->hid.feature_report_buf);
     memset(&controller->hid, 0, sizeof(controller->hid));
-    CloseHandle(event);
+    controller->device = NULL;
     return FALSE;
 }
 
@@ -453,17 +439,13 @@ static BOOL device_is_overridden(HANDLE device)
     return disable;
 }
 
-static BOOL try_add_device(const WCHAR *device_path)
+/* open a device with the given path at the given index, xinput_cs must be held */
+static BOOL open_device_at_index(const WCHAR *device_path, int index)
 {
-    SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
     PHIDP_PREPARSED_DATA preparsed;
     HIDP_CAPS caps;
     NTSTATUS status;
     HANDLE device;
-    int i;
-
-    if (find_opened_device(device_path, &i)) return TRUE; /* already opened */
-    if (i == XUSER_MAX_COUNT) return FALSE; /* no more slots */
 
     device = CreateFileW(device_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
                          NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, NULL);
@@ -481,22 +463,53 @@ static BOOL try_add_device(const WCHAR *device_path)
         WARN("ignoring HID device, unsupported usage %04x:%04x\n", caps.UsagePage, caps.Usage);
     else if (device_is_overridden(device))
         WARN("ignoring HID device, overridden for dinput\n");
-    else if (!controller_init(&controllers[i], preparsed, &caps, device, device_path))
+    else if (!controller_init(&controllers[index], preparsed, &caps, device, device_path))
         WARN("ignoring HID device, failed to initialize\n");
     else
+    {
+        TRACE("opened device %s at index %u\n", debugstr_w(device_path), index);
         return TRUE;
+    }
 
     CloseHandle(device);
     HidD_FreePreparsedData(preparsed);
     return TRUE;
 }
 
+static BOOL find_opened_device(const WCHAR *device_path, int *slot)
+{
+    int i;
+
+    *slot = XUSER_MAX_COUNT;
+    for (i = XUSER_MAX_COUNT; i > 0; i--)
+    {
+        if (!controllers[i - 1].device) *slot = i - 1;
+        else if (!wcsicmp(device_path, controllers[i - 1].device_path))
+        {
+            *slot = i - 1;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+/* try opening a new controller device from the given path, xinput_cs must be held */
+static BOOL try_add_device(const WCHAR *device_path)
+{
+    int i;
+
+    if (find_opened_device(device_path, &i)) return TRUE; /* already opened */
+    if (i == XUSER_MAX_COUNT) return FALSE; /* no more slots */
+    return open_device_at_index(device_path, i);
+}
+
+/* try closing an open controller device with the given path, xinput_cs must be held */
 static void try_remove_device(const WCHAR *device_path)
 {
     int i;
 
     if (find_opened_device(device_path, &i))
-        controller_destroy(&controllers[i], TRUE);
+        controller_destroy(&controllers[i], FALSE);
 }
 
 static void update_controller_list(void)
@@ -504,11 +517,11 @@ static void update_controller_list(void)
     char buffer[sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_W) + MAX_PATH * sizeof(WCHAR)];
     SP_DEVICE_INTERFACE_DETAIL_DATA_W *detail = (SP_DEVICE_INTERFACE_DETAIL_DATA_W *)buffer;
     SP_DEVICE_INTERFACE_DATA iface = {sizeof(iface)};
+    GUID guid = GUID_DEVINTERFACE_WINEXINPUT;
     HDEVINFO set;
     DWORD idx;
-    GUID guid;
 
-    guid = GUID_DEVINTERFACE_WINEXINPUT;
+    EnterCriticalSection(&xinput_cs);
 
     set = SetupDiGetClassDevsW(&guid, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
     detail->cbSize = sizeof(*detail);
@@ -523,15 +536,20 @@ static void update_controller_list(void)
     }
 
     SetupDiDestroyDeviceInfoList(set);
+
+    LeaveCriticalSection(&xinput_cs);
 }
 
+/* close a possibly opened controller, xinput_cs must be held */
 static void controller_destroy(struct xinput_controller *controller, BOOL already_removed)
 {
-    EnterCriticalSection(&controller->crit);
+    set_current_state(controller - controllers, NULL);
 
     if (controller->device)
     {
-        if (!already_removed) controller_disable(controller);
+        if (already_removed) controller->enabled = FALSE;
+        else controller_disable(controller);
+
         CloseHandle(controller->device);
         controller->device = NULL;
 
@@ -541,8 +559,6 @@ static void controller_destroy(struct xinput_controller *controller, BOOL alread
         HidD_FreePreparsedData(controller->hid.preparsed);
         memset(&controller->hid, 0, sizeof(controller->hid));
     }
-
-    LeaveCriticalSection(&controller->crit);
 }
 
 static LONG sign_extend(ULONG value, const HIDP_VALUE_CAPS *caps)
@@ -560,6 +576,7 @@ static LONG scale_value(ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG
     return min + MulDiv(tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin);
 }
 
+/* read the controller state from the HID device, xinput_cs must be held */
 static void read_controller_state(struct xinput_controller *controller)
 {
     ULONG read_len, report_len = controller->hid.caps.InputReportByteLength;
@@ -586,6 +603,8 @@ static void read_controller_state(struct xinput_controller *controller)
     status = HidP_GetUsages(HidP_Input, HID_USAGE_PAGE_BUTTON, 0, buttons, &button_length, controller->hid.preparsed, report_buf, report_len);
     if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsages HID_USAGE_PAGE_BUTTON returned %#lx\n", status);
 
+    get_current_state(controller - controllers, &state);
+
     state.Gamepad.wButtons = 0;
     for (i = 0; i < button_length; i++)
     {
@@ -651,17 +670,14 @@ static void read_controller_state(struct xinput_controller *controller)
     if (status != HIDP_STATUS_SUCCESS) WARN("HidP_GetUsageValue HID_USAGE_PAGE_GENERIC / HID_USAGE_GENERIC_Z returned %#lx\n", status);
     else state.Gamepad.bLeftTrigger = scale_value(value, &controller->hid.lt_caps, 0, 255);
 
-    EnterCriticalSection(&controller->crit);
     if (controller->enabled)
     {
-        state.dwPacketNumber = controller->state.dwPacketNumber + 1;
-        controller->state = state;
+        set_current_state(controller - controllers, &state);
         memset(&controller->hid.read_ovl, 0, sizeof(controller->hid.read_ovl));
-        controller->hid.read_ovl.hEvent = controller->hid.read_event;
+        controller->hid.read_ovl.hEvent = controller->read_event;
         ret = ReadFile(controller->device, report_buf, report_len, NULL, &controller->hid.read_ovl);
         if (!ret && GetLastError() != ERROR_IO_PENDING) controller_destroy(controller, TRUE);
     }
-    LeaveCriticalSection(&controller->crit);
 }
 
 static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
@@ -669,8 +685,11 @@ static LRESULT CALLBACK xinput_devnotify_wndproc(HWND hwnd, UINT msg, WPARAM wpa
     if (msg == WM_DEVICECHANGE)
     {
         DEV_BROADCAST_DEVICEINTERFACE_W *iface = (DEV_BROADCAST_DEVICEINTERFACE_W *)lparam;
+
+        EnterCriticalSection(&xinput_cs);
         if (wparam == DBT_DEVICEARRIVAL) try_add_device(iface->dbcc_name);
         if (wparam == DBT_DEVICEREMOVECOMPLETE) try_remove_device(iface->dbcc_name);
+        LeaveCriticalSection(&xinput_cs);
     }
 
     return DefWindowProcW(hwnd, msg, wparam, lparam);
@@ -712,22 +731,20 @@ static DWORD WINAPI hid_update_thread_proc(void *param)
     {
         if (ret == count) while (PeekMessageW(&msg, hwnd, 0, 0, PM_REMOVE)) DispatchMessageW(&msg);
         if (ret == WAIT_TIMEOUT) update_controller_list();
-        if (ret < count - 1) read_controller_state(devices[ret]);
 
-        count = 0;
-        for (i = 0; i < XUSER_MAX_COUNT; ++i)
+        EnterCriticalSection(&xinput_cs);
+        if (ret < count - 1 && devices[ret]->device) read_controller_state(devices[ret]);
+        for (count = 0, i = 0; i < XUSER_MAX_COUNT; ++i)
         {
-            if (!controllers[i].device) continue;
-            EnterCriticalSection(&controllers[i].crit);
-            if (controllers[i].enabled)
+            if (controllers[i].device && controllers[i].enabled)
             {
                 devices[count] = controllers + i;
-                events[count] = controllers[i].hid.read_event;
+                events[count] = controllers[i].read_event;
                 count++;
             }
-            LeaveCriticalSection(&controllers[i].crit);
         }
         events[count++] = update_event;
+        LeaveCriticalSection(&xinput_cs);
     }
     while ((ret = MsgWaitForMultipleObjectsEx(count, events, 2000, QS_ALLINPUT, MWMO_ALERTABLE)) <= count ||
             ret == WAIT_TIMEOUT);
@@ -745,6 +762,7 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void
 {
     HANDLE thread;
     HMODULE module;
+    int i;
 
     if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (void*)hid_update_thread_proc, &module))
         WARN("Failed to increase module's reference count, error: %lu\n", GetLastError());
@@ -755,6 +773,12 @@ static BOOL WINAPI start_update_thread_once( INIT_ONCE *once, void *param, void
     update_event = CreateEventA(NULL, FALSE, FALSE, NULL);
     if (!update_event) ERR("failed to create update event, error %lu\n", GetLastError());
 
+    for (i = 0; i < XUSER_MAX_COUNT; i++)
+    {
+        controllers[i].read_event = CreateEventA(NULL, TRUE, FALSE, NULL);
+        if (!controllers[i].read_event) ERR("failed to create read event for controller %d, error %lu\n", i, GetLastError());
+    }
+
     thread = CreateThread(NULL, 0, hid_update_thread_proc, NULL, 0, NULL);
     if (!thread) ERR("failed to create update thread, error %lu\n", GetLastError());
     CloseHandle(thread);
@@ -769,26 +793,6 @@ static void start_update_thread(void)
     InitOnceExecuteOnce(&init_once, start_update_thread_once, NULL, NULL);
 }
 
-static BOOL controller_lock(struct xinput_controller *controller)
-{
-    if (!controller->device) return FALSE;
-
-    EnterCriticalSection(&controller->crit);
-
-    if (!controller->device)
-    {
-        LeaveCriticalSection(&controller->crit);
-        return FALSE;
-    }
-
-    return TRUE;
-}
-
-static void controller_unlock(struct xinput_controller *controller)
-{
-    LeaveCriticalSection(&controller->crit);
-}
-
 BOOL WINAPI DllMain(HINSTANCE inst, DWORD reason, LPVOID reserved)
 {
     TRACE("inst %p, reason %lu, reserved %p.\n", inst, reason, reserved);
@@ -815,13 +819,14 @@ void WINAPI DECLSPEC_HOTPATCH XInputEnable(BOOL enable)
     be sent */
     start_update_thread();
 
+    EnterCriticalSection(&xinput_cs);
     for (index = 0; index < XUSER_MAX_COUNT; index++)
     {
-        if (!controller_lock(&controllers[index])) continue;
-        if (enable) controller_enable(&controllers[index]);
-        else controller_disable(&controllers[index]);
-        controller_unlock(&controllers[index]);
+        if (!controllers[index].device) continue;
+        if (!enable) controller_disable(&controllers[index]);
+        else if (!controller_enable(&controllers[index])) controller_destroy(&controllers[index], TRUE);
     }
+    LeaveCriticalSection(&xinput_cs);
 }
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vibration)
@@ -833,11 +838,14 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib
     start_update_thread();
 
     if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
-    if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED;
 
-    ret = HID_set_state(&controllers[index], vibration);
-
-    controller_unlock(&controllers[index]);
+    EnterCriticalSection(&xinput_cs);
+    if (!controllers[index].device) update_controller_list();
+    if (!controllers[index].device)
+        ret = ERROR_DEVICE_NOT_CONNECTED;
+    else
+        ret = HID_set_state(&controllers[index], vibration);
+    LeaveCriticalSection(&xinput_cs);
 
     return ret;
 }
@@ -846,17 +854,21 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputSetState(DWORD index, XINPUT_VIBRATION *vib
  * XInputGetState() in the hook, so we need a wrapper. */
 static DWORD xinput_get_state(DWORD index, XINPUT_STATE *state)
 {
+    DWORD ret;
+
     if (!state) return ERROR_BAD_ARGUMENTS;
 
     start_update_thread();
 
     if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
-    if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED;
+    if (get_current_state(index, state)) return ERROR_SUCCESS;
 
-    *state = controllers[index].state;
-    controller_unlock(&controllers[index]);
+    EnterCriticalSection(&xinput_cs);
+    update_controller_list();
+    ret = get_current_state(index, state) ? ERROR_SUCCESS : ERROR_DEVICE_NOT_CONNECTED;
+    LeaveCriticalSection(&xinput_cs);
 
-    return ERROR_SUCCESS;
+    return ret;
 }
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetState(DWORD index, XINPUT_STATE *state)
@@ -975,9 +987,13 @@ static BOOL trigger_is_on(const BYTE value)
 
 static DWORD check_for_keystroke(const DWORD index, XINPUT_KEYSTROKE *keystroke)
 {
-    struct xinput_controller *controller = &controllers[index];
+    static XINPUT_GAMEPAD last_state[XUSER_MAX_COUNT];
+    static SRWLOCK keystroke_lock = SRWLOCK_INIT;
+
+    XINPUT_GAMEPAD *last = last_state + index;
     const XINPUT_GAMEPAD *cur;
     DWORD ret = ERROR_EMPTY;
+    XINPUT_STATE state;
     int i;
 
     static const struct
@@ -1002,26 +1018,27 @@ static DWORD check_for_keystroke(const DWORD index, XINPUT_KEYSTROKE *keystroke)
         /* note: guide button does not send an event */
     };
 
-    if (!controller_lock(controller)) return ERROR_DEVICE_NOT_CONNECTED;
+    if ((ret = xinput_get_state(index, &state))) return ret;
+    AcquireSRWLockExclusive(&keystroke_lock);
 
-    cur = &controller->state.Gamepad;
+    cur = &state.Gamepad;
 
     /*** buttons ***/
     for (i = 0; i < ARRAY_SIZE(buttons); ++i)
     {
-        if ((cur->wButtons & buttons[i].mask) ^ (controller->last_keystroke.wButtons & buttons[i].mask))
+        if ((cur->wButtons & buttons[i].mask) ^ (last->wButtons & buttons[i].mask))
         {
             keystroke->VirtualKey = buttons[i].vk;
             keystroke->Unicode = 0; /* unused */
             if (cur->wButtons & buttons[i].mask)
             {
                 keystroke->Flags = XINPUT_KEYSTROKE_KEYDOWN;
-                controller->last_keystroke.wButtons |= buttons[i].mask;
+                last->wButtons |= buttons[i].mask;
             }
             else
             {
                 keystroke->Flags = XINPUT_KEYSTROKE_KEYUP;
-                controller->last_keystroke.wButtons &= ~buttons[i].mask;
+                last->wButtons &= ~buttons[i].mask;
             }
             keystroke->UserIndex = index;
             keystroke->HidCode = 0;
@@ -1031,46 +1048,45 @@ static DWORD check_for_keystroke(const DWORD index, XINPUT_KEYSTROKE *keystroke)
     }
 
     /*** triggers ***/
-    if (trigger_is_on(cur->bLeftTrigger) ^ trigger_is_on(controller->last_keystroke.bLeftTrigger))
+    if (trigger_is_on(cur->bLeftTrigger) ^ trigger_is_on(last->bLeftTrigger))
     {
         keystroke->VirtualKey = VK_PAD_LTRIGGER;
         keystroke->Unicode = 0; /* unused */
         keystroke->Flags = trigger_is_on(cur->bLeftTrigger) ? XINPUT_KEYSTROKE_KEYDOWN : XINPUT_KEYSTROKE_KEYUP;
         keystroke->UserIndex = index;
         keystroke->HidCode = 0;
-        controller->last_keystroke.bLeftTrigger = cur->bLeftTrigger;
+        last->bLeftTrigger = cur->bLeftTrigger;
         ret = ERROR_SUCCESS;
         goto done;
     }
 
-    if (trigger_is_on(cur->bRightTrigger) ^ trigger_is_on(controller->last_keystroke.bRightTrigger))
+    if (trigger_is_on(cur->bRightTrigger) ^ trigger_is_on(last->bRightTrigger))
     {
         keystroke->VirtualKey = VK_PAD_RTRIGGER;
         keystroke->Unicode = 0; /* unused */
         keystroke->Flags = trigger_is_on(cur->bRightTrigger) ? XINPUT_KEYSTROKE_KEYDOWN : XINPUT_KEYSTROKE_KEYUP;
         keystroke->UserIndex = index;
         keystroke->HidCode = 0;
-        controller->last_keystroke.bRightTrigger = cur->bRightTrigger;
+        last->bRightTrigger = cur->bRightTrigger;
         ret = ERROR_SUCCESS;
         goto done;
     }
 
     /*** joysticks ***/
     ret = check_joystick_keystroke(index, keystroke, &cur->sThumbLX, &cur->sThumbLY,
-            &controller->last_keystroke.sThumbLX,
-            &controller->last_keystroke.sThumbLY, VK_PAD_LTHUMB_UP);
+            &last->sThumbLX,
+            &last->sThumbLY, VK_PAD_LTHUMB_UP);
     if (ret == ERROR_SUCCESS)
         goto done;
 
     ret = check_joystick_keystroke(index, keystroke, &cur->sThumbRX, &cur->sThumbRY,
-            &controller->last_keystroke.sThumbRX,
-            &controller->last_keystroke.sThumbRY, VK_PAD_RTHUMB_UP);
+            &last->sThumbRX,
+            &last->sThumbRY, VK_PAD_RTHUMB_UP);
     if (ret == ERROR_SUCCESS)
         goto done;
 
 done:
-    controller_unlock(controller);
-
+    ReleaseSRWLockExclusive(&keystroke_lock);
     return ret;
 }
 
@@ -1106,25 +1122,34 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilities(DWORD index, DWORD flags, X
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetDSoundAudioDeviceGuids(DWORD index, GUID *render_guid, GUID *capture_guid)
 {
+    DWORD ret;
+
     FIXME("index %lu, render_guid %s, capture_guid %s stub!\n", index, debugstr_guid(render_guid),
           debugstr_guid(capture_guid));
 
     if (index >= XUSER_MAX_COUNT || !render_guid || !capture_guid) return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].device) return ERROR_DEVICE_NOT_CONNECTED;
 
-    return ERROR_NOT_SUPPORTED;
+    EnterCriticalSection(&xinput_cs);
+    ret = controllers[index].device ? ERROR_NOT_SUPPORTED : ERROR_DEVICE_NOT_CONNECTED;
+    LeaveCriticalSection(&xinput_cs);
+
+    return ret;
 }
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetBatteryInformation(DWORD index, BYTE type, XINPUT_BATTERY_INFORMATION* battery)
 {
     static int once;
+    DWORD ret;
 
     if (!once++) FIXME("index %lu, type %u, battery %p.\n", index, type, battery);
 
     if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
-    if (!controllers[index].device) return ERROR_DEVICE_NOT_CONNECTED;
 
-    return ERROR_NOT_SUPPORTED;
+    EnterCriticalSection(&xinput_cs);
+    ret = controllers[index].device ? ERROR_NOT_SUPPORTED : ERROR_DEVICE_NOT_CONNECTED;
+    LeaveCriticalSection(&xinput_cs);
+
+    return ret;
 }
 
 DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilitiesEx(DWORD unk, DWORD index, DWORD flags, XINPUT_CAPABILITIES_EX *caps)
@@ -1138,9 +1163,11 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilitiesEx(DWORD unk, DWORD index, D
 
     if (index >= XUSER_MAX_COUNT) return ERROR_BAD_ARGUMENTS;
 
-    if (!controller_lock(&controllers[index])) return ERROR_DEVICE_NOT_CONNECTED;
-
-    if (flags & XINPUT_FLAG_GAMEPAD && controllers[index].caps.SubType != XINPUT_DEVSUBTYPE_GAMEPAD)
+    EnterCriticalSection(&xinput_cs);
+    if (!controllers[index].device) update_controller_list();
+    if (!controllers[index].device)
+        ret = ERROR_DEVICE_NOT_CONNECTED;
+    else if (flags & XINPUT_FLAG_GAMEPAD && controllers[index].caps.SubType != XINPUT_DEVSUBTYPE_GAMEPAD)
         ret = ERROR_DEVICE_NOT_CONNECTED;
     else if (!HidD_GetAttributes(controllers[index].device, &attr))
         ret = ERROR_DEVICE_NOT_CONNECTED;
@@ -1152,7 +1179,7 @@ DWORD WINAPI DECLSPEC_HOTPATCH XInputGetCapabilitiesEx(DWORD unk, DWORD index, D
         caps->VersionNumber = attr.VersionNumber;
     }
 
-    controller_unlock(&controllers[index]);
+    LeaveCriticalSection(&xinput_cs);
 
     return ret;
 }
diff --git a/include/config.h.in b/include/config.h.in
index 551771eaa6ac..831e35a23d9c 100644
--- a/include/config.h.in
+++ b/include/config.h.in
@@ -93,9 +93,6 @@
 /* Define to 1 if you have the <gettext-po.h> header file. */
 #undef HAVE_GETTEXT_PO_H
 
-/* Define to 1 if you have the 'gnutls_cipher_init' function. */
-#undef HAVE_GNUTLS_CIPHER_INIT
-
 /* Define if we have the libgphoto2_port development environment */
 #undef HAVE_GPHOTO2_PORT
 
@@ -162,6 +159,9 @@
 /* Define to 1 if you have the <linux/cdrom.h> header file. */
 #undef HAVE_LINUX_CDROM_H
 
+/* Define to 1 if you have the <linux/errqueue.h> header file. */
+#undef HAVE_LINUX_ERRQUEUE_H
+
 /* Define to 1 if you have the <linux/filter.h> header file. */
 #undef HAVE_LINUX_FILTER_H
 
diff --git a/include/msvcrt/setjmp.h b/include/msvcrt/setjmp.h
index ae00dc6a8c82..7267d0252c0d 100644
--- a/include/msvcrt/setjmp.h
+++ b/include/msvcrt/setjmp.h
@@ -28,18 +28,18 @@
 
 typedef struct __JUMP_BUFFER
 {
-    unsigned long Ebp;
-    unsigned long Ebx;
-    unsigned long Edi;
-    unsigned long Esi;
-    unsigned long Esp;
-    unsigned long Eip;
-    unsigned long Registration;
-    unsigned long TryLevel;
+    __msvcrt_ulong Ebp;
+    __msvcrt_ulong Ebx;
+    __msvcrt_ulong Edi;
+    __msvcrt_ulong Esi;
+    __msvcrt_ulong Esp;
+    __msvcrt_ulong Eip;
+    __msvcrt_ulong Registration;
+    __msvcrt_ulong TryLevel;
     /* Start of new struct members */
-    unsigned long Cookie;
-    unsigned long UnwindFunc;
-    unsigned long UnwindData[6];
+    __msvcrt_ulong Cookie;
+    __msvcrt_ulong UnwindFunc;
+    __msvcrt_ulong UnwindData[6];
 } _JUMP_BUFFER;
 
 #define _JBLEN 16
@@ -65,7 +65,7 @@ typedef _CRT_ALIGN(16) struct _JUMP_BUFFER
     unsigned __int64 R14;
     unsigned __int64 R15;
     unsigned __int64 Rip;
-    unsigned long MxCsr;
+    __msvcrt_ulong MxCsr;
     unsigned short FpCsr;
     unsigned short Spare;
     SETJMP_FLOAT128  Xmm6;
@@ -87,18 +87,18 @@ typedef SETJMP_FLOAT128 _JBTYPE;
 
 typedef struct _JUMP_BUFFER
 {
-    unsigned long Frame;
-    unsigned long R4;
-    unsigned long R5;
-    unsigned long R6;
-    unsigned long R7;
-    unsigned long R8;
-    unsigned long R9;
-    unsigned long R10;
-    unsigned long R11;
-    unsigned long Sp;
-    unsigned long Pc;
-    unsigned long Fpscr;
+    __msvcrt_ulong Frame;
+    __msvcrt_ulong R4;
+    __msvcrt_ulong R5;
+    __msvcrt_ulong R6;
+    __msvcrt_ulong R7;
+    __msvcrt_ulong R8;
+    __msvcrt_ulong R9;
+    __msvcrt_ulong R10;
+    __msvcrt_ulong R11;
+    __msvcrt_ulong Sp;
+    __msvcrt_ulong Pc;
+    __msvcrt_ulong Fpscr;
     unsigned long long D[8];
 } _JUMP_BUFFER;
 
@@ -124,8 +124,8 @@ typedef struct _JUMP_BUFFER
     unsigned __int64 Fp;
     unsigned __int64 Lr;
     unsigned __int64 Sp;
-    unsigned long Fpcr;
-    unsigned long Fpsr;
+    __msvcrt_ulong Fpcr;
+    __msvcrt_ulong Fpsr;
     double D[8];
 } _JUMP_BUFFER;
 
diff --git a/include/ntuser.h b/include/ntuser.h
index 2bbf77a4cf1e..c3c4c8cdcf2f 100644
--- a/include/ntuser.h
+++ b/include/ntuser.h
@@ -881,6 +881,8 @@ W32KAPI BOOL    WINAPI NtUserGetObjectInformation( HANDLE handle, INT index, voi
 W32KAPI HWND    WINAPI NtUserGetOpenClipboardWindow(void);
 W32KAPI BOOL    WINAPI NtUserGetPointerInfoList( UINT32 id, POINTER_INPUT_TYPE type, UINT_PTR, UINT_PTR, SIZE_T size,
                                                  UINT32 *entry_count, UINT32 *pointer_count, void *pointer_info );
+W32KAPI BOOL    WINAPI NtUserGetPointerType( UINT32 id, POINTER_INPUT_TYPE *type );
+W32KAPI BOOL    WINAPI NtUserGetPointerDeviceRects( HANDLE handle, RECT *device_rect, RECT *display_rect );
 W32KAPI INT     WINAPI NtUserGetPriorityClipboardFormat( UINT *list, INT count );
 W32KAPI BOOL    WINAPI NtUserGetProcessDefaultLayout( ULONG *layout );
 W32KAPI ULONG   WINAPI NtUserGetProcessDpiAwarenessContext( HANDLE process );
diff --git a/include/peninputpanel.idl b/include/peninputpanel.idl
index 0d1188705d26..cfb179c09a64 100644
--- a/include/peninputpanel.idl
+++ b/include/peninputpanel.idl
@@ -195,6 +195,9 @@ interface ITextInputPanel : IUnknown
 }
 
 [
+    progid("TextInputPanel.TextInputPanel.1"),
+    vi_progid("TextInputPanel.TextInputPanel"),
+    threading(apartment),
     uuid(f9b189d7-228b-4f2b-8650-b97f59e02c8c)
 ]
 coclass TextInputPanel
diff --git a/include/rpcasync.h b/include/rpcasync.h
index e51177c9859e..e429c3b049b9 100644
--- a/include/rpcasync.h
+++ b/include/rpcasync.h
@@ -22,6 +22,10 @@
 # include <windef.h>
 #endif
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 #ifdef __RPC_WIN64__
 # pragma pack(push,8)
 #endif
@@ -165,10 +169,6 @@ typedef struct _RPC_ASYNC_STATE
 # pragma pack(pop)
 #endif
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 RPCRTAPI RPC_STATUS RPC_ENTRY RpcAsyncInitializeHandle(PRPC_ASYNC_STATE,unsigned int);
 RPCRTAPI RPC_STATUS RPC_ENTRY RpcAsyncRegisterInfo(PRPC_ASYNC_STATE);
 RPCRTAPI RPC_STATUS RPC_ENTRY RpcAsyncGetCallStatus(PRPC_ASYNC_STATE);
diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h
index 97c646d6ec9e..630e035a5896 100644
--- a/include/wine/gdi_driver.h
+++ b/include/wine/gdi_driver.h
@@ -218,7 +218,7 @@ struct gdi_dc_funcs
 };
 
 /* increment this when you change the DC function table */
-#define WINE_GDI_DRIVER_VERSION 108
+#define WINE_GDI_DRIVER_VERSION 110
 
 #define GDI_PRIORITY_NULL_DRV        0  /* null driver */
 #define GDI_PRIORITY_FONT_DRV      100  /* any font driver */
@@ -404,7 +404,7 @@ struct user_driver_funcs
     BOOL    (*pProcessEvents)(DWORD);
     void    (*pReleaseDC)(HWND,HDC);
     BOOL    (*pScrollDC)(HDC,INT,INT,HRGN);
-    void    (*pSetCapture)(HWND,UINT);
+    void    (*pSetCapture)(HWND,UINT,HWND);
     void    (*pSetDesktopWindow)(HWND);
     void    (*pActivateWindow)(HWND,HWND);
     void    (*pSetLayeredWindowAttributes)(HWND,COLORREF,BYTE,DWORD);
@@ -420,6 +420,7 @@ struct user_driver_funcs
     BOOL    (*pWindowPosChanging)(HWND,UINT,BOOL,const struct window_rects *);
     BOOL    (*pGetWindowStyleMasks)(HWND,UINT,UINT,UINT*,UINT*);
     BOOL    (*pGetWindowStateUpdates)(HWND,UINT*,UINT*,RECT*,HWND*);
+    struct client_surface *(*pCreateClientSurface)(HWND,int);
     BOOL    (*pCreateWindowSurface)(HWND,BOOL,const RECT *,struct window_surface**);
     void    (*pMoveWindowBits)(HWND,const struct window_rects *,const struct window_rects *,const RECT *);
     void    (*pWindowPosChanged)(HWND,HWND,HWND,UINT,const struct window_rects*,struct window_surface*);
diff --git a/include/wine/opengl_driver.h b/include/wine/opengl_driver.h
index af745e038a6b..3c71db20fd25 100644
--- a/include/wine/opengl_driver.h
+++ b/include/wine/opengl_driver.h
@@ -75,6 +75,7 @@ struct opengl_client_context
     UINT64                      unix_funcs;
     DWORD                       current_tid;                            /* thread that the context is current in */
     GLenum                      last_error;
+    GLint                       context_flags;
     GLint                       profile_mask;
     int                         major_version;
     int                         minor_version;
@@ -111,7 +112,7 @@ struct __GLsync
 #include "wine/gdi_driver.h"
 
 /* Wine internal opengl driver version, needs to be bumped upon opengl_funcs changes. */
-#define WINE_OPENGL_DRIVER_VERSION 37
+#define WINE_OPENGL_DRIVER_VERSION 38
 
 struct opengl_drawable;
 
@@ -119,7 +120,6 @@ struct opengl_context
 {
     HGLRC                       client_context;     /* client side context pointer */
     void                       *driver_private;     /* driver context / private data */
-    void                       *internal_context;   /* driver context for win32u internal use */
     int                         format;             /* pixel format of the context */
     struct opengl_drawable     *draw;               /* currently bound draw surface */
     struct opengl_drawable     *read;               /* currently bound read surface */
@@ -146,9 +146,8 @@ struct opengl_funcs
     void (*p_get_pixel_formats)( struct wgl_pixel_format *formats, UINT max_formats, UINT *num_formats, UINT *num_onscreen_formats );
     BOOL (*p_query_renderer)( UINT attribute, void *value );
     BOOL (*p_context_flush)( struct opengl_context *context, void (*flush)(void), UINT flags );
-    BOOL (*p_context_create)( struct opengl_context *context, HDC hdc, struct opengl_context *share, const int *attribs );
+    BOOL (*p_context_create)( struct opengl_context *context, HDC hdc, const int *attribs );
     BOOL (*p_context_destroy)( struct opengl_context *context );
-    BOOL (*p_context_reset)( struct opengl_context *context, struct opengl_context *share, const int *attribs );
     BOOL (*p_pbuffer_create)( HDC hdc, int format, int width, int height, const int *attribs, HPBUFFERARB client_pbuffer );
     void *egl_handle;
 };
@@ -190,8 +189,6 @@ struct opengl_drawable_funcs
     void (*flush)( struct opengl_drawable *iface, UINT flags );
     /* swap and present the drawable buffers, called from render thread */
     BOOL (*swap)( struct opengl_drawable *iface );
-    /* drawable is being unset or made current, called from render thread */
-    void (*set_context)( struct opengl_drawable *iface, void *private );
 };
 
 /* flags for opengl_drawable flush */
@@ -244,7 +241,7 @@ struct opengl_driver_funcs
     UINT (*p_init_pixel_formats)(UINT*);
     BOOL (*p_describe_pixel_format)(int,struct wgl_pixel_format*);
     void (*p_init_extensions)( struct opengl_funcs *funcs, BOOLEAN extensions[GL_EXTENSION_COUNT] );
-    BOOL (*p_surface_create)( HWND hwnd, int format, struct opengl_drawable **drawable );
+    BOOL (*p_surface_create)( struct client_surface *client, int format, struct opengl_drawable **drawable );
     BOOL (*p_context_create)( int format, void *share, const int *attribs, void **context );
     BOOL (*p_context_destroy)(void*);
     BOOL (*p_make_current)( struct opengl_drawable *draw, struct opengl_drawable *read, void *private );
@@ -252,6 +249,7 @@ struct opengl_driver_funcs
                               GLint max_level, GLsizei *width, GLsizei *height, struct opengl_drawable **drawable );
     BOOL (*p_pbuffer_updated)( HDC hdc, struct opengl_drawable *drawable, GLenum cube_face, GLint mipmap_level );
     UINT (*p_pbuffer_bind)( HDC hdc, struct opengl_drawable *drawable, GLenum buffer );
+    BOOL (*p_null_surface_create)( int format, struct opengl_drawable **drawable );
 };
 
 #endif /* WINE_UNIX_LIB */
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 7904152d18e1..c74b015747a0 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1167,10 +1167,11 @@ struct get_startup_info_reply
 {
     struct reply_header __header;
     data_size_t  info_size;
+    int          debugged;
     unsigned short machine;
     /* VARARG(info,startup_info,info_size); */
     /* VARARG(env,unicode_str); */
-    char __pad_14[2];
+    char __pad_18[6];
 };
 
 
@@ -7148,6 +7149,6 @@ union generic_reply
     struct d3dkmt_mutex_release_reply d3dkmt_mutex_release_reply;
 };
 
-#define SERVER_PROTOCOL_VERSION 951
+#define SERVER_PROTOCOL_VERSION 952
 
 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */
diff --git a/include/wine/vulkan_driver.h b/include/wine/vulkan_driver.h
index 9c18f6d20dbb..d2209a3ef543 100644
--- a/include/wine/vulkan_driver.h
+++ b/include/wine/vulkan_driver.h
@@ -89,7 +89,7 @@ struct VkDevice_T
 #include "wine/list.h"
 
 /* Wine internal vulkan driver version, needs to be bumped upon vulkan_funcs changes. */
-#define WINE_VULKAN_DRIVER_VERSION 47
+#define WINE_VULKAN_DRIVER_VERSION 48
 
 struct vulkan_object
 {
@@ -358,7 +358,7 @@ struct vulkan_funcs
 struct client_surface;
 struct vulkan_driver_funcs
 {
-    VkResult (*p_vulkan_surface_create)(HWND, const struct vulkan_instance *, VkSurfaceKHR *, struct client_surface **);
+    VkResult (*p_vulkan_surface_create)(struct client_surface *, const struct vulkan_instance *, VkSurfaceKHR *);
     VkBool32 (*p_get_physical_device_presentation_support)(struct vulkan_physical_device *, uint32_t);
     void (*p_map_instance_extensions)( struct vulkan_instance_extensions *extensions );
     void (*p_map_device_extensions)( struct vulkan_device_extensions *extensions );
diff --git a/include/winternl.h b/include/winternl.h
index bed72e83ce4f..81dc3db2b740 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -201,8 +201,9 @@ typedef struct _RTL_USER_PROCESS_PARAMETERS
     ULONG               LoaderThreads;
 } RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
 
-/* value for Flags field (FIXME: not the correct name) */
-#define PROCESS_PARAMS_FLAG_NORMALIZED 1
+/* value for Flags field (FIXME: not the correct names) */
+#define PROCESS_PARAMS_FLAG_NORMALIZED        0x00000001
+#define PROCESS_PARAMS_IMAGE_KEY_MISSING      0x00004000
 
 typedef struct _PEB_LDR_DATA
 {
diff --git a/libs/ffmpeg/LICENSE.md b/libs/ffmpeg/LICENSE.md
new file mode 100644
index 000000000000..371b0913ce7c
--- /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 000000000000..35ccba4157a6
--- /dev/null
+++ b/libs/ffmpeg/Makefile.in
@@ -0,0 +1,201 @@
+STATICLIB = libffmpeg.a
+EXTRADEFS = $(FFMPEG_PE_CFLAGS) -DHAVE_AV_CONFIG_H
+
+SOURCES = \
+	config.h \
+	libavutil/aarch64/cpu.c \
+	libavutil/aarch64/crc.S \
+	libavutil/aarch64/float_dsp_init.c \
+	libavutil/aarch64/float_dsp_neon.S \
+	libavutil/aarch64/tx_float_init.c \
+	libavutil/aarch64/tx_float_neon.S \
+	libavutil/adler32.c \
+	libavutil/aes.c \
+	libavutil/aes_ctr.c \
+	libavutil/ambient_viewing_environment.c \
+	libavutil/arm/cpu.c \
+	libavutil/arm/float_dsp_init_arm.c \
+	libavutil/arm/float_dsp_init_neon.c \
+	libavutil/arm/float_dsp_init_vfp.c \
+	libavutil/arm/float_dsp_neon.S \
+	libavutil/arm/float_dsp_vfp.S \
+	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/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/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/x86/cpu.c \
+	libavutil/x86/cpuid.asm \
+	libavutil/x86/crc.asm \
+	libavutil/x86/fixed_dsp.asm \
+	libavutil/x86/fixed_dsp_init.c \
+	libavutil/x86/float_dsp.asm \
+	libavutil/x86/float_dsp_init.c \
+	libavutil/x86/imgutils.asm \
+	libavutil/x86/imgutils_init.c \
+	libavutil/x86/lls.asm \
+	libavutil/x86/lls_init.c \
+	libavutil/x86/tx_float.asm \
+	libavutil/x86/tx_float_init.c \
+	libavutil/xga_font_data.c \
+	libavutil/xtea.c \
+	libswresample/aarch64/audio_convert_init.c \
+	libswresample/aarch64/audio_convert_neon.S \
+	libswresample/aarch64/resample.S \
+	libswresample/aarch64/resample_init.c \
+	libswresample/arm/audio_convert_init.c \
+	libswresample/arm/audio_convert_neon.S \
+	libswresample/arm/resample.S \
+	libswresample/arm/resample_init.c \
+	libswresample/audioconvert.c \
+	libswresample/dither.c \
+	libswresample/options.c \
+	libswresample/rematrix.c \
+	libswresample/resample.c \
+	libswresample/resample_dsp.c \
+	libswresample/swresample.c \
+	libswresample/swresample_frame.c \
+	libswresample/version.c \
+	libswresample/x86/audio_convert.asm \
+	libswresample/x86/audio_convert_init.c \
+	libswresample/x86/rematrix.asm \
+	libswresample/x86/rematrix_init.c \
+	libswresample/x86/resample.asm \
+	libswresample/x86/resample_init.c \
+	libswscale/aarch64/hscale.S \
+	libswscale/aarch64/input.S \
+	libswscale/aarch64/output.S \
+	libswscale/aarch64/range_convert_neon.S \
+	libswscale/aarch64/rgb2rgb.c \
+	libswscale/aarch64/rgb2rgb_neon.S \
+	libswscale/aarch64/swscale.c \
+	libswscale/aarch64/swscale_unscaled.c \
+	libswscale/aarch64/swscale_unscaled_neon.S \
+	libswscale/aarch64/xyz2rgb_neon.S \
+	libswscale/aarch64/yuv2rgb_neon.S \
+	libswscale/alphablend.c \
+	libswscale/arm/hscale.S \
+	libswscale/arm/output.S \
+	libswscale/arm/swscale.c \
+	libswscale/arm/swscale_unscaled.c \
+	libswscale/arm/yuv2rgb_neon.S \
+	libswscale/cms.c \
+	libswscale/csputils.c \
+	libswscale/format.c \
+	libswscale/gamma.c \
+	libswscale/graph.c \
+	libswscale/hscale.c \
+	libswscale/hscale_fast_bilinear.c \
+	libswscale/input.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/x86/hscale_fast_bilinear_simd.c \
+	libswscale/x86/input.asm \
+	libswscale/x86/ops.c \
+	libswscale/x86/ops_float.asm \
+	libswscale/x86/ops_int.asm \
+	libswscale/x86/output.asm \
+	libswscale/x86/range_convert.asm \
+	libswscale/x86/rgb2rgb.c \
+	libswscale/x86/rgb_2_rgb.asm \
+	libswscale/x86/scale.asm \
+	libswscale/x86/scale_avx2.asm \
+	libswscale/x86/swscale.c \
+	libswscale/x86/yuv2rgb.c \
+	libswscale/x86/yuv2yuvX.asm \
+	libswscale/x86/yuv_2_rgb.asm \
+	libswscale/yuv2rgb.c
diff --git a/libs/ffmpeg/VERSION b/libs/ffmpeg/VERSION
new file mode 100644
index 000000000000..0e79152459e0
--- /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 000000000000..a40bbe663716
--- /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 000000000000..f689d04d5149
--- /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 000000000000..49178cc252e3
--- /dev/null
+++ b/libs/ffmpeg/config.h
@@ -0,0 +1,892 @@
+/* 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 1
+#define HAVE_ARMV6 1
+#define HAVE_ARMV6T2 1
+#define HAVE_ARMV8 1
+#define HAVE_ARM_CRC 1
+#define HAVE_DOTPROD 1
+#define HAVE_I8MM 0
+#define HAVE_NEON 1
+#define HAVE_VFP 1
+#define HAVE_VFPV3 1
+#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 1
+#define HAVE_AVX2 1
+#define HAVE_AVX512 1
+#define HAVE_AVX512ICL 1
+#define HAVE_FMA3 0
+#define HAVE_FMA4 0
+#define HAVE_MMX 1
+#define HAVE_MMXEXT 1
+#define HAVE_SSE 1
+#define HAVE_SSE2 1
+#define HAVE_SSE3 1
+#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 1
+#define HAVE_ARMV6_EXTERNAL 1
+#define HAVE_ARMV6T2_EXTERNAL 1
+#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 1
+#define HAVE_AMD3DNOW_EXTERNAL 0
+#define HAVE_AMD3DNOWEXT_EXTERNAL 0
+#define HAVE_AVX_EXTERNAL 1
+#define HAVE_AVX2_EXTERNAL 1
+#define HAVE_AVX512_EXTERNAL 1
+#define HAVE_AVX512ICL_EXTERNAL 1
+#define HAVE_FMA3_EXTERNAL 1
+#define HAVE_FMA4_EXTERNAL 1
+#define HAVE_MMX_EXTERNAL 0
+#define HAVE_MMXEXT_EXTERNAL 1
+#define HAVE_SSE_EXTERNAL 1
+#define HAVE_SSE2_EXTERNAL 1
+#define HAVE_SSE3_EXTERNAL 1
+#define HAVE_SSE4_EXTERNAL 1
+#define HAVE_SSE42_EXTERNAL 1
+#define HAVE_SSSE3_EXTERNAL 1
+#define HAVE_XOP_EXTERNAL 1
+#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 1
+#define HAVE_ARMV6_INLINE 1
+#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 1
+#define HAVE_SIMD_ALIGN_32 1
+#define HAVE_SIMD_ALIGN_64 1
+#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 1
+#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 1
+#define HAVE_INTRINSICS_SSE2 1
+#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 0
+#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 1
+#define HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE 1
+#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 0
+#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 1
+#define HAVE_XFORM_ASM 0
+#define HAVE_XMM_CLOBBERS 1
+#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
+
+/* tweaks for Wine build */
+
+#if defined __aarch64__
+
+#undef  ARCH_AARCH64
+#define ARCH_AARCH64 1
+#undef  HAVE_FAST_64BIT
+#define HAVE_FAST_64BIT 1
+#undef  HAVE_FAST_FLOAT16
+#define HAVE_FAST_FLOAT16 1
+#undef  CONFIG_PIC
+#define CONFIG_PIC 1
+
+#elif defined __arm64ec__
+
+/* FIXME */
+
+#elif defined __arm__
+
+#undef  ARCH_ARM
+#define ARCH_ARM 1
+#undef  HAVE_FAST_FLOAT16
+#define HAVE_FAST_FLOAT16 1
+
+#elif defined __x86_64__ && defined HAVE_NASM && defined __WINE_PE_BUILD
+
+#undef  ARCH_X86
+#define ARCH_X86 1
+#undef  ARCH_X86_64
+#define ARCH_X86_64 1
+#undef  HAVE_FAST_64BIT
+#define HAVE_FAST_64BIT 1
+#undef  HAVE_MMX_INLINE
+#define HAVE_MMX_INLINE 1
+#undef  HAVE_MMXEXT_INLINE
+#define HAVE_MMXEXT_INLINE 1
+#undef  HAVE_X86ASM
+#define HAVE_X86ASM 1
+#define PIC 1
+
+#elif defined __i386__ && defined HAVE_NASM && defined __WINE_PE_BUILD
+
+#undef  ARCH_X86
+#define ARCH_X86 1
+#undef  ARCH_X86_32
+#define ARCH_X86_32 1
+#undef  HAVE_MMX_INLINE
+#define HAVE_MMX_INLINE 1
+#undef  HAVE_MMXEXT_INLINE
+#define HAVE_MMXEXT_INLINE 1
+#undef  HAVE_X86ASM
+#define HAVE_X86ASM 1
+#define PIC 0
+
+#undef EXTERN_PREFIX
+#define EXTERN_PREFIX "_"
+
+#endif
+#endif /* FFMPEG_CONFIG_H */
diff --git a/libs/ffmpeg/config_components.h b/libs/ffmpeg/config_components.h
new file mode 100644
index 000000000000..354bb86fa27b
--- /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/arm/mathops.h b/libs/ffmpeg/libavcodec/arm/mathops.h
new file mode 100644
index 000000000000..9d0385db6cc8
--- /dev/null
+++ b/libs/ffmpeg/libavcodec/arm/mathops.h
@@ -0,0 +1,86 @@
+/*
+ * simple math operations
+ * 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_ARM_MATHOPS_H
+#define AVCODEC_ARM_MATHOPS_H
+
+#include <stdint.h>
+#include "config.h"
+#include "libavutil/common.h"
+
+#if HAVE_INLINE_ASM
+
+#if HAVE_ARMV6_INLINE
+#define MULH MULH
+static inline av_const int MULH(int a, int b)
+{
+    int r;
+    __asm__ ("smmul %0, %1, %2" : "=r"(r) : "r"(a), "r"(b));
+    return r;
+}
+
+#define FASTDIV FASTDIV
+static av_always_inline av_const int FASTDIV(int a, int b)
+{
+    int r;
+    __asm__ ("cmp     %2, #2               \n\t"
+             "ldr     %0, [%3, %2, lsl #2] \n\t"
+             "ite     le                   \n\t"
+             "lsrle   %0, %1, #1           \n\t"
+             "smmulgt %0, %0, %1           \n\t"
+             : "=&r"(r) : "r"(a), "r"(b), "r"(ff_inverse) : "cc");
+    return r;
+}
+
+#else /* HAVE_ARMV6_INLINE */
+
+#define FASTDIV FASTDIV
+static av_always_inline av_const int FASTDIV(int a, int b)
+{
+    int r, t;
+    __asm__ ("umull %1, %0, %2, %3"
+             : "=&r"(r), "=&r"(t) : "r"(a), "r"(ff_inverse[b]));
+    return r;
+}
+#endif
+
+#define MLS64(d, a, b) MAC64(d, -(a), b)
+
+#if HAVE_ARMV5TE_INLINE
+
+/* signed 16x16 -> 32 multiply add accumulate */
+#   define MAC16(rt, ra, rb)                                            \
+    __asm__ ("smlabb %0, %1, %2, %0" : "+r"(rt) : "r"(ra), "r"(rb));
+
+/* signed 16x16 -> 32 multiply */
+#   define MUL16 MUL16
+static inline av_const int MUL16(int ra, int rb)
+{
+    int rt;
+    __asm__ ("smulbb %0, %1, %2" : "=r"(rt) : "r"(ra), "r"(rb));
+    return rt;
+}
+
+#endif
+
+#endif /* HAVE_INLINE_ASM */
+
+#endif /* AVCODEC_ARM_MATHOPS_H */
diff --git a/libs/ffmpeg/libavcodec/defs.h b/libs/ffmpeg/libavcodec/defs.h
new file mode 100644
index 000000000000..b13e983b13a9
--- /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 000000000000..a22c9755aed2
--- /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 000000000000..64431b8a1597
--- /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 000000000000..98c0d7e51f09
--- /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 000000000000..7eecd9651fca
--- /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/libavcodec/x86/mathops.h b/libs/ffmpeg/libavcodec/x86/mathops.h
new file mode 100644
index 000000000000..ca7e2dffc107
--- /dev/null
+++ b/libs/ffmpeg/libavcodec/x86/mathops.h
@@ -0,0 +1,153 @@
+/*
+ * simple math operations
+ * 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_X86_MATHOPS_H
+#define AVCODEC_X86_MATHOPS_H
+
+#include "config.h"
+
+#include "libavutil/common.h"
+#include "libavutil/x86/asm.h"
+
+#if HAVE_INLINE_ASM
+
+#if ARCH_X86_32
+
+#define MULL MULL
+static av_always_inline av_const int MULL(int a, int b, unsigned shift)
+{
+    int rt, dummy;
+    if (__builtin_constant_p(shift))
+    __asm__ (
+        "imull %3               \n\t"
+        "shrdl %4, %%edx, %%eax \n\t"
+        :"=a"(rt), "=d"(dummy)
+        :"a"(a), "rm"(b), "i"(shift & 0x1F)
+    );
+    else
+        __asm__ (
+            "imull %3               \n\t"
+            "shrdl %4, %%edx, %%eax \n\t"
+            :"=a"(rt), "=d"(dummy)
+            :"a"(a), "rm"(b), "c"((uint8_t)shift)
+        );
+    return rt;
+}
+
+#define MULH MULH
+static av_always_inline av_const int MULH(int a, int b)
+{
+    int rt, dummy;
+    __asm__ (
+        "imull %3"
+        :"=d"(rt), "=a"(dummy)
+        :"a"(a), "rm"(b)
+    );
+    return rt;
+}
+
+#define MUL64 MUL64
+static av_always_inline av_const int64_t MUL64(int a, int b)
+{
+    int64_t rt;
+    __asm__ (
+        "imull %2"
+        :"=A"(rt)
+        :"a"(a), "rm"(b)
+    );
+    return rt;
+}
+
+#endif /* ARCH_X86_32 */
+
+#if HAVE_I686
+/* median of 3 */
+#define mid_pred mid_pred
+static inline av_const int mid_pred(int a, int b, int c)
+{
+    int i=b;
+    __asm__ (
+        "cmp    %2, %1 \n\t"
+        "cmovg  %1, %0 \n\t"
+        "cmovg  %2, %1 \n\t"
+        "cmp    %3, %1 \n\t"
+        "cmovl  %3, %1 \n\t"
+        "cmp    %1, %0 \n\t"
+        "cmovg  %1, %0 \n\t"
+        :"+&r"(i), "+&r"(a)
+        :"r"(b), "r"(c)
+    );
+    return i;
+}
+
+#if HAVE_6REGS
+#define COPY3_IF_LT(x, y, a, b, c, d)\
+__asm__ volatile(\
+    "cmpl  %0, %3       \n\t"\
+    "cmovl %3, %0       \n\t"\
+    "cmovl %4, %1       \n\t"\
+    "cmovl %5, %2       \n\t"\
+    : "+&r" (x), "+&r" (a), "+r" (c)\
+    : "r" (y), "r" (b), "r" (d)\
+);
+#endif /* HAVE_6REGS */
+
+#endif /* HAVE_I686 */
+
+#define MASK_ABS(mask, level)                   \
+    __asm__ ("cdq                    \n\t"      \
+             "xorl %1, %0            \n\t"      \
+             "subl %1, %0            \n\t"      \
+             : "+a"(level), "=&d"(mask))
+
+// avoid +32 for shift optimization (gcc should do that ...)
+#define NEG_SSR32 NEG_SSR32
+static inline  int32_t NEG_SSR32( int32_t a, int8_t s){
+    if (__builtin_constant_p(s))
+    __asm__ ("sarl %1, %0\n\t"
+         : "+r" (a)
+         : "i" (-s & 0x1F)
+    );
+    else
+        __asm__ ("sarl %1, %0\n\t"
+               : "+r" (a)
+               : "c" ((uint8_t)(-s))
+        );
+    return a;
+}
+
+#define NEG_USR32 NEG_USR32
+static inline uint32_t NEG_USR32(uint32_t a, int8_t s){
+    if (__builtin_constant_p(s))
+    __asm__ ("shrl %1, %0\n\t"
+         : "+r" (a)
+         : "i" (-s & 0x1F)
+    );
+    else
+        __asm__ ("shrl %1, %0\n\t"
+               : "+r" (a)
+               : "c" ((uint8_t)(-s))
+        );
+    return a;
+}
+
+#endif /* HAVE_INLINE_ASM */
+#endif /* AVCODEC_X86_MATHOPS_H */
diff --git a/libs/ffmpeg/libavutil/aarch64/asm.S b/libs/ffmpeg/libavutil/aarch64/asm.S
new file mode 100644
index 000000000000..f0dadd23d92e
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/asm.S
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2008 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
+ */
+
+#if 0
+#pragma makedep header
+#endif
+
+#include "config.h"
+
+#ifdef __ELF__
+#   define ELF
+#else
+#   define ELF #
+#endif
+
+#if HAVE_AS_FUNC
+#   define FUNC
+#else
+#   define FUNC #
+#endif
+
+#ifndef __has_feature
+#   define __has_feature(x) 0
+#endif
+
+#if HAVE_AS_ARCH_DIRECTIVE
+        .arch           AS_ARCH_LEVEL
+#endif
+
+#if HAVE_AS_ARCHEXT_CRC_DIRECTIVE
+#define ENABLE_ARM_CRC  .arch_extension crc
+#define DISABLE_ARM_CRC .arch_extension nocrc
+#else
+#define ENABLE_ARM_CRC
+#define DISABLE_ARM_CRC
+#endif
+
+#if HAVE_AS_ARCHEXT_DOTPROD_DIRECTIVE
+#define ENABLE_DOTPROD  .arch_extension dotprod
+#define DISABLE_DOTPROD .arch_extension nodotprod
+#else
+#define ENABLE_DOTPROD
+#define DISABLE_DOTPROD
+#endif
+
+#if HAVE_AS_ARCHEXT_I8MM_DIRECTIVE
+#define ENABLE_I8MM  .arch_extension i8mm
+#define DISABLE_I8MM .arch_extension noi8mm
+#else
+#define ENABLE_I8MM
+#define DISABLE_I8MM
+#endif
+
+#if HAVE_AS_ARCHEXT_SVE_DIRECTIVE
+#define ENABLE_SVE  .arch_extension sve
+#define DISABLE_SVE .arch_extension nosve
+#else
+#define ENABLE_SVE
+#define DISABLE_SVE
+#endif
+
+#if HAVE_AS_ARCHEXT_SVE2_DIRECTIVE
+#define ENABLE_SVE2  .arch_extension sve2
+#define DISABLE_SVE2 .arch_extension nosve2
+#else
+#define ENABLE_SVE2
+#define DISABLE_SVE2
+#endif
+
+#if HAVE_AS_ARCHEXT_SME_DIRECTIVE
+#define ENABLE_SME   .arch_extension sme
+#define DISABLE_SME  .arch_extension nosme
+#else
+#define ENABLE_SME
+#define DISABLE_SME
+#endif
+
+#if HAVE_AS_ARCHEXT_SME_I16I64_DIRECTIVE
+#define ENABLE_SME_I16I64  .arch_extension sme-i16i64
+#define DISABLE_SME_I16I64 .arch_extension nosme-i16i64
+#else
+#define ENABLE_SME_I16I64
+#define DISABLE_SME_I16I64
+#endif
+
+#if HAVE_AS_ARCHEXT_SME2_DIRECTIVE
+#define ENABLE_SME2   .arch_extension sme2
+#define DISABLE_SME2  .arch_extension nosme2
+#else
+#define ENABLE_SME2
+#define DISABLE_SME2
+#endif
+
+DISABLE_ARM_CRC
+DISABLE_DOTPROD
+DISABLE_I8MM
+DISABLE_SVE
+DISABLE_SVE2
+DISABLE_SME
+DISABLE_SME_I16I64
+DISABLE_SME2
+
+#if HAVE_SME
+.macro sme_entry
+        stp             x29, x30, [sp, #-80]!
+        mov             x29, sp
+        stp             d8, d9, [sp, #16]
+        stp             d10, d11, [sp, #32]
+        stp             d12, d13, [sp, #48]
+        stp             d14, d15, [sp, #64]
+        smstart
+.endm
+
+.macro sme_exit
+        smstop
+        ldp             d8, d9, [sp, #16]
+        ldp             d10, d11, [sp, #32]
+        ldp             d12, d13, [sp, #48]
+        ldp             d14, d15, [sp, #64]
+        ldp             x29, x30, [sp], #80
+.endm
+#endif
+
+/* Support macros for
+ *   - Armv8.3-A Pointer Authentication and
+ *   - Armv8.5-A Branch Target Identification
+ * features which require emitting a .note.gnu.property section with the
+ * appropriate architecture-dependent feature bits set.
+ *
+ * |AARCH64_SIGN_LINK_REGISTER| and |AARCH64_VALIDATE_LINK_REGISTER| expand to
+ * PACIxSP and AUTIxSP, respectively. |AARCH64_SIGN_LINK_REGISTER| should be
+ * used immediately before saving the LR register (x30) to the stack.
+ * |AARCH64_VALIDATE_LINK_REGISTER| should be used immediately after restoring
+ * it. Note |AARCH64_SIGN_LINK_REGISTER|'s modifications to LR must be undone
+ * with |AARCH64_VALIDATE_LINK_REGISTER| before RET. The SP register must also
+ * have the same value at the two points. For example:
+ *
+ *   .global f
+ *   f:
+ *     AARCH64_SIGN_LINK_REGISTER
+ *     stp x29, x30, [sp, #-96]!
+ *     mov x29, sp
+ *     ...
+ *     ldp x29, x30, [sp], #96
+ *     AARCH64_VALIDATE_LINK_REGISTER
+ *     ret
+ *
+ * |AARCH64_VALID_CALL_TARGET| expands to BTI 'c'. Either it, or
+ * |AARCH64_SIGN_LINK_REGISTER|, must be used at every point that may be an
+ * indirect call target. In particular, all symbols exported from a file must
+ * begin with one of these macros. For example, a leaf function that does not
+ * save LR can instead use |AARCH64_VALID_CALL_TARGET|:
+ *
+ *   .globl return_zero
+ *   return_zero:
+ *     AARCH64_VALID_CALL_TARGET
+ *     mov x0, #0
+ *     ret
+ *
+ * A non-leaf function which does not immediately save LR may need both macros
+ * because |AARCH64_SIGN_LINK_REGISTER| appears late. For example, the function
+ * may jump to an alternate implementation before setting up the stack:
+ *
+ *   .globl with_early_jump
+ *   with_early_jump:
+ *     AARCH64_VALID_CALL_TARGET
+ *     cmp x0, #128
+ *     b.lt .Lwith_early_jump_128
+ *     AARCH64_SIGN_LINK_REGISTER
+ *     stp x29, x30, [sp, #-96]!
+ *     mov x29, sp
+ *     ...
+ *     ldp x29, x30, [sp], #96
+ *     AARCH64_VALIDATE_LINK_REGISTER
+ *     ret
+ *
+ *  .Lwith_early_jump_128:
+ *     ...
+ *     ret
+ *
+ * These annotations are only required with indirect calls. Private symbols that
+ * are only the target of direct calls do not require annotations. Also note
+ * that |AARCH64_VALID_CALL_TARGET| is only valid for indirect calls (BLR), not
+ * indirect jumps (BR). Indirect jumps in assembly are supported through
+ * |AARCH64_VALID_JUMP_TARGET|. Landing Pads which shall serve for jumps and
+ * calls can be created using |AARCH64_VALID_JUMP_CALL_TARGET|.
+ *
+ * Although not necessary, it is safe to use these macros in 32-bit ARM
+ * assembly. This may be used to simplify dual 32-bit and 64-bit files.
+ *
+ * References:
+ * - "ELF for the Arm® 64-bit Architecture"
+ *   https: *github.com/ARM-software/abi-aa/blob/master/aaelf64/aaelf64.rst
+ * - "Providing protection for complex software"
+ *   https://developer.arm.com/architectures/learn-the-architecture/providing-protection-for-complex-software
+ */
+#if defined(__ARM_FEATURE_BTI_DEFAULT) && (__ARM_FEATURE_BTI_DEFAULT == 1)
+#   define GNU_PROPERTY_AARCH64_BTI (1 << 0)   // Has BTI
+#   define AARCH64_VALID_CALL_TARGET hint #34  // BTI 'c'
+#   define AARCH64_VALID_JUMP_TARGET hint #38  // BTI 'j'
+#else
+#   define GNU_PROPERTY_AARCH64_BTI 0          // No BTI
+#   define AARCH64_VALID_CALL_TARGET
+#   define AARCH64_VALID_JUMP_TARGET
+#endif
+
+#if defined(__ARM_FEATURE_PAC_DEFAULT)
+#   if ((__ARM_FEATURE_PAC_DEFAULT & (1 << 0)) != 0) // authentication using key A
+#       define AARCH64_SIGN_LINK_REGISTER      paciasp
+#       define AARCH64_VALIDATE_LINK_REGISTER  autiasp
+#   elif ((__ARM_FEATURE_PAC_DEFAULT & (1 << 1)) != 0) // authentication using key B
+#       define AARCH64_SIGN_LINK_REGISTER      pacibsp
+#       define AARCH64_VALIDATE_LINK_REGISTER  autibsp
+#   else
+#       error Pointer authentication defines no valid key!
+#   endif
+#   if ((__ARM_FEATURE_PAC_DEFAULT & (1 << 2)) != 0)
+#       error Authentication of leaf functions is enabled but not supported in FFmpeg!
+#   endif
+#   define GNU_PROPERTY_AARCH64_PAC (1 << 1)
+#else
+#   define GNU_PROPERTY_AARCH64_PAC 0
+#   define AARCH64_SIGN_LINK_REGISTER
+#   define AARCH64_VALIDATE_LINK_REGISTER
+#endif
+
+#if defined(__ARM_FEATURE_GCS_DEFAULT) && __ARM_FEATURE_GCS_DEFAULT == 1
+#define GNU_PROPERTY_AARCH64_GCS (1 << 2)
+#else
+#define GNU_PROPERTY_AARCH64_GCS 0 /* No GCS */
+#endif
+
+
+#if (GNU_PROPERTY_AARCH64_BTI != 0 || GNU_PROPERTY_AARCH64_PAC != 0 || GNU_PROPERTY_AARCH64_GCS != 0) && defined(__ELF__)
+        .pushsection .note.gnu.property, "a"
+        .balign 8
+        .long 4
+        .long 0x10
+        .long 0x5
+        .asciz "GNU"
+        .long 0xc0000000 /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */
+        .long 4
+        .long (GNU_PROPERTY_AARCH64_BTI | GNU_PROPERTY_AARCH64_PAC | GNU_PROPERTY_AARCH64_GCS)
+        .long 0
+        .popsection
+#endif
+
+.macro  function name, export=0, align=4
+    .macro endfunc
+ELF     .size   \name, . - \name
+FUNC    .endfunc
+        .purgem endfunc
+    .endm
+        .text
+        .align          \align
+    .if \export
+        .global EXTERN_ASM\name
+ELF     .type   EXTERN_ASM\name, %function
+FUNC    .func   EXTERN_ASM\name
+EXTERN_ASM\name:
+        AARCH64_VALID_CALL_TARGET
+    .else
+ELF     .type   \name, %function
+FUNC    .func   \name
+\name:
+    .endif
+.endm
+
+.macro  const   name, align=4, relocate=0
+    .macro endconst
+ELF     .size   \name, . - \name
+        .purgem endconst
+    .endm
+#if HAVE_SECTION_DATA_REL_RO
+.if \relocate
+        .section        .data.rel.ro
+.else
+        .section        .rodata
+.endif
+#elif defined(_WIN32)
+        .section        .rdata
+#elif !defined(__MACH__)
+        .section        .rodata
+#else
+        .const_data
+#endif
+        .align          \align
+\name:
+.endm
+
+.macro  movrel rd, val, offset=0
+#if CONFIG_PIC && defined(__APPLE__)
+    .if \offset < 0
+        adrp            \rd, \val@PAGE
+        add             \rd, \rd, \val@PAGEOFF
+        sub             \rd, \rd, -(\offset)
+    .else
+        adrp            \rd, \val+(\offset)@PAGE
+        add             \rd, \rd, \val+(\offset)@PAGEOFF
+    .endif
+#elif CONFIG_PIC && defined(_WIN32)
+    .if \offset < 0
+        adrp            \rd, \val
+        add             \rd, \rd, :lo12:\val
+        sub             \rd, \rd, -(\offset)
+    .else
+        adrp            \rd, \val+(\offset)
+        add             \rd, \rd, :lo12:\val+(\offset)
+    .endif
+#elif CONFIG_PIC
+#   if __has_feature(hwaddress_sanitizer)
+        adrp            \rd, :pg_hi21_nc:\val+(\offset)
+#   else
+        adrp            \rd, \val+(\offset)
+#   endif
+        add             \rd, \rd, :lo12:\val+(\offset)
+#else
+        ldr             \rd, =\val+\offset
+#endif
+.endm
+
+#define GLUE(a, b) a ## b
+#define JOIN(a, b) GLUE(a, b)
+#define X(s) JOIN(EXTERN_ASM, s)
+
+#define x18 do_not_use_x18
+#define w18 do_not_use_w18
diff --git a/libs/ffmpeg/libavutil/aarch64/cpu.c b/libs/ffmpeg/libavutil/aarch64/cpu.c
new file mode 100644
index 000000000000..8dd82453582c
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/cpu.c
@@ -0,0 +1,226 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/cpu.h"
+#include "libavutil/cpu_internal.h"
+#include "config.h"
+
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+#include <stdint.h>
+#include <sys/auxv.h>
+
+#define HWCAP_AARCH64_CRC32   (1 << 7)
+#define HWCAP_AARCH64_ASIMDDP (1 << 20)
+#define HWCAP_AARCH64_SVE     (1 << 22)
+#define HWCAP2_AARCH64_SVE2   (1 << 1)
+#define HWCAP2_AARCH64_I8MM   (1 << 13)
+#define HWCAP2_AARCH64_SME    (1 << 23)
+#define HWCAP2_AARCH64_SME_I16I64 (1 << 24)
+#define HWCAP2_AARCH64_SME2   (1ULL << 37)
+
+static int detect_flags(void)
+{
+    int flags = 0;
+
+    unsigned long hwcap = ff_getauxval(AT_HWCAP);
+    unsigned long hwcap2 = ff_getauxval(AT_HWCAP2);
+
+    if (hwcap & HWCAP_AARCH64_CRC32)
+        flags |= AV_CPU_FLAG_ARM_CRC;
+    if (hwcap & HWCAP_AARCH64_ASIMDDP)
+        flags |= AV_CPU_FLAG_DOTPROD;
+    if (hwcap & HWCAP_AARCH64_SVE)
+        flags |= AV_CPU_FLAG_SVE;
+    if (hwcap2 & HWCAP2_AARCH64_SVE2)
+        flags |= AV_CPU_FLAG_SVE2;
+    if (hwcap2 & HWCAP2_AARCH64_I8MM)
+        flags |= AV_CPU_FLAG_I8MM;
+    if (hwcap2 & HWCAP2_AARCH64_SME)
+        flags |= AV_CPU_FLAG_SME;
+    if (hwcap2 & HWCAP2_AARCH64_SME_I16I64)
+        flags |= AV_CPU_FLAG_SME_I16I64;
+    if (hwcap2 & HWCAP2_AARCH64_SME2)
+        flags |= AV_CPU_FLAG_SME2;
+
+    return flags;
+}
+
+#elif defined(__APPLE__) && HAVE_SYSCTLBYNAME
+#include <sys/sysctl.h>
+
+static int have_feature(const char *feature) {
+    uint32_t value = 0;
+    size_t size = sizeof(value);
+    if (!sysctlbyname(feature, &value, &size, NULL, 0))
+        return value;
+    return 0;
+}
+
+static int detect_flags(void)
+{
+    int flags = 0;
+
+    if (have_feature("hw.optional.arm.FEAT_DotProd"))
+        flags |= AV_CPU_FLAG_DOTPROD;
+    if (have_feature("hw.optional.arm.FEAT_I8MM"))
+        flags |= AV_CPU_FLAG_I8MM;
+    if (have_feature("hw.optional.arm.FEAT_SME"))
+        flags |= AV_CPU_FLAG_SME;
+    if (have_feature("hw.optional.arm.FEAT_SME_I16I64"))
+        flags |= AV_CPU_FLAG_SME_I16I64;
+    if (have_feature("hw.optional.armv8_crc32"))
+        flags |= AV_CPU_FLAG_ARM_CRC;
+    if (have_feature("hw.optional.arm.FEAT_SME2"))
+        flags |= AV_CPU_FLAG_SME2;
+
+    return flags;
+}
+
+#elif defined(__OpenBSD__)
+#include <machine/armreg.h>
+#include <machine/cpu.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+static int detect_flags(void)
+{
+    int flags = 0;
+
+#ifdef CPU_ID_AA64ISAR0
+    int mib[2];
+    uint64_t isar0;
+    uint64_t isar1;
+    size_t len;
+
+    mib[0] = CTL_MACHDEP;
+    mib[1] = CPU_ID_AA64ISAR0;
+    len = sizeof(isar0);
+    if (sysctl(mib, 2, &isar0, &len, NULL, 0) != -1) {
+        if (ID_AA64ISAR0_DP(isar0) >= ID_AA64ISAR0_DP_IMPL)
+            flags |= AV_CPU_FLAG_DOTPROD;
+        if (ID_AA64ISAR0_CRC32(isar0) >= ID_AA64ISAR0_CRC32_BASE)
+            flags |= AV_CPU_FLAG_ARM_CRC;
+    }
+
+    mib[0] = CTL_MACHDEP;
+    mib[1] = CPU_ID_AA64ISAR1;
+    len = sizeof(isar1);
+    if (sysctl(mib, 2, &isar1, &len, NULL, 0) != -1) {
+#ifdef ID_AA64ISAR1_I8MM_IMPL
+        if (ID_AA64ISAR1_I8MM(isar1) >= ID_AA64ISAR1_I8MM_IMPL)
+            flags |= AV_CPU_FLAG_I8MM;
+#endif
+    }
+#endif
+
+    return flags;
+}
+
+#elif defined(_WIN32)
+#include <windows.h>
+
+static int detect_flags(void)
+{
+    int flags = 0;
+#ifdef PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_ARM_CRC;
+#endif
+#ifdef PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_DOTPROD;
+#endif
+#ifdef PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_I8MM;
+#endif
+#ifdef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SVE_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_SVE;
+#endif
+#ifdef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_SVE2;
+#endif
+#ifdef PF_ARM_SME_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SME_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_SME;
+#endif
+#ifdef PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SME_I16I64_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_SME_I16I64;
+#endif
+#ifdef PF_ARM_SME2_INSTRUCTIONS_AVAILABLE
+    if (IsProcessorFeaturePresent(PF_ARM_SME2_INSTRUCTIONS_AVAILABLE))
+        flags |= AV_CPU_FLAG_SME2;
+#endif
+    return flags;
+}
+#else
+
+static int detect_flags(void)
+{
+    return 0;
+}
+
+#endif
+
+int ff_get_cpu_flags_aarch64(void)
+{
+    int flags = AV_CPU_FLAG_ARMV8 * HAVE_ARMV8 |
+                AV_CPU_FLAG_NEON  * HAVE_NEON;
+
+#ifdef __ARM_FEATURE_DOTPROD
+    flags |= AV_CPU_FLAG_DOTPROD;
+#endif
+#ifdef __ARM_FEATURE_MATMUL_INT8
+    flags |= AV_CPU_FLAG_I8MM;
+#endif
+#ifdef __ARM_FEATURE_SVE
+    flags |= AV_CPU_FLAG_SVE;
+#endif
+#ifdef __ARM_FEATURE_SVE2
+    flags |= AV_CPU_FLAG_SVE2;
+#endif
+#ifdef __ARM_FEATURE_SME
+    flags |= AV_CPU_FLAG_SME;
+#endif
+#ifdef __ARM_FEATURE_CRC32
+    flags |= AV_CPU_FLAG_ARM_CRC;
+#endif
+#ifdef __ARM_FEATURE_SME_I16I64
+    flags |= AV_CPU_FLAG_SME_I16I64;
+#endif
+#ifdef __ARM_FEATURE_SME2
+    flags |= AV_CPU_FLAG_SME2;
+#endif
+
+    flags |= detect_flags();
+
+    return flags;
+}
+
+size_t ff_get_cpu_max_align_aarch64(void)
+{
+    int flags = av_get_cpu_flags();
+
+    if (flags & AV_CPU_FLAG_NEON)
+        return 16;
+
+    return 8;
+}
diff --git a/libs/ffmpeg/libavutil/aarch64/cpu.h b/libs/ffmpeg/libavutil/aarch64/cpu.h
new file mode 100644
index 000000000000..f1dff3f647d7
--- /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.S b/libs/ffmpeg/libavutil/aarch64/crc.S
new file mode 100644
index 000000000000..892c7ff22907
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/crc.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2025 Zhao Zhili <quinkblack@foxmail.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 General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General 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 "asm.S"
+
+#if HAVE_ARM_CRC
+ENABLE_ARM_CRC
+
+.macro crc32_byte
+        ldrb            w5, [x2], #1
+        subs            x4, x4, #1
+        crc32b          w0, w0, w5
+.endm
+
+function ff_crc32_aarch64, export=1
+        and             x4, x2, #7          // non-aligned buffer addr
+        mov             w0, w1
+        cbz             x3, 8f
+
+        cbz             x4, 2f
+
+        mov             x5, #8
+        sub             x4, x5, x4
+        cmp             x4, x3
+        csel            x4, x4, x3, lo
+        sub             x3, x3, x4
+1:
+        // loop on non-aligned buffer
+        crc32_byte
+        b.ne            1b
+2:
+        // loop on aligned buffer
+        bic             x5, x3, #15
+        and             x4, x3, #15
+        cbz             x5, 4f
+3:
+        ldp             x6, x7, [x2], #16
+        subs            x5, x5, #16
+        crc32x          w0, w0, x6
+        crc32x          w0, w0, x7
+        b.ne            3b
+4:
+        cbz             x4, 8f
+5:
+        crc32_byte
+        b.ne            5b
+8:
+        ret
+endfunc
+
+DISABLE_ARM_CRC
+#endif
diff --git a/libs/ffmpeg/libavutil/aarch64/crc.h b/libs/ffmpeg/libavutil/aarch64/crc.h
new file mode 100644
index 000000000000..08efdd28f3e7
--- /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/float_dsp_init.c b/libs/ffmpeg/libavutil/aarch64/float_dsp_init.c
new file mode 100644
index 000000000000..4325071821cd
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/float_dsp_init.c
@@ -0,0 +1,69 @@
+/*
+ * ARM NEON optimised Float DSP functions
+ * Copyright (c) 2008 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
+ */
+
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/float_dsp.h"
+#include "cpu.h"
+
+void ff_vector_fmul_neon(float *dst, const float *src0, const float *src1,
+                         int len);
+
+void ff_vector_fmac_scalar_neon(float *dst, const float *src, float mul,
+                                int len);
+
+void ff_vector_fmul_scalar_neon(float *dst, const float *src, float mul,
+                                int len);
+
+void ff_vector_dmul_scalar_neon(double *dst, const double *src, double mul,
+                                int len);
+
+void ff_vector_fmul_window_neon(float *dst, const float *src0,
+                                const float *src1, const float *win, int len);
+
+void ff_vector_fmul_add_neon(float *dst, const float *src0, const float *src1,
+                             const float *src2, int len);
+
+void ff_vector_fmul_reverse_neon(float *dst, const float *src0,
+                                 const float *src1, int len);
+
+void ff_butterflies_float_neon(float *v1, float *v2, int len);
+
+float ff_scalarproduct_float_neon(const float *v1, const float *v2, int len);
+
+av_cold void ff_float_dsp_init_aarch64(AVFloatDSPContext *fdsp)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_neon(cpu_flags)) {
+        fdsp->butterflies_float   = ff_butterflies_float_neon;
+        fdsp->scalarproduct_float = ff_scalarproduct_float_neon;
+        fdsp->vector_dmul_scalar  = ff_vector_dmul_scalar_neon;
+        fdsp->vector_fmul         = ff_vector_fmul_neon;
+        fdsp->vector_fmac_scalar  = ff_vector_fmac_scalar_neon;
+        fdsp->vector_fmul_add     = ff_vector_fmul_add_neon;
+        fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_neon;
+        fdsp->vector_fmul_scalar  = ff_vector_fmul_scalar_neon;
+        fdsp->vector_fmul_window  = ff_vector_fmul_window_neon;
+    }
+}
diff --git a/libs/ffmpeg/libavutil/aarch64/float_dsp_neon.S b/libs/ffmpeg/libavutil/aarch64/float_dsp_neon.S
new file mode 100644
index 000000000000..35e2715b87e9
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/float_dsp_neon.S
@@ -0,0 +1,202 @@
+/*
+ * ARM NEON optimised Float DSP functions
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) 2014 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
+ */
+
+#include "config.h"
+#include "asm.S"
+
+function ff_vector_fmul_neon, export=1
+1:      subs            w3,  w3,  #16
+        ld1             {v0.4s, v1.4s}, [x1], #32
+        ld1             {v2.4s, v3.4s}, [x1], #32
+        ld1             {v4.4s, v5.4s}, [x2], #32
+        ld1             {v6.4s, v7.4s}, [x2], #32
+        fmul            v16.4s, v0.4s,  v4.4s
+        fmul            v17.4s, v1.4s,  v5.4s
+        fmul            v18.4s, v2.4s,  v6.4s
+        fmul            v19.4s, v3.4s,  v7.4s
+        st1             {v16.4s, v17.4s}, [x0], #32
+        st1             {v18.4s, v19.4s}, [x0], #32
+        b.ne            1b
+        ret
+endfunc
+
+function ff_vector_fmac_scalar_neon, export=1
+        mov             x3,  #-32
+1:      subs            w2,  w2,  #16
+        ld1             {v16.4s, v17.4s}, [x0], #32
+        ld1             {v18.4s, v19.4s}, [x0], x3
+        ld1             {v4.4s,  v5.4s},  [x1], #32
+        ld1             {v6.4s,  v7.4s},  [x1], #32
+        fmla            v16.4s, v4.4s,  v0.s[0]
+        fmla            v17.4s, v5.4s,  v0.s[0]
+        fmla            v18.4s, v6.4s,  v0.s[0]
+        fmla            v19.4s, v7.4s,  v0.s[0]
+        st1             {v16.4s, v17.4s}, [x0], #32
+        st1             {v18.4s, v19.4s}, [x0], #32
+        b.ne            1b
+        ret
+endfunc
+
+function ff_vector_fmul_scalar_neon, export=1
+        mov             w4,  #15
+        bics            w3,  w2,  w4
+        dup             v16.4s, v0.s[0]
+        b.eq            3f
+        ld1             {v0.4s, v1.4s}, [x1], #32
+1:      subs            w3,  w3,  #16
+        fmul            v0.4s,  v0.4s,  v16.4s
+        ld1             {v2.4s, v3.4s}, [x1], #32
+        fmul            v1.4s,  v1.4s,  v16.4s
+        fmul            v2.4s,  v2.4s,  v16.4s
+        st1             {v0.4s, v1.4s}, [x0], #32
+        fmul            v3.4s,  v3.4s,  v16.4s
+        b.eq            2f
+        ld1             {v0.4s, v1.4s}, [x1], #32
+        st1             {v2.4s, v3.4s}, [x0], #32
+        b               1b
+2:      ands            w2,  w2,  #15
+        st1             {v2.4s, v3.4s}, [x0], #32
+        b.eq            4f
+3:      ld1             {v0.4s}, [x1], #16
+        fmul            v0.4s,  v0.4s,  v16.4s
+        st1             {v0.4s}, [x0], #16
+        subs            w2,  w2,  #4
+        b.gt            3b
+4:      ret
+endfunc
+
+function ff_vector_dmul_scalar_neon, export=1
+        dup             v16.2d, v0.d[0]
+        ld1             {v0.2d, v1.2d}, [x1], #32
+1:      subs            w2,  w2,  #8
+        fmul            v0.2d,  v0.2d,  v16.2d
+        ld1             {v2.2d, v3.2d}, [x1], #32
+        fmul            v1.2d,  v1.2d,  v16.2d
+        fmul            v2.2d,  v2.2d,  v16.2d
+        st1             {v0.2d, v1.2d}, [x0], #32
+        fmul            v3.2d,  v3.2d,  v16.2d
+        ld1             {v0.2d, v1.2d}, [x1], #32
+        st1             {v2.2d, v3.2d}, [x0], #32
+        b.gt            1b
+        ret
+endfunc
+
+function ff_vector_fmul_window_neon, export=1
+        sxtw            x4,  w4                 // len
+        sub             x2,  x2,  #8
+        sub             x5,  x4,  #2
+        add             x2,  x2,  x5, lsl #2    // src1 + 4 * (len - 4)
+        add             x6,  x3,  x5, lsl #3    // win  + 8 * (len - 2)
+        add             x5,  x0,  x5, lsl #3    // dst  + 8 * (len - 2)
+        mov             x7,  #-16
+        ld1             {v0.4s},  [x1], #16     // s0
+        ld1             {v2.4s},  [x3], #16     // wi
+        ld1             {v1.4s},  [x2], x7      // s1
+1:      ld1             {v3.4s},  [x6], x7      // wj
+        subs            x4,  x4,  #4
+        fmul            v17.4s, v0.4s,  v2.4s   // s0 * wi
+        rev64           v4.4s,  v1.4s
+        rev64           v5.4s,  v3.4s
+        rev64           v17.4s, v17.4s
+        ext             v4.16b,  v4.16b,  v4.16b,  #8 // s1_r
+        ext             v5.16b,  v5.16b,  v5.16b,  #8 // wj_r
+        ext             v17.16b, v17.16b, v17.16b, #8 // (s0 * wi)_rev
+        fmul            v16.4s, v0.4s,  v5.4s  // s0 * wj_r
+        fmla            v17.4s, v1.4s,  v3.4s  // (s0 * wi)_rev + s1 * wj
+        b.eq            2f
+        ld1             {v0.4s},  [x1], #16
+        fmls            v16.4s, v4.4s,  v2.4s  // s0 * wj_r - s1_r * wi
+        st1             {v17.4s}, [x5], x7
+        ld1             {v2.4s},  [x3], #16
+        ld1             {v1.4s},  [x2], x7
+        st1             {v16.4s}, [x0], #16
+        b               1b
+2:
+        fmls            v16.4s, v4.4s,  v2.4s  // s0 * wj_r - s1_r * wi
+        st1             {v17.4s}, [x5], x7
+        st1             {v16.4s}, [x0], #16
+        ret
+endfunc
+
+function ff_vector_fmul_add_neon, export=1
+        ld1             {v0.4s, v1.4s},  [x1], #32
+        ld1             {v2.4s, v3.4s},  [x2], #32
+        ld1             {v4.4s, v5.4s},  [x3], #32
+1:      subs            w4,  w4,  #8
+        fmla            v4.4s,  v0.4s,  v2.4s
+        fmla            v5.4s,  v1.4s,  v3.4s
+        b.eq            2f
+        ld1             {v0.4s, v1.4s},  [x1], #32
+        ld1             {v2.4s, v3.4s},  [x2], #32
+        st1             {v4.4s, v5.4s},  [x0], #32
+        ld1             {v4.4s, v5.4s},  [x3], #32
+        b               1b
+2:      st1             {v4.4s, v5.4s},  [x0], #32
+        ret
+endfunc
+
+function ff_vector_fmul_reverse_neon, export=1
+        sxtw            x3,  w3
+        add             x2,  x2,  x3,  lsl #2
+        sub             x2,  x2,  #32
+        mov             x4, #-32
+        ld1             {v2.4s, v3.4s},  [x2], x4
+        ld1             {v0.4s, v1.4s},  [x1], #32
+1:      subs            x3,  x3,  #8
+        rev64           v3.4s,  v3.4s
+        rev64           v2.4s,  v2.4s
+        ext             v3.16b, v3.16b, v3.16b,  #8
+        ext             v2.16b, v2.16b, v2.16b,  #8
+        fmul            v16.4s, v0.4s,  v3.4s
+        fmul            v17.4s, v1.4s,  v2.4s
+        b.eq            2f
+        ld1             {v2.4s, v3.4s},  [x2], x4
+        ld1             {v0.4s, v1.4s},  [x1], #32
+        st1             {v16.4s, v17.4s},  [x0], #32
+        b               1b
+2:      st1             {v16.4s, v17.4s},  [x0], #32
+        ret
+endfunc
+
+function ff_butterflies_float_neon, export=1
+1:      ld1             {v0.4s}, [x0]
+        ld1             {v1.4s}, [x1]
+        subs            w2,  w2,  #4
+        fsub            v2.4s,   v0.4s,  v1.4s
+        fadd            v3.4s,   v0.4s,  v1.4s
+        st1             {v2.4s}, [x1],   #16
+        st1             {v3.4s}, [x0],   #16
+        b.gt            1b
+        ret
+endfunc
+
+function ff_scalarproduct_float_neon, export=1
+        movi            v2.4s,  #0
+1:      ld1             {v0.4s}, [x0],   #16
+        ld1             {v1.4s}, [x1],   #16
+        subs            w2,      w2,     #4
+        fmla            v2.4s,   v0.4s,  v1.4s
+        b.gt            1b
+        faddp           v0.4s,   v2.4s,  v2.4s
+        faddp           s0,      v0.2s
+        ret
+endfunc
diff --git a/libs/ffmpeg/libavutil/aarch64/intreadwrite.h b/libs/ffmpeg/libavutil/aarch64/intreadwrite.h
new file mode 100644
index 000000000000..4ce2d6498766
--- /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 000000000000..922b0c5598a9
--- /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/aarch64/tx_float_init.c b/libs/ffmpeg/libavutil/aarch64/tx_float_init.c
new file mode 100644
index 000000000000..8300472c4c98
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/tx_float_init.c
@@ -0,0 +1,64 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "libavutil/tx_priv.h"
+#include "libavutil/attributes.h"
+#include "libavutil/aarch64/cpu.h"
+
+TX_DECL_FN(fft2,      neon)
+TX_DECL_FN(fft4_fwd,  neon)
+TX_DECL_FN(fft4_inv,  neon)
+TX_DECL_FN(fft8,      neon)
+TX_DECL_FN(fft8_ns,   neon)
+TX_DECL_FN(fft16,     neon)
+TX_DECL_FN(fft16_ns,  neon)
+TX_DECL_FN(fft32,     neon)
+TX_DECL_FN(fft32_ns,  neon)
+TX_DECL_FN(fft_sr,    neon)
+TX_DECL_FN(fft_sr_ns, neon)
+
+static av_cold int neon_init(AVTXContext *s, const FFTXCodelet *cd,
+                             uint64_t flags, FFTXCodeletOptions *opts,
+                             int len, int inv, const void *scale)
+{
+    ff_tx_init_tabs_float(len);
+    if (cd->max_len == 2)
+        return ff_tx_gen_ptwo_revtab(s, opts);
+    else
+        return ff_tx_gen_split_radix_parity_revtab(s, len, inv, opts, 8, 0);
+}
+
+const FFTXCodelet * const ff_tx_codelet_list_float_aarch64[] = {
+    TX_DEF(fft2,      FFT,  2,  2, 2, 0, 128, NULL,      neon, NEON, AV_TX_INPLACE, 0),
+    TX_DEF(fft2,      FFT,  2,  2, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft4_fwd,  FFT,  4,  4, 2, 0, 128, NULL,      neon, NEON, AV_TX_INPLACE | FF_TX_FORWARD_ONLY, 0),
+    TX_DEF(fft4_fwd,  FFT,  4,  4, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft4_inv,  FFT,  4,  4, 2, 0, 128, NULL,      neon, NEON, AV_TX_INPLACE | FF_TX_INVERSE_ONLY, 0),
+    TX_DEF(fft8,      FFT,  8,  8, 2, 0, 128, neon_init, neon, NEON, AV_TX_INPLACE, 0),
+    TX_DEF(fft8_ns,   FFT,  8,  8, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft16,     FFT, 16, 16, 2, 0, 128, neon_init, neon, NEON, AV_TX_INPLACE, 0),
+    TX_DEF(fft16_ns,  FFT, 16, 16, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft32,     FFT, 32, 32, 2, 0, 128, neon_init, neon, NEON, AV_TX_INPLACE, 0),
+    TX_DEF(fft32_ns,  FFT, 32, 32, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+
+    TX_DEF(fft_sr,    FFT, 64, 131072, 2, 0, 128, neon_init, neon, NEON, 0, 0),
+    TX_DEF(fft_sr_ns, FFT, 64, 131072, 2, 0, 192, neon_init, neon, NEON, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+
+    NULL,
+};
diff --git a/libs/ffmpeg/libavutil/aarch64/tx_float_neon.S b/libs/ffmpeg/libavutil/aarch64/tx_float_neon.S
new file mode 100644
index 000000000000..d00b3f96840f
--- /dev/null
+++ b/libs/ffmpeg/libavutil/aarch64/tx_float_neon.S
@@ -0,0 +1,1278 @@
+/*
+ * Copyright (c) Lynne
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/aarch64/asm.S"
+
+/* Open `doc/transforms.md` to see the code upon which the transforms here were
+ * based upon.
+ *
+ * File conventions:
+ * GPRs:    x0-x3   - arguments, untouched
+ *          x4      - Lookup table base pointer
+ *          x5-x6   - macro ld1 temps/function scratch
+ *          x7-x9   - FFT table state
+ *          x10-x17 - lookup table/macro scratch
+ *          w19-w20 - current/target length when needed
+ *          x21-x22 - len*2, len*6
+ *
+ * Vectors: v0-v7   - coefficients
+ *          v8-v15  - coefficients when needed, otherwise untouched
+ *          v16-v30 - used as needed
+ *          v31     - -1.0, +1.0, -1.0, +1.0. Never touched after loading.
+ *
+ * Stack:   backup for v8-v15 and x19-x22 when needed, and transform lengths
+ */
+
+#define M_SQRT1_2 0.707106781186547524401
+#define COS16_1   0.92387950420379638671875
+#define COS16_3   0.3826834261417388916015625
+
+/* We only ever load this once at the start, and then live with losing an
+ * entire register as we need to lug this all the time everywhere.
+ * Clearly should be integrated into an fsadd and fmlsa, but "muh RISC!". */
+const subadd, align=4
+        .float -1.0,  1.0, -1.0,  1.0
+endconst
+
+.macro LOAD_SUBADD
+        movrel          x5, subadd
+        ld1             { v31.4s }, [x5]
+.endm
+
+.macro SETUP_LUT no_lut=0
+.if \no_lut == 0
+        ldr             x4, [x0, #8]
+.endif
+.endm
+
+.macro LOAD_INPUT dst1, dst2, dst3, dst4, src, no_lut=0, discont=0
+.if \no_lut == 1
+.if \discont == 1
+        ldp             q\dst1\(), q\dst2\(), [\src\()]
+        ldp             q\dst3\(), q\dst4\(), [\src\(), #32]
+        add             \src\(), \src\(), #64
+.else
+        ld1             { v\dst1\().4s, v\dst2\().4s, v\dst3\().4s, v\dst4\().4s }, [\src], #64
+.endif
+.else
+        ldp             w10, w11, [x4, #0 ]
+        ldp             w12, w13, [x4, #8 ]
+        ldp             w14, w15, [x4, #16]
+        ldp             w16, w17, [x4, #24]
+
+        add             x4, x4, #32
+
+        ldr             d\dst1, [\src, x10, lsl #3]
+        add             x11, \src, x11, lsl #3
+        ldr             d\dst2, [\src, x12, lsl #3]
+        add             x13, \src, x13, lsl #3
+        ldr             d\dst3, [\src, x14, lsl #3]
+        add             x15, \src, x15, lsl #3
+        ldr             d\dst4, [\src, x16, lsl #3]
+        add             x17, \src, x17, lsl #3
+
+        ld1             { v\dst1\().d }[1], [x11]
+        ld1             { v\dst2\().d }[1], [x13]
+        ld1             { v\dst3\().d }[1], [x15]
+        ld1             { v\dst4\().d }[1], [x17]
+.endif
+.endm
+
+.macro FFT4 e0, o0, standalone
+        fadd            v16.4s, \e0\().4s, \o0\().4s         // r1..4
+        fsub            \e0\().4s, \e0\().4s, \o0\().4s      // t1..4
+
+        rev64           v18.4s, \e0\().4s
+
+        zip2            \o0\().2d, v16.2d, \e0\().2d
+        zip1            v17.2d, v16.2d, \e0\().2d
+
+        mov             \o0\().d[1], v18.d[1]
+
+        fadd            \e0\().4s, v17.4s, \o0\().4s         // a1,2 b1,4
+        fsub            v16.4s,    v17.4s, \o0\().4s         // a3,4 b3,2
+
+        mov             \o0\().16b, v16.16b                  // Swap once again...
+        mov             \o0\().s[3], \e0\().s[3]
+        mov             \e0\().s[3], v16.s[3]
+
+.if \standalone == 0
+        uzp2            \o0\().2d, \e0\().2d, \o0\().2d
+        uzp1            \e0\().2d, \e0\().2d, v16.2d
+.endif
+.endm
+
+// Identical to FFT4, but does 2 transforms in parallel, with no deinterleaving
+.macro FFT4_X2 e0, o0, e1, o1, \
+               t0=v16, t1=v17, t2=v18, t3=v19, t4=v20, t5=v21, t6=v22
+
+        fadd            \t0\().4s, \e0\().4s, \o0\().4s                     // r1234
+        fadd            \t2\().4s, \e1\().4s, \o1\().4s                     // r1234
+        fsub            \e0\().4s, \e0\().4s, \o0\().4s                     // t1234
+        fsub            \e1\().4s, \e1\().4s, \o1\().4s                     // t1234
+
+        rev64           \t4\().4s, \e0\().4s
+        rev64           \t5\().4s, \e1\().4s
+
+        zip2            \o0\().2d, \t0\().2d, \t4\().2d                     // t3,4 r3,4
+        zip2            \o1\().2d, \t2\().2d, \t5\().2d                     // t3,4 r3,4
+
+        fneg            \t3\().4s, \t4\().4s
+        fneg            \t4\().4s, \t5\().4s
+
+        mov             \o0\().s[3], \t3\().s[3]
+        mov             \o1\().s[3], \t4\().s[3]
+
+        zip1            \t1\().2d, \t0\().2d, \e0\().2d                     // t1,2 r1,2
+        zip1            \t3\().2d, \t2\().2d, \e1\().2d                     // t1,2 r1,2
+
+        fsub            \t4\().4s, \t1\().4s, \o0\().4s                     // a34 b32
+        fadd            \t5\().4s, \t1\().4s, \o0\().4s                     // a12 b14
+        fsub            \t2\().4s, \t3\().4s, \o1\().4s                     // a34 b32
+        fadd            \t3\().4s, \t3\().4s, \o1\().4s                     // a12 b14
+
+        zip1            \e0\().2d, \t5\().2d, \t4\().2d                     // a1234
+        zip2            \o0\().2d, \t5\().2d, \t4\().2d                     // b1432
+        zip1            \e1\().2d, \t3\().2d, \t2\().2d                     // a1234
+        zip2            \o1\().2d, \t3\().2d, \t2\().2d                     // b1432
+.endm
+
+const tab_8pt, align=4
+        .float M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2,  M_SQRT1_2
+endconst
+
+.macro FFT8 e0, e1, o0, o1, \
+            t0=v16, t1=v17, t2=v18, t3=v19, t4=v20, t5=v21, t6=v22
+
+        movrel          x5, tab_8pt
+
+        fsub            \t1\().4s, \e1\().4s, \o1\().4s             // j1234
+        fadd            \o1\().4s, \e1\().4s, \o1\().4s             // k1234
+        fsub            \t0\().4s, \e0\().4s, \o0\().4s             // r1234
+        fadd            \o0\().4s, \e0\().4s, \o0\().4s             // q1234
+
+        ld1             { \t5\().4s }, [x5]
+
+        ext             \t4\().16b, \o1\().16b, \o1\().16b, #12
+        rev64           \t4\().4s,  \t4\().4s
+
+        ext             \t2\().16b, \o0\().16b, \t4\().16b, #8      // o0[0,1], o1[3,2]
+        mov             \o0\().d[1], \t4\().d[1]                    // o0[3, 4]; o1[1, 4]
+
+        fsub            \e1\().4s, \o0\().4s, \t2\().4s             // s34, g43
+        fadd            \t2\().4s, \o0\().4s, \t2\().4s             // s12, g12
+
+        rev64           \t6\().4s, v31.4s                           // 1, -1, 1, -1
+        dup             \o0\().2d, \t0\().d[0]                      // r1212
+        dup             \o1\().2d, \t0\().d[1]                      // r3434
+
+        rev64           \t4\().4s, \e1\().4s                        // xxg34
+        rev64           \o1\().4s, \o1\().4s                        // r4343
+
+        ext             \t6\().16b, v31.16b, \t6\().16b, #8         // -1, 1, 1, -1
+        zip1            \t3\().2d, \t2\().2d, \e1\().2d             // s1234
+        zip2            \t2\().2d, \t2\().2d, \t4\().2d             // g1234
+
+        fadd            \e0\().4s, \t3\().4s, \t2\().4s             // out_e1
+        fsub            \e1\().4s, \t3\().4s, \t2\().4s             // out_e2
+
+        fmul            \t1\().4s, \t1\().4s, \t5\().4s             // j * +--+M_SQRT1_2
+        fmls            \o0\().4s, \o1\().4s, \t6\().4s             // z1234
+
+        rev64           \t4\().4s, \t1\().4s                        // j2143
+        fmla            \t1\().4s, \t4\().4s, v31.4s                // l2143
+
+        rev64           \t4\().4s, \t1\().4s                        // l1234
+        ext             \t4\().16b, \t4\().16b, \t4\().16b, #8      // l3412
+
+        fmla            \t4\().4s, \t1\().4s, v31.4s                // t1234
+
+        fadd            \o1\().4s, \o0\().4s, \t4\().4s             // out_o2
+        fsub            \o0\().4s, \o0\().4s, \t4\().4s             // out_o1
+.endm
+
+// Identical as FFT8, but does 2 transforms in parallel
+.macro FFT8_X2 e0, e1, o0, o1, e2, e3, o2, o3
+
+        movrel          x5, tab_8pt
+
+        fadd            v19.4s, \e3\().4s, \o3\().4s             // k1234
+        fadd            v17.4s, \e1\().4s, \o1\().4s             // k1234
+        fadd            v18.4s, \e2\().4s, \o2\().4s             // q1234
+        fadd            v16.4s, \e0\().4s, \o0\().4s             // q1234
+
+        ld1             { v23.4s }, [x5]
+
+        ext             v22.16b, v19.16b, v19.16b, #12
+        ext             v21.16b, v17.16b, v17.16b, #12
+
+        rev64           v22.4s,  v22.4s
+        rev64           v21.4s,  v21.4s
+
+        ext             v19.16b, v18.16b, v22.16b, #8
+        ext             v17.16b, v16.16b, v21.16b, #8
+
+        mov             v18.d[1], v22.d[1]
+        mov             v21.d[0], v16.d[0]
+
+        fadd            v22.4s, v18.4s, v19.4s                   // s12, g12
+        fsub            v19.4s, v18.4s, v19.4s                   // s34, g43
+        fsub            v18.4s, v21.4s, v17.4s                   // s34, g43
+        fadd            v16.4s, v21.4s, v17.4s                   // s12, g12
+
+        fsub            \e0\().4s, \e0\().4s, \o0\().4s          // r1234
+        fsub            v20.4s, \e1\().4s, \o1\().4s             // j1234
+        fsub            \e2\().4s, \e2\().4s, \o2\().4s          // r1234
+        fsub            v21.4s, \e3\().4s, \o3\().4s             // j1234
+
+        rev64           v24.4s, v31.4s                           // 1, -1, 1, -1
+        zip1            v17.2d, v16.2d, v18.2d                   // s1234
+        zip1            \e1\().2d, v22.2d, v19.2d                // s1234
+
+        rev64           v18.4s, v18.4s                           // xxg34
+        rev64           v19.4s, v19.4s                           // xxg34
+
+        zip2            v16.2d, v16.2d, v18.2d                   // g1234
+        zip2            \e3\().2d, v22.2d, v19.2d                // g1234
+
+        dup             \o0\().2d, \e0\().d[0]                   // r1212
+        dup             \o1\().2d, \e0\().d[1]                   // r3434
+        dup             \o2\().2d, \e2\().d[0]                   // r1212
+        dup             \o3\().2d, \e2\().d[1]                   // r3434
+
+        fadd            \e2\().4s, \e1\().4s, \e3\().4s          // out_e1
+        fsub            \e3\().4s, \e1\().4s, \e3\().4s          // out_e2
+        fadd            \e0\().4s, v17.4s, v16.4s                // out_e1
+        fsub            \e1\().4s, v17.4s, v16.4s                // out_e2
+
+        ext             v24.16b, v31.16b, v24.16b, #8            // -1, 1, 1, -1
+        rev64           \o1\().4s, \o1\().4s                     // r4343
+        rev64           \o3\().4s, \o3\().4s                     // r4343
+
+        fmul            v19.4s, v20.4s, v23.4s                   // j * +--+M_SQRT1_2
+        fmul            v21.4s, v21.4s, v23.4s                   // j * +--+M_SQRT1_2
+
+        rev64           v20.4s, v19.4s                           // j2143
+        rev64           v18.4s, v21.4s                           // j2143
+
+        fmls            \o0\().4s, \o1\().4s, v24.4s             // z1234
+        fmls            \o2\().4s, \o3\().4s, v24.4s             // z1234
+
+        fmla            v19.4s, v20.4s, v31.4s                   // l2143
+        fmla            v21.4s, v18.4s, v31.4s                   // l2143
+
+        rev64           v20.4s, v19.4s                           // l1234
+        rev64           v18.4s, v21.4s                           // l1234
+        ext             v20.16b, v20.16b, v20.16b, #8            // l3412
+        ext             v18.16b, v18.16b, v18.16b, #8            // l3412
+
+        fmla            v20.4s, v19.4s, v31.4s                   // t1234
+        fmla            v18.4s, v21.4s, v31.4s                   // t1234
+
+        fadd            \o1\().4s, \o0\().4s, v20.4s             // out_o2
+        fadd            \o3\().4s, \o2\().4s, v18.4s             // out_o2
+        fsub            \o0\().4s, \o0\().4s, v20.4s             // out_o1
+        fsub            \o2\().4s, \o2\().4s, v18.4s             // out_o1
+.endm
+
+const tab_16pt, align=4
+        .float   -COS16_1,    COS16_1,   -COS16_3,    COS16_3    // Could be +-+- too
+        .float    COS16_3,    COS16_3,    COS16_1,    COS16_1
+        .float        1.0,        1.0,  M_SQRT1_2,  M_SQRT1_2
+endconst
+
+// 16-point FFT
+// t3, t4, t5, t6 must be sequential
+.macro FFT16 e0, e1, e2, e3, o0, o1, o2, o3, \
+             t0=v16, t1=v17, t2=v18, t3=v19, t4=v20, t5=v21, t6=v22
+
+        FFT8            \e0, \e1, \e2, \e3, \t0, \t1, \t2, \t3, \t4, \t5, \t6
+        FFT4_X2         \o0, \o1, \o2, \o3, \t0, \t1, \t2, \t3, \t4, \t5, \t6
+
+        movrel          x5, tab_16pt
+
+        rev64           \t0\().4s, \o0\().4s                     // z[ 8, 9].imre
+        rev64           \t1\().4s, \o2\().4s                     // z[10,11].imre
+
+        ins             \t0\().d[0], xzr
+        ins             \t1\().d[0], xzr
+
+        ld1             { \t4\().4s, \t5\().4s, \t6\().4s }, [x5]
+        // TODO: We could derive \t4\() or \t5\() from either, but it seems cheaper to load
+
+        fmla            \o2\().4s, \t1\().4s, v31.4s             // s[4567]
+        fmls            \o0\().4s, \t0\().4s, v31.4s             // s[0123]
+
+        fmul            \t2\().4s, \o1\().4s, \t4\().4s
+        fmul            \t3\().4s, \o3\().4s, \t4\().4s
+
+        rev64           \o3\().4s, \o3\().4s
+        rev64           \o1\().4s, \o1\().4s
+
+        fmla            \t3\().4s, \o3\().4s, \t5\().4s          // s[12, 13, 14, 15]
+        fmls            \t2\().4s, \o1\().4s, \t5\().4s          // s[ 8,  9, 10, 11]
+
+        fmul            \t1\().4s, \o2\().4s, \t6\().4s          // s[4567] * mult
+        fmul            \t0\().4s, \o0\().4s, \t6\().4s          // s[0123] * mult
+
+        mov             \o1\().16b, \t3\().16b
+        mov             \o2\().16b, \t1\().16b
+
+        fsub            \t3\().4s, \t3\().4s, \t2\().4s          // y34, u34
+        fsub            \t1\().4s, \t1\().4s, \t0\().4s          // w34, x34
+
+        fadd            \t2\().4s, \t2\().4s, \o1\().4s          // y56, u56
+        rev64           \t3\().4s, \t3\().4s
+        fadd            \t0\().4s, \t0\().4s, \o2\().4s          // w56, x56
+        rev64           \t1\().4s, \t1\().4s
+
+        fmul            \t2\().4s, \t2\().4s, v31.4s
+        fmul            \t1\().4s, \t1\().4s, v31.4s
+
+        fadd            \o3\().4s, \e3\().4s, \t3\().4s
+        fsub            \o2\().4s, \e3\().4s, \t3\().4s
+        fsub            \o1\().4s, \e2\().4s, \t2\().4s
+        fadd            \o0\().4s, \e2\().4s, \t2\().4s
+
+        fsub            \e2\().4s, \e0\().4s, \t0\().4s
+        fadd            \e0\().4s, \e0\().4s, \t0\().4s
+        fsub            \e3\().4s, \e1\().4s, \t1\().4s
+        fadd            \e1\().4s, \e1\().4s, \t1\().4s
+.endm
+
+function ff_tx_fft2_float_neon, export=1
+        ld2r            { v0.2d, v1.2d }, [x2]
+
+        fneg            v2.2s, v1.2s
+        mov             v2.d[1], v1.d[0]
+
+        fsub            v2.4s, v0.4s, v2.4s
+
+        st1             { v2.4s }, [x1]
+        ret
+endfunc
+
+.macro FFT4_FN name, inv
+function ff_tx_fft4_\name\()_float_neon, export=1
+        ld1             {v0.4s, v1.4s}, [x2]
+
+.if \inv == 1
+        mov             v2.d[0], v0.d[1]
+        mov             v0.d[1], v1.d[1]
+        mov             v1.d[1], v2.d[0]
+.endif
+
+        FFT4            v0, v1, 1
+
+        st1             { v0.4s, v1.4s }, [x1]
+        ret
+endfunc
+.endm
+
+FFT4_FN fwd, 0
+FFT4_FN inv, 1
+
+.macro FFT8_FN name, no_perm
+function ff_tx_fft8_\name\()_neon, export=1
+        SETUP_LUT       \no_perm
+        LOAD_INPUT      0, 1, 2, 3, x2, \no_perm
+
+        LOAD_SUBADD
+        FFT8            v0, v1, v2, v3
+
+        zip1            v16.2d, v0.2d, v2.2d
+        zip2            v17.2d, v0.2d, v2.2d
+        zip1            v18.2d, v1.2d, v3.2d
+        zip2            v19.2d, v1.2d, v3.2d
+        st1             { v16.4s, v17.4s, v18.4s, v19.4s }, [x1]
+
+        ret
+endfunc
+.endm
+
+FFT8_FN float,    0
+FFT8_FN ns_float, 1
+
+.macro FFT16_FN name, no_perm
+function ff_tx_fft16_\name\()_neon, export=1
+        SETUP_LUT       \no_perm
+        LOAD_INPUT      0, 1, 2, 3, x2, \no_perm
+        LOAD_INPUT      4, 5, 6, 7, x2, \no_perm
+
+        LOAD_SUBADD
+        FFT16           v0, v1, v2, v3, v4, v5, v6, v7
+
+        zip1            v20.2d, v0.2d, v4.2d
+        zip2            v21.2d, v0.2d, v4.2d
+        zip1            v22.2d, v1.2d, v6.2d
+        zip2            v23.2d, v1.2d, v6.2d
+        st1             { v20.4s, v21.4s, v22.4s, v23.4s }, [x1], #64
+
+        zip1            v24.2d, v2.2d, v5.2d
+        zip2            v25.2d, v2.2d, v5.2d
+        zip1            v26.2d, v3.2d, v7.2d
+        zip2            v27.2d, v3.2d, v7.2d
+        st1             { v24.4s, v25.4s, v26.4s, v27.4s }, [x1]
+
+        ret
+endfunc
+.endm
+
+FFT16_FN float,    0
+FFT16_FN ns_float, 1
+
+.macro SETUP_SR_RECOMB len, re, im, dec
+        ldr             w5, =(\len - 4*7)
+        movrel          \re, X(ff_tx_tab_\len\()_float)
+        add             \im, \re, x5
+        mov             \dec, #-32
+
+.if \len > 32
+        mov             x21, #2*\len
+        add             x22, x21, x21, lsl #1
+.endif
+.endm
+
+.macro SR_COMBINE e0, e1, e2, e3, e4, e5, e6, e7, \
+                  o0, o1, o2, o3, o4, o5, o6, o7, \
+                  re, im, dec, swap_im, \
+                  t0=v16, t1=v17, t2=v18, t3=v19, t4=v20, t5=v21, \
+                  t6=v22, t7=v23, t8=v24, t9=v25, ta=v26, tb=v27
+
+        ld1             { \t8\().4s, \t9\().4s }, [\im], \dec
+        ld1             { \t0\().4s, \t1\().4s }, [\re], #32
+
+.if \swap_im == 1
+        ext             \t2\().16b, \t9\().16b, \t9\().16b, #8
+        ext             \t3\().16b, \t8\().16b, \t8\().16b, #8
+.else
+        ext             \t2\().16b, \t8\().16b, \t8\().16b, #8
+        ext             \t3\().16b, \t9\().16b, \t9\().16b, #8
+.endif
+
+        trn1            \t4\().4s, \t0\().4s, \t0\().4s      // cos0022
+        trn2            \t0\().4s, \t0\().4s, \t0\().4s      // cos4466
+        trn1            \t5\().4s, \t1\().4s, \t1\().4s      // cos1133
+        trn2            \t1\().4s, \t1\().4s, \t1\().4s      // cos5577
+
+        rev64           \t6\().4s, \o0\().4s                 // E m2[0,1].imre
+        rev64           \t7\().4s, \o2\().4s                 // O m2[0,1].imre
+        rev64           \t8\().4s, \o4\().4s                 // E m2[2,3].imre
+        rev64           \t9\().4s, \o6\().4s                 // O m2[2,3].imre
+
+        fmul            \t6\().4s, \t6\().4s, \t4\().4s      // E m2[0,1].imre*t1[0,2]
+        fmul            \t7\().4s, \t7\().4s, \t0\().4s      // O m2[0,1].imre*t1[0,2]
+        fmul            \t8\().4s, \t8\().4s, \t4\().4s      // E m2[2,3].imre*t1[0,2]
+        fmul            \t9\().4s, \t9\().4s, \t0\().4s      // O m2[2,3].imre*t1[0,2]
+
+        rev64           \ta\().4s, \o1\().4s                 // E m3[0,1].imre
+        rev64           \tb\().4s, \o3\().4s                 // O m3[0,1].imre
+        rev64           \t4\().4s, \o5\().4s                 // E m3[2,3].imre
+        rev64           \t0\().4s, \o7\().4s                 // O m3[2,3].imre
+
+        fmul            \ta\().4s, \ta\().4s, \t5\().4s      // E m3[0,1].imre*t1[4,6]
+        fmul            \tb\().4s, \tb\().4s, \t1\().4s      // O m3[0,1].imre*t1[4,6]
+        fmul            \t4\().4s, \t4\().4s, \t5\().4s      // E m3[2,3].imre*t1[4,6]
+        fmul            \t0\().4s, \t0\().4s, \t1\().4s      // O m3[2,3].imre*t1[4,6]
+
+        trn1            \t5\().4s, \t3\().4s, \t3\().4s      // wim2200
+        trn2            \t3\().4s, \t3\().4s, \t3\().4s      // wim3311
+        trn1            \t1\().4s, \t2\().4s, \t2\().4s      // wim6644
+        trn2            \t2\().4s, \t2\().4s, \t2\().4s      // wim7755
+
+        fmul            \t5\().4s, \t5\().4s, v31.4s
+        fmul            \t3\().4s, \t3\().4s, v31.4s
+        fmul            \t1\().4s, \t1\().4s, v31.4s
+        fmul            \t2\().4s, \t2\().4s, v31.4s
+
+        fmla            \t7\().4s, \o2\().4s, \t5\().4s      // O w0123
+        fmls            \t9\().4s, \o6\().4s, \t5\().4s      // O j0123
+        fmla            \t6\().4s, \o0\().4s, \t3\().4s      // E w0123
+        fmls            \t8\().4s, \o4\().4s, \t3\().4s      // E j0123
+
+        fmla            \ta\().4s, \o1\().4s, \t2\().4s      // E w4567
+        fmla            \tb\().4s, \o3\().4s, \t1\().4s      // O w4567
+        fmls            \t4\().4s, \o5\().4s, \t2\().4s      // E j4567
+        fmls            \t0\().4s, \o7\().4s, \t1\().4s      // O j4567
+
+        fsub            \t2\().4s, \t7\().4s, \t9\().4s
+        fsub            \t1\().4s, \t8\().4s, \t6\().4s
+        fsub            \t3\().4s, \t4\().4s, \ta\().4s
+        fsub            \t5\().4s, \t0\().4s, \tb\().4s
+
+        fadd            \t6\().4s, \t8\().4s, \t6\().4s
+        fadd            \t7\().4s, \t9\().4s, \t7\().4s
+        fadd            \t8\().4s, \t4\().4s, \ta\().4s
+        fadd            \t9\().4s, \t0\().4s, \tb\().4s
+
+        fmul            \t1\().4s, \t1\().4s, v31.4s
+        fmul            \t2\().4s, \t2\().4s, v31.4s
+        fmul            \t3\().4s, \t3\().4s, v31.4s
+        fmul            \t5\().4s, \t5\().4s, v31.4s
+
+        rev64           \t6\().4s, \t6\().4s
+        rev64           \t8\().4s, \t8\().4s
+        rev64           \t7\().4s, \t7\().4s
+        rev64           \t9\().4s, \t9\().4s
+
+        fsub            \o0\().4s, \e0\().4s, \t6\().4s
+        fsub            \o1\().4s, \e1\().4s, \t8\().4s
+        fsub            \o2\().4s, \e2\().4s, \t1\().4s
+        fsub            \o3\().4s, \e3\().4s, \t3\().4s
+
+        fsub            \o4\().4s, \e4\().4s, \t7\().4s
+        fsub            \o5\().4s, \e6\().4s, \t9\().4s
+        fadd            \o6\().4s, \e5\().4s, \t2\().4s
+        fsub            \o7\().4s, \e7\().4s, \t5\().4s
+
+        fadd            \e0\().4s, \e0\().4s, \t6\().4s
+        fadd            \e1\().4s, \e1\().4s, \t8\().4s
+        fadd            \e2\().4s, \e2\().4s, \t1\().4s
+        fadd            \e3\().4s, \e3\().4s, \t3\().4s
+
+        fadd            \e4\().4s, \e4\().4s, \t7\().4s
+        fsub            \e5\().4s, \e5\().4s, \t2\().4s      // swapped
+        fadd            \e6\().4s, \e6\().4s, \t9\().4s      // swapped
+        fadd            \e7\().4s, \e7\().4s, \t5\().4s
+.endm
+
+.macro SR_COMBINE_HALF e0, e1, e2, e3, \
+                       o0, o1, o2, o3, \
+                       c0, c1, c2, c3, \
+                       t0, t1, t2, t3, t4, t5, part
+
+.if \part == 0
+        trn1            \t4\().4s, \c0\().4s, \c0\().4s   // cos0022
+        trn1            \c1\().4s, \c1\().4s, \c1\().4s   // cos1133
+.else
+        trn2            \t4\().4s, \c0\().4s, \c0\().4s   // cos0022
+        trn2            \c1\().4s, \c1\().4s, \c1\().4s   // cos1133
+.endif
+.if \part == 0
+        trn2            \t5\().4s, \c2\().4s, \c2\().4s   // wim7755
+        trn2            \c3\().4s, \c3\().4s, \c3\().4s   // wim3311
+.else
+        trn1            \t5\().4s, \c2\().4s, \c2\().4s   // wim7755
+        trn1            \c3\().4s, \c3\().4s, \c3\().4s   // wim3311
+.endif
+
+        fmul            \t5\().4s, \t5\().4s, v31.4s
+        fmul            \c3\().4s, \c3\().4s, v31.4s
+
+        rev64           \t0\().4s, \o0\().4s              // E m2[0,1].imre
+        rev64           \t1\().4s, \o2\().4s              // E m2[2,3].imre
+        rev64           \t2\().4s, \o1\().4s              // E m3[0,1].imre
+        rev64           \t3\().4s, \o3\().4s              // E m3[2,3].imre
+
+        fmul            \o0\().4s, \o0\().4s, \c3\().4s   // E m2[0,1].imre*t1[0,2]
+        fmul            \o1\().4s, \o1\().4s, \t5\().4s   // E m3[0,1].imre*t1[4,6]
+        fmla            \o0\().4s, \t0\().4s, \t4\().4s   // E w0123
+        fmla            \o1\().4s, \t2\().4s, \c1\().4s   // E w4567
+
+        fmul            \t1\().4s, \t1\().4s, \t4\().4s   // E m2[2,3].imre*t1[0,2]
+        fmul            \t3\().4s, \t3\().4s, \c1\().4s   // E m3[2,3].imre*t1[4,6]
+        fmls            \t1\().4s, \o2\().4s, \c3\().4s   // E j0123
+        fmls            \t3\().4s, \o3\().4s, \t5\().4s   // E j4567
+
+        fsub            \t0\().4s, \t1\().4s, \o0\().4s
+        fadd            \t1\().4s, \t1\().4s, \o0\().4s
+        fadd            \t2\().4s, \t3\().4s, \o1\().4s
+        fsub            \t3\().4s, \t3\().4s, \o1\().4s
+
+        fmul            \t0\().4s, \t0\().4s, v31.4s
+        fmul            \t3\().4s, \t3\().4s, v31.4s
+
+        rev64           \t1\().4s, \t1\().4s
+        rev64           \t2\().4s, \t2\().4s
+
+.if \part == 0
+        fsub            \o0\().4s, \e0\().4s, \t1\().4s
+        fsub            \o1\().4s, \e1\().4s, \t2\().4s
+        fsub            \o2\().4s, \e2\().4s, \t0\().4s
+        fsub            \o3\().4s, \e3\().4s, \t3\().4s
+.else
+        fsub            \o0\().4s, \e0\().4s, \t1\().4s
+        fadd            \o2\().4s, \e1\().4s, \t2\().4s
+        fsub            \o1\().4s, \e2\().4s, \t0\().4s
+        fadd            \o3\().4s, \e3\().4s, \t3\().4s
+.endif
+
+.if \part == 0
+        fadd            \e0\().4s, \e0\().4s, \t1\().4s
+        fadd            \e1\().4s, \e1\().4s, \t2\().4s
+        fadd            \e2\().4s, \e2\().4s, \t0\().4s
+        fadd            \e3\().4s, \e3\().4s, \t3\().4s
+.else
+        fadd            \e0\().4s, \e0\().4s, \t1\().4s
+        fsub            \e1\().4s, \e1\().4s, \t2\().4s   // swapped
+        fadd            \e2\().4s, \e2\().4s, \t0\().4s   // swapped
+        fsub            \e3\().4s, \e3\().4s, \t3\().4s
+.endif
+.endm
+
+/* Same as SR_COMBINE_HALF, but heroically tries to use 3 temporary registers
+ * without touching the tables. */
+.macro SR_COMBINE_LITE e0, e1, e2, e3, \
+                       o0, o1, o2, o3, \
+                       c0, c1, c2, c3, \
+                       t0, t1, t2, part
+
+        rev64           \t0\().4s, \o0\().4s              // E m2[0,1].imre
+        rev64           \t1\().4s, \o2\().4s              // E m2[2,3].imre
+.if \part == 0
+        trn2            \t2\().4s, \c3\().4s, \c3\().4s   // wim3311
+.else
+        trn1            \t2\().4s, \c3\().4s, \c3\().4s   // wim3311
+.endif
+        fmul            \t2\().4s, \t2\().4s, v31.4s
+        fmul            \o2\().4s, \o2\().4s, \t2\().4s
+        fmul            \o0\().4s, \o0\().4s, \t2\().4s   // E m2[0,1].imre*t1[0,2]
+.if \part == 0
+        trn1            \t2\().4s, \c0\().4s, \c0\().4s   // cos0022
+.else
+        trn2            \t2\().4s, \c0\().4s, \c0\().4s   // cos0022
+.endif
+        fmul            \t1\().4s, \t1\().4s, \t2\().4s   // E m2[2,3].imre*t1[0,2]
+        fmla            \o0\().4s, \t0\().4s, \t2\().4s   // E w0123
+        fsub            \t1\().4s, \t1\().4s, \o2\().4s   // E j0123
+
+        rev64           \t2\().4s, \o1\().4s              // E m3[0,1].imre
+        rev64           \o2\().4s, \o3\().4s              // E m3[2,3].imre
+
+.if \part == 0
+        trn2            \t0\().4s, \c2\().4s, \c2\().4s   // wim7755
+.else
+        trn1            \t0\().4s, \c2\().4s, \c2\().4s   // wim7755
+.endif
+        fmul            \t0\().4s, \t0\().4s, v31.4s
+
+        fmul            \o1\().4s, \o1\().4s, \t0\().4s   // E m3[0,1].imre*t1[4,6]
+        fmul            \o3\().4s, \o3\().4s, \t0\().4s
+
+.if \part == 0
+        trn1            \t0\().4s, \c1\().4s, \c1\().4s   // cos1133
+.else
+        trn2            \t0\().4s, \c1\().4s, \c1\().4s   // cos1133
+.endif
+        fmul            \o2\().4s, \o2\().4s, \t0\().4s   // E m3[2,3].imre*t1[4,6]
+        fmla            \o1\().4s, \t2\().4s, \t0\().4s   // E w4567
+        fsub            \o2\().4s, \o2\().4s, \o3\().4s   // E j4567
+
+        fsub            \t0\().4s, \t1\().4s, \o0\().4s
+        fadd            \o0\().4s, \t1\().4s, \o0\().4s
+        fadd            \t2\().4s, \o2\().4s, \o1\().4s
+        fsub            \t1\().4s, \o2\().4s, \o1\().4s
+
+        fmul            \t0\().4s, \t0\().4s, v31.4s
+        fmul            \t1\().4s, \t1\().4s, v31.4s
+
+        rev64           \t2\().4s, \t2\().4s
+        rev64           \o0\().4s, \o0\().4s
+
+.if \part == 0
+        fsub            \o1\().4s, \e1\().4s, \t2\().4s
+        fsub            \o2\().4s, \e2\().4s, \t0\().4s
+        fsub            \o3\().4s, \e3\().4s, \t1\().4s
+.else
+        fadd            \o2\().4s, \e1\().4s, \t0\().4s
+        fsub            \o1\().4s, \e2\().4s, \t2\().4s
+        fadd            \o3\().4s, \e3\().4s, \t1\().4s
+.endif
+
+.if \part == 0
+        fadd            \e1\().4s, \e1\().4s, \t2\().4s
+        fadd            \e2\().4s, \e2\().4s, \t0\().4s
+        fadd            \e3\().4s, \e3\().4s, \t1\().4s
+.else
+        fsub            \e1\().4s, \e1\().4s, \t0\().4s   // swapped
+        fadd            \e2\().4s, \e2\().4s, \t2\().4s   // swapped
+        fsub            \e3\().4s, \e3\().4s, \t1\().4s
+.endif
+
+        mov             \t1\().16b, \o0\().16b
+
+        fsub            \o0\().4s, \e0\().4s, \t1\().4s
+        fadd            \e0\().4s, \e0\().4s, \t1\().4s
+.endm
+
+.macro SR_COMBINE_4 len, part, off
+        add             x10, x1, x21
+        add             x11, x1, x21, lsl #1
+        add             x12, x1, x22
+
+        ldp             q0,  q1,  [x1,  #((0 + \part)*32 + \off)]
+        ldp             q4,  q5,  [x1,  #((2 + \part)*32 + \off)]
+        ldp             q2,  q3,  [x10, #((0 + \part)*32 + \off)]
+        ldp             q6,  q7,  [x10, #((2 + \part)*32 + \off)]
+
+        ldp             q8,  q9,  [x11, #((0 + \part)*32 + \off)]
+        ldp             q10, q11, [x11, #((2 + \part)*32 + \off)]
+        ldp             q12, q13, [x12, #((0 + \part)*32 + \off)]
+        ldp             q14, q15, [x12, #((2 + \part)*32 + \off)]
+
+        SR_COMBINE      v0,  v1,  v2,  v3,  v4,  v6,  v5,  v7, \
+                        v8,  v9, v10, v11, v12, v13, v14, v15, \
+                        x7,  x8, x9, 0
+
+        stp             q0,  q1,  [x1,  #((0 + \part)*32 + \off)]
+        stp             q4,  q5,  [x1,  #((2 + \part)*32 + \off)]
+        stp             q2,  q3,  [x10, #((0 + \part)*32 + \off)]
+        stp             q6,  q7,  [x10, #((2 + \part)*32 + \off)]
+
+        stp             q8,  q9,  [x11, #((0 + \part)*32 + \off)]
+        stp             q12, q13, [x11, #((2 + \part)*32 + \off)]
+        stp             q10, q11, [x12, #((0 + \part)*32 + \off)]
+        stp             q14, q15, [x12, #((2 + \part)*32 + \off)]
+.endm
+
+.macro SR_COMBINE_FULL len, off=0
+        add             x10, x1, x21
+        add             x11, x1, x21, lsl #1
+        add             x12, x1, x22
+
+        SR_COMBINE_4    \len, 0, \off
+        SR_COMBINE_4    \len, 1, \off
+        SR_COMBINE_4    \len, 4, \off
+        SR_COMBINE_4    \len, 5, \off
+.endm
+
+.macro SR_COMBINE_D2 part, off
+        add             x10,  x1, #((\part)*32 + \off)
+        add             x11, x14, #((\part)*32 + \off)
+        add             x12, x15, #((\part)*32 + \off)
+        add             x13, x16, #((\part)*32 + \off)
+
+        ldp             q0,  q1,  [x10]
+        ldp             q4,  q5,  [x10, #(2*32)]
+        ldp             q2,  q3,  [x11]
+        ldp             q6,  q7,  [x11, #(2*32)]
+
+        ldp             q8,  q9,  [x12]
+        ldp             q10, q11, [x12, #(2*32)]
+        ldp             q12, q13, [x13]
+        ldp             q14, q15, [x13, #(2*32)]
+
+        SR_COMBINE      v0,  v1,  v2,  v3,  v4,  v6,  v5,  v7, \
+                        v8,  v9, v10, v11, v12, v13, v14, v15, \
+                        x7,  x8, x9, 0, \
+                        v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27
+
+        zip1            v16.2d, v0.2d, v4.2d
+        zip2            v17.2d, v0.2d, v4.2d
+        zip1            v18.2d, v1.2d, v5.2d
+        zip2            v19.2d, v1.2d, v5.2d
+
+        zip1            v20.2d, v2.2d, v6.2d
+        zip2            v21.2d, v2.2d, v6.2d
+        zip1            v22.2d, v3.2d, v7.2d
+        zip2            v23.2d, v3.2d, v7.2d
+
+        ldp             q0,  q1,  [x10, #(1*32)]
+        ldp             q4,  q5,  [x10, #(3*32)]
+        ldp             q2,  q3,  [x11, #(1*32)]
+        ldp             q6,  q7,  [x11, #(3*32)]
+
+        st1             { v16.4s, v17.4s, v18.4s, v19.4s }, [x10], #64
+        st1             { v20.4s, v21.4s, v22.4s, v23.4s }, [x11], #64
+
+        zip1            v20.2d, v8.2d, v12.2d
+        zip2            v21.2d, v8.2d, v12.2d
+        zip1            v22.2d, v9.2d, v13.2d
+        zip2            v23.2d, v9.2d, v13.2d
+        zip1            v24.2d, v10.2d, v14.2d
+        zip2            v25.2d, v10.2d, v14.2d
+        zip1            v26.2d, v11.2d, v15.2d
+        zip2            v27.2d, v11.2d, v15.2d
+
+        ldp             q8,  q9,  [x12, #(1*32)]
+        ldp             q10, q11, [x12, #(3*32)]
+        ldp             q12, q13, [x13, #(1*32)]
+        ldp             q14, q15, [x13, #(3*32)]
+
+        st1             { v20.4s, v21.4s, v22.4s, v23.4s }, [x12], #64
+        st1             { v24.4s, v25.4s, v26.4s, v27.4s }, [x13], #64
+
+        SR_COMBINE      v0,  v1,  v2,  v3,  v4,  v6,  v5,  v7, \
+                        v8,  v9, v10, v11, v12, v13, v14, v15, \
+                        x7,  x8, x9, 0, \
+                        v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27
+
+        zip1            v16.2d, v0.2d, v4.2d
+        zip2            v17.2d, v0.2d, v4.2d
+        zip1            v18.2d, v1.2d, v5.2d
+        zip2            v19.2d, v1.2d, v5.2d
+        st1             { v16.4s, v17.4s, v18.4s, v19.4s }, [x10]
+
+        zip1            v16.2d, v2.2d, v6.2d
+        zip2            v17.2d, v2.2d, v6.2d
+        zip1            v18.2d, v3.2d, v7.2d
+        zip2            v19.2d, v3.2d, v7.2d
+        st1             { v16.4s, v17.4s, v18.4s, v19.4s }, [x11]
+
+        zip1            v20.2d, v8.2d, v12.2d
+        zip2            v21.2d, v8.2d, v12.2d
+        zip1            v22.2d, v9.2d, v13.2d
+        zip2            v23.2d, v9.2d, v13.2d
+        st1             { v20.4s, v21.4s, v22.4s, v23.4s }, [x12]
+
+        zip1            v24.2d, v10.2d, v14.2d
+        zip2            v25.2d, v10.2d, v14.2d
+        zip1            v26.2d, v11.2d, v15.2d
+        zip2            v27.2d, v11.2d, v15.2d
+        st1             { v24.4s, v25.4s, v26.4s, v27.4s }, [x13]
+.endm
+
+.macro SR_COMBINE_DINT off=0
+        add             x14, x1, x21
+        add             x15, x1, x21, lsl #1
+        add             x16, x1, x22
+
+        SR_COMBINE_D2   0, \off
+        SR_COMBINE_D2   4, \off
+.endm
+
+.macro FFT32_FN name, no_perm
+function ff_tx_fft32_\name\()_neon, export=1
+        stp             d14, d15, [sp, #-16*4]!
+        stp             d8,  d9,  [sp, #16*3]
+        stp             d10, d11, [sp, #16*2]
+        stp             d12, d13, [sp, #16]
+
+        LOAD_SUBADD
+        SETUP_SR_RECOMB 32, x7, x8, x9
+
+        SETUP_LUT       \no_perm
+        LOAD_INPUT      0,  1,  2,  3,  x2, \no_perm
+        LOAD_INPUT      4,  5,  6,  7,  x2, \no_perm
+        LOAD_INPUT      8,  9,  10, 11, x2, \no_perm
+        LOAD_INPUT      12, 13, 14, 15, x2, \no_perm
+
+        FFT8_X2         v8, v9, v10, v11, v12, v13, v14, v15
+        FFT16           v0, v1, v2, v3, v4, v5, v6, v7
+
+        SR_COMBINE      v0,  v1,  v2,  v3,  v4,  v5,  v6,  v7, \
+                        v8,  v9, v10, v11, v12, v13, v14, v15, \
+                        x7,  x8,  x9, 0
+
+        zip1            v16.2d, v0.2d, v4.2d
+        zip2            v17.2d, v0.2d, v4.2d
+        zip1            v18.2d, v1.2d, v6.2d
+        zip2            v19.2d, v1.2d, v6.2d
+        st1             { v16.4s, v17.4s, v18.4s, v19.4s }, [x1], #64
+
+        zip1            v20.2d, v2.2d, v5.2d
+        zip2            v21.2d, v2.2d, v5.2d
+        zip1            v22.2d, v3.2d, v7.2d
+        zip2            v23.2d, v3.2d, v7.2d
+        st1             { v20.4s, v21.4s, v22.4s, v23.4s }, [x1], #64
+
+        zip1            v24.2d, v8.2d, v12.2d
+        zip2            v25.2d, v8.2d, v12.2d
+        zip1            v26.2d, v9.2d, v13.2d
+        zip2            v27.2d, v9.2d, v13.2d
+        st1             { v24.4s, v25.4s, v26.4s, v27.4s }, [x1], #64
+
+        zip1            v28.2d, v10.2d, v14.2d
+        zip2            v29.2d, v10.2d, v14.2d
+        zip1            v30.2d, v11.2d, v15.2d
+        zip2            v31.2d, v11.2d, v15.2d
+        st1             { v28.4s, v29.4s, v30.4s, v31.4s }, [x1]
+
+        ldp             d12, d13, [sp, #16]
+        ldp             d10, d11, [sp, #16*2]
+        ldp             d8,  d9,  [sp, #16*3]
+        ldp             d14, d15, [sp], #16*4
+
+        ret
+endfunc
+.endm
+
+FFT32_FN float,    0
+FFT32_FN ns_float, 1
+
+.macro cmp_imm reg, imm
+.if \imm >= 4096
+        cmp             \reg, #((\imm)/4096), lsl #12
+.else
+        cmp             \reg, #(\imm)
+.endif
+.endm
+
+.macro SR_TRANSFORM_DEF len, next=0
+\len:
+        stp             x20, x30, [sp, #-16]!
+        mov             w20, #(\len/4)
+        mov             x5, #((\len*4) - (\len/1))
+        add             x1, x1, x5
+        bl              32b
+        mov             x5, #((\len*2) - (\len/2))
+        add             x1, x1, x5
+        bl              32b
+        ldp             x20, x30, [sp], #16
+        ldr             w5, =(\len*6 + \len/2)
+        sub             x1, x1, x5
+
+        SETUP_SR_RECOMB \len, x7, x8, x9
+
+.if \next\() != 0
+        cmp_imm         w19, \len
+        b.eq            0f
+
+        mov             w5, #(\len/128)
+\len\()5:
+        SR_COMBINE_FULL \len
+        add             x1, x1, 8*32
+        subs            w5, w5, 1
+        b.gt            \len\()5b
+
+        cmp_imm         w20, \len
+        b.gt            \next\()f
+        ret
+.endif
+.endm
+
+.macro FFT_SPLIT_RADIX_FN name, no_perm
+function ff_tx_fft_sr_\name\()_neon, export=1
+        stp             x21, x22, [sp, #-16*6]!
+        stp             d8,  d9,  [sp, #16*5]
+        stp             d10, d11, [sp, #16*4]
+        stp             d12, d13, [sp, #16*3]
+        stp             d14, d15, [sp, #16*2]
+        stp             x19, x20, [sp, #16]
+
+        ldr             w19, [x0, #0] // global target
+        mov             w20, w19      // local length
+
+        LOAD_SUBADD
+        SETUP_LUT       \no_perm
+
+32:
+        SETUP_SR_RECOMB 32, x7, x8, x9
+
+        LOAD_INPUT      0,  1,  2,  3,  x2, \no_perm
+        LOAD_INPUT      4,  6,  5,  7,  x2, \no_perm, 1
+        LOAD_INPUT      8,  9,  10, 11, x2, \no_perm
+        LOAD_INPUT      12, 13, 14, 15, x2, \no_perm
+
+        FFT8_X2         v8, v9, v10, v11, v12, v13, v14, v15
+        FFT16           v0, v1, v2, v3, v4, v6, v5, v7
+
+        SR_COMBINE      v0,  v1,  v2,  v3,  v4,  v6,  v5,  v7,  \
+                        v8,  v9,  v10, v11, v12, v13, v14, v15, \
+                        x7,  x8,  x9,  0
+
+        stp             q2,  q3,  [x1, #32*1]
+        stp             q6,  q7,  [x1, #32*3]
+        stp             q10, q11, [x1, #32*5]
+        stp             q14, q15, [x1, #32*7]
+
+        cmp             w20, #32
+        b.gt            64f
+
+        stp             q0,  q1,  [x1, #32*0]
+        stp             q4,  q5,  [x1, #32*2]
+        stp             q8,  q9,  [x1, #32*4]
+        stp             q12, q13, [x1, #32*6]
+
+        ret
+64:
+        SETUP_SR_RECOMB 64, x7, x8, x9
+
+        LOAD_INPUT      2,  3,  10, 11, x2, \no_perm, 1
+        LOAD_INPUT      6,  14, 7,  15, x2, \no_perm, 1
+
+        FFT16           v2, v3, v10, v11, v6, v14, v7, v15
+
+        LOAD_INPUT      16, 17, 18, 19, x2, \no_perm
+        LOAD_INPUT      20, 22, 21, 23, x2, \no_perm, 1
+
+        FFT16           v16, v17, v18, v19, v20, v22, v21, v23, \
+                        v24, v25, v26, v27, v28, v29, v30
+
+        ld1             { v26.4s, v27.4s }, [x8], x9
+        ldp             q24, q25, [x7], #32
+
+        ext             v26.16b, v26.16b, v26.16b, #8
+        ext             v27.16b, v27.16b, v27.16b, #8
+
+        cmp             w19, #64
+        b.eq            2f // custom deinterleave
+
+        // TODO: investigate doing the 2 combines like in deinterleave
+        // TODO: experiment with spilling to gprs and converting to HALF or full
+        SR_COMBINE_LITE v0,  v1,  v8,  v9,  \
+                        v2,  v3,  v16, v17, \
+                        v24, v25, v26, v27, \
+                        v28, v29, v30, 0
+
+        stp             q0,  q1,  [x1, #32* 0]
+        stp             q8,  q9,  [x1, #32* 4]
+        stp             q2,  q3,  [x1, #32* 8]
+        stp             q16, q17, [x1, #32*12]
+
+        SR_COMBINE_HALF v4,  v5,  v12, v13, \
+                        v6,  v7,  v20, v21, \
+                        v24, v25, v26, v27, \
+                        v28, v29, v30, v0, v1, v8, 1
+
+        stp             q4,  q20, [x1, #32* 2]
+        stp             q12, q21, [x1, #32* 6]
+        stp             q6,  q5,  [x1, #32*10]
+        stp             q7,  q13, [x1, #32*14]
+
+        ldp             q2,  q3,  [x1, #32*1]
+        ldp             q6,  q7,  [x1, #32*3]
+        ldp             q12, q13, [x1, #32*5]
+        ldp             q16, q17, [x1, #32*7]
+
+        SR_COMBINE      v2,  v3,  v12, v13, v6,  v16, v7,  v17, \
+                        v10, v11, v14, v15, v18, v19, v22, v23, \
+                        x7,  x8,  x9,  0, \
+                        v24, v25, v26, v27, v28, v29, v30, v8, v0, v1, v4, v5
+
+        stp             q2,  q3,  [x1, #32* 1]
+        stp             q6,  q7,  [x1, #32* 3]
+        stp             q12, q13, [x1, #32* 5]
+        stp             q16, q17, [x1, #32* 7]
+
+        stp             q10, q11, [x1, #32* 9]
+        stp             q18, q19, [x1, #32*11]
+        stp             q14, q15, [x1, #32*13]
+        stp             q22, q23, [x1, #32*15]
+
+        cmp             w20, #64
+        b.gt            128f
+        ret
+128:
+        stp             x20, x30, [sp, #-16]!
+        mov             w20, #32
+        add             x1, x1, #16*32
+        bl              32b
+        add             x1, x1, #8*32
+        bl              32b
+        ldp             x20, x30, [sp], #16
+        sub             x1, x1, #24*32
+
+        SETUP_SR_RECOMB 128, x7, x8, x9
+
+        cmp             w19, #128
+        b.eq            0f
+
+        SR_COMBINE_FULL 128
+
+        cmp             w20, #128
+        b.gt            256f
+        ret
+256:
+        stp             x20, x30, [sp, #-16]!
+        mov             w20, #64
+        add             x1, x1, #32*32
+        bl              32b
+        add             x1, x1, #16*32
+        bl              32b
+        ldp             x20, x30, [sp], #16
+        sub             x1, x1, #48*32
+
+        SETUP_SR_RECOMB 256, x7, x8, x9
+
+        cmp             w19, #256
+        b.eq            0f
+
+        SR_COMBINE_FULL 256
+        SR_COMBINE_FULL 256, 8*32
+
+        cmp             w20, #256
+        b.gt            512f
+        ret
+512:
+        stp             x20, x30, [sp, #-16]!
+        mov             w20, #128
+        add             x1, x1, #64*32
+        bl              32b
+        add             x1, x1, #32*32
+        bl              32b
+        ldp             x20, x30, [sp], #16
+        sub             x1, x1, #96*32
+
+        SETUP_SR_RECOMB 512, x7, x8, x9
+
+        cmp             w19, #512
+        b.eq            0f
+
+        mov             x5, 4
+5125:
+        SR_COMBINE_FULL 512
+        add             x1, x1, 8*32
+        subs            w5, w5, 1
+        b.gt            5125b
+
+        cmp             w20, #512
+        b.gt            1024f
+
+        ret
+1024:
+        stp             x20, x30, [sp, #-16]!
+        mov             w20, #256
+        add             x1, x1, #96*32
+        bl              32b
+        add             x1, x1, #64*32
+        bl              32b
+        ldp             x20, x30, [sp], #16
+        mov             x5, #192*32
+        sub             x1, x1, x5
+
+        SETUP_SR_RECOMB 1024, x7, x8, x9
+
+        cmp             w19, #1024
+        b.eq            0f
+
+        mov             w5, 8
+10245:
+        SR_COMBINE_FULL 1024
+        add             x1, x1, 8*32
+        subs            w5, w5, 1
+        b.gt            10245b
+
+        cmp             w20, #1024
+        b.gt            2048f
+
+        ret
+
+SR_TRANSFORM_DEF        2048, 4096
+SR_TRANSFORM_DEF        4096, 8192
+SR_TRANSFORM_DEF        8192, 16384
+SR_TRANSFORM_DEF        16384, 32768
+SR_TRANSFORM_DEF        32768, 65536
+SR_TRANSFORM_DEF        65536, 131072
+SR_TRANSFORM_DEF        131072
+
+0: // general deinterleave loop
+        SR_COMBINE_DINT
+        add             x1, x1, #32*8
+        subs            w19, w19, #32*4
+        b.gt            0b
+
+        ldp             x19, x20, [sp, #16]
+        ldp             d14, d15, [sp, #16*2]
+        ldp             d12, d13, [sp, #16*3]
+        ldp             d10, d11, [sp, #16*4]
+        ldp             d8,  d9,  [sp, #16*5]
+        ldp             x21, x22, [sp], #16*6
+
+        ret
+
+2: // special case for 64 point deinterleave
+        mov             x10, v23.d[0]
+        mov             x11, v23.d[1]
+
+        SR_COMBINE_LITE v0,  v1,  v8,  v9,  \
+                        v2,  v3,  v16, v17, \
+                        v24, v25, v26, v27, \
+                        v28, v29, v30, 0
+
+        SR_COMBINE_HALF v4,  v5,  v12, v13, \
+                        v6,  v7,  v20, v21, \
+                        v24, v25, v26, v27, \
+                        v28, v29, v30, v23, v24, v26, 1
+
+        zip1            v23.2d, v0.2d, v4.2d
+        zip2            v24.2d, v0.2d, v4.2d
+        zip1            v25.2d, v1.2d, v20.2d
+        zip2            v26.2d, v1.2d, v20.2d
+
+        zip1            v27.2d, v8.2d, v12.2d
+        zip2            v28.2d, v8.2d, v12.2d
+        zip1            v29.2d, v9.2d, v21.2d
+        zip2            v30.2d, v9.2d, v21.2d
+
+        mov             v20.16b, v5.16b
+        mov             v21.16b, v7.16b
+        mov             x12, x1
+        add             x13, x1, #32* 4
+        add             x14, x1, #32* 8
+        add             x15, x1, #32*12
+
+        zip1            v4.2d,  v2.2d, v6.2d
+        zip2            v5.2d,  v2.2d, v6.2d
+        zip1            v6.2d,  v3.2d, v20.2d
+        zip2            v7.2d,  v3.2d, v20.2d
+
+        zip1            v0.2d, v16.2d, v21.2d
+        zip2            v1.2d, v16.2d, v21.2d
+        zip1            v2.2d, v17.2d, v13.2d
+        zip2            v3.2d, v17.2d, v13.2d
+
+        // stp is faster by a little on A53, but this is faster on M1s (theory)
+        ldp             q8,  q9, [x1, #32*1]
+        ldp             q12, q13, [x1, #32*5]
+
+        st1             { v23.4s, v24.4s, v25.4s, v26.4s }, [x12], #64  // 32* 0...1
+        st1             { v27.4s, v28.4s, v29.4s, v30.4s }, [x13], #64  // 32* 4...5
+        st1             {  v4.4s,  v5.4s,  v6.4s,  v7.4s }, [x14], #64  // 32* 8...9
+        st1             {  v0.4s,  v1.4s,  v2.4s,  v3.4s }, [x15], #64  // 32*12..13
+
+        mov             v23.d[0], x10
+        mov             v23.d[1], x11
+
+        ldp             q6,  q7, [x1, #32*3]
+        ldp             q16, q17, [x1, #32*7]
+
+        SR_COMBINE      v8,  v9,  v12, v13, v6,  v16, v7,  v17, \
+                        v10, v11, v14, v15, v18, v19, v22, v23, \
+                        x7,  x8,  x9,  0, \
+                        v24, v25, v26, v27, v28, v29, v30, v4, v0, v1, v5, v20
+
+        zip1            v0.2d, v8.2d, v6.2d
+        zip2            v1.2d, v8.2d, v6.2d
+        zip1            v2.2d, v9.2d, v7.2d
+        zip2            v3.2d, v9.2d, v7.2d
+        st1             {  v0.4s,  v1.4s,  v2.4s,  v3.4s }, [x12]
+
+        zip1            v4.2d, v12.2d, v16.2d
+        zip2            v5.2d, v12.2d, v16.2d
+        zip1            v6.2d, v13.2d, v17.2d
+        zip2            v7.2d, v13.2d, v17.2d
+        st1             {  v4.4s,  v5.4s,  v6.4s,  v7.4s }, [x13]
+
+        zip1            v0.2d, v10.2d, v18.2d
+        zip2            v1.2d, v10.2d, v18.2d
+        zip1            v2.2d, v11.2d, v19.2d
+        zip2            v3.2d, v11.2d, v19.2d
+        st1             {  v0.4s,  v1.4s,  v2.4s,  v3.4s }, [x14]
+
+        zip1            v4.2d, v14.2d, v22.2d
+        zip2            v5.2d, v14.2d, v22.2d
+        zip1            v6.2d, v15.2d, v23.2d
+        zip2            v7.2d, v15.2d, v23.2d
+        st1             {  v4.4s,  v5.4s,  v6.4s,  v7.4s }, [x15]
+
+        ldp             x19, x20, [sp, #16]
+        ldp             d14, d15, [sp, #16*2]
+        ldp             d12, d13, [sp, #16*3]
+        ldp             d10, d11, [sp, #16*4]
+        ldp             d8,  d9,  [sp, #16*5]
+        ldp             x21, x22, [sp], #16*6
+
+        ret
+endfunc
+.endm
+
+FFT_SPLIT_RADIX_FN float, 0
+FFT_SPLIT_RADIX_FN ns_float, 1
diff --git a/libs/ffmpeg/libavutil/adler32.c b/libs/ffmpeg/libavutil/adler32.c
new file mode 100644
index 000000000000..7124f188029f
--- /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 000000000000..232d07f5fe82
--- /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 000000000000..de7144fab8b1
--- /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 000000000000..4e73473688fd
--- /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 000000000000..f653e54bd198
--- /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 000000000000..d98c07122769
--- /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 000000000000..17f79d3ce30c
--- /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 000000000000..e3597277767b
--- /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 000000000000..e5e4ac217328
--- /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/asm.S b/libs/ffmpeg/libavutil/arm/asm.S
new file mode 100644
index 000000000000..47b3a8e6c055
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/asm.S
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2008 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
+ */
+
+#if 0
+#pragma makedep header
+#endif
+
+#include "config.h"
+
+#ifdef __ELF__
+#   define ELF
+#else
+#   define ELF @
+#endif
+
+#if CONFIG_THUMB
+#   define A @
+#   define T
+#else
+#   define A
+#   define T @
+#endif
+
+#if HAVE_AS_FUNC
+#   define FUNC
+#else
+#   define FUNC @
+#endif
+
+#if HAVE_AS_FPU_DIRECTIVE
+#   define FPU
+#else
+#   define FPU @
+#endif
+
+#if CONFIG_THUMB && defined(__APPLE__)
+#   define TFUNC
+#else
+#   define TFUNC @
+#endif
+
+#if HAVE_AS_ARCH_DIRECTIVE
+#if   HAVE_NEON
+        .arch           armv7-a
+#elif HAVE_ARMV6T2
+        .arch           armv6t2
+#elif HAVE_ARMV6
+        .arch           armv6
+#elif HAVE_ARMV5TE
+        .arch           armv5te
+#endif
+#endif
+#if   HAVE_AS_OBJECT_ARCH
+ELF     .object_arch    armv4
+#endif
+
+#if   HAVE_NEON
+FPU     .fpu            neon
+ELF     .eabi_attribute 10, 0           @ suppress Tag_FP_arch
+ELF     .eabi_attribute 12, 0           @ suppress Tag_Advanced_SIMD_arch
+#elif HAVE_VFP
+FPU     .fpu            vfp
+ELF     .eabi_attribute 10, 0           @ suppress Tag_FP_arch
+#endif
+
+        .syntax unified
+T       .thumb
+ELF     .eabi_attribute 25, 1           @ Tag_ABI_align_preserved
+ELF     .section .note.GNU-stack,"",%progbits @ Mark stack as non-executable
+
+.macro  function name, export=0, align=2
+        .set            .Lpic_idx, 0
+        .set            .Lpic_gp, 0
+    .macro endfunc
+      .if .Lpic_idx
+        .align          2
+        .altmacro
+        put_pic         %(.Lpic_idx - 1)
+        .noaltmacro
+      .endif
+      .if .Lpic_gp
+        .unreq          gp
+      .endif
+ELF     .size   \name, . - \name
+FUNC    .endfunc
+        .purgem endfunc
+    .endm
+        .text
+        .align          \align
+    .if \export
+        .global EXTERN_ASM\name
+ELF     .type   EXTERN_ASM\name, %function
+FUNC    .func   EXTERN_ASM\name
+TFUNC   .thumb_func EXTERN_ASM\name
+EXTERN_ASM\name:
+    .else
+ELF     .type   \name, %function
+FUNC    .func   \name
+TFUNC   .thumb_func \name
+\name:
+    .endif
+.endm
+
+.macro  const   name, align=2, relocate=0
+    .macro endconst
+ELF     .size   \name, . - \name
+        .purgem endconst
+    .endm
+#if HAVE_SECTION_DATA_REL_RO
+.if \relocate
+        .section        .data.rel.ro
+.else
+        .section        .rodata
+.endif
+#elif defined(_WIN32)
+        .section        .rdata
+#elif !defined(__MACH__)
+        .section        .rodata
+#else
+        .const_data
+#endif
+        .align          \align
+\name:
+.endm
+
+#if !HAVE_ARMV6T2_EXTERNAL
+.macro  movw    rd, val
+        mov     \rd, \val &  255
+        orr     \rd, \val & ~255
+.endm
+#endif
+
+.macro  mov32   rd, val
+#if HAVE_ARMV6T2_EXTERNAL
+        movw            \rd, #(\val) & 0xffff
+    .if (\val) >> 16
+        movt            \rd, #(\val) >> 16
+    .endif
+#else
+        ldr             \rd, =\val
+#endif
+.endm
+
+.macro  put_pic         num
+        put_pic_\num
+.endm
+
+.macro  do_def_pic      num, val, label
+    .macro put_pic_\num
+      .if \num
+        .altmacro
+        put_pic         %(\num - 1)
+        .noaltmacro
+      .endif
+\label: .word           \val
+        .purgem         put_pic_\num
+    .endm
+.endm
+
+.macro  def_pic         val, label
+        .altmacro
+        do_def_pic      %.Lpic_idx, \val, \label
+        .noaltmacro
+        .set            .Lpic_idx, .Lpic_idx + 1
+.endm
+
+.macro  ldpic           rd,  val, indir=0
+        ldr             \rd, .Lpicoff\@
+.Lpic\@:
+    .if \indir
+A       ldr             \rd, [pc, \rd]
+T       add             \rd, pc
+T       ldr             \rd, [\rd]
+    .else
+        add             \rd, pc
+    .endif
+        def_pic         \val - (.Lpic\@ + (8 >> CONFIG_THUMB)), .Lpicoff\@
+.endm
+
+.macro  movrel rd, val
+#if CONFIG_PIC
+        ldpic           \rd, \val
+#elif HAVE_ARMV6T2_EXTERNAL && !defined(__APPLE__)
+        movw            \rd, #:lower16:\val
+        movt            \rd, #:upper16:\val
+#else
+        ldr             \rd, =\val
+#endif
+.endm
+
+.macro  movrelx         rd,  val, gp
+    .ifc \rd,\gp
+        .error      "movrelx needs two distinct registers"
+    .endif
+    .ifc \rd\()_\gp,r12_
+        .warning    "movrelx rd=\rd without explicit set gp"
+    .endif
+    .ifc \rd\()_\gp,ip_
+        .warning    "movrelx rd=\rd without explicit set gp"
+    .endif
+#if CONFIG_PIC && defined(__ELF__)
+    .ifnb \gp
+      .if .Lpic_gp
+        .unreq          gp
+      .endif
+        gp      .req    \gp
+        ldpic           gp,  _GLOBAL_OFFSET_TABLE_
+    .elseif !.Lpic_gp
+        gp      .req    r12
+        ldpic           gp,  _GLOBAL_OFFSET_TABLE_
+    .endif
+        .set            .Lpic_gp, 1
+        ldr             \rd, .Lpicoff\@
+        ldr             \rd, [gp, \rd]
+        def_pic         \val(GOT), .Lpicoff\@
+#elif CONFIG_PIC && defined(__APPLE__)
+        ldpic           \rd, .Lpic\@, indir=1
+        .non_lazy_symbol_pointer
+.Lpic\@:
+        .indirect_symbol \val
+        .word           0
+        .text
+#else
+        movrel          \rd, \val
+#endif
+.endm
+
+.macro  add_sh          rd,  rn,  rm,  sh:vararg
+A       add             \rd, \rn, \rm, \sh
+T       mov             \rm, \rm, \sh
+T       add             \rd, \rn, \rm
+.endm
+
+.macro  ldr_pre         rt,  rn,  rm:vararg
+A       ldr             \rt, [\rn, \rm]!
+T       add             \rn, \rn, \rm
+T       ldr             \rt, [\rn]
+.endm
+
+.macro  ldr_dpre        rt,  rn,  rm:vararg
+A       ldr             \rt, [\rn, -\rm]!
+T       sub             \rn, \rn, \rm
+T       ldr             \rt, [\rn]
+.endm
+
+.macro  ldr_nreg        rt,  rn,  rm:vararg
+A       ldr             \rt, [\rn, -\rm]
+T       sub             \rt, \rn, \rm
+T       ldr             \rt, [\rt]
+.endm
+
+.macro  ldr_post        rt,  rn,  rm:vararg
+A       ldr             \rt, [\rn], \rm
+T       ldr             \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  ldrc_pre        cc,  rt,  rn,  rm:vararg
+A       ldr\cc          \rt, [\rn, \rm]!
+T       itt             \cc
+T       add\cc          \rn, \rn, \rm
+T       ldr\cc          \rt, [\rn]
+.endm
+
+.macro  ldrd_reg        rt,  rt2, rn,  rm
+A       ldrd            \rt, \rt2, [\rn, \rm]
+T       add             \rt, \rn, \rm
+T       ldrd            \rt, \rt2, [\rt]
+.endm
+
+.macro  ldrd_post       rt,  rt2, rn,  rm
+A       ldrd            \rt, \rt2, [\rn], \rm
+T       ldrd            \rt, \rt2, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  ldrh_pre        rt,  rn,  rm
+A       ldrh            \rt, [\rn, \rm]!
+T       add             \rn, \rn, \rm
+T       ldrh            \rt, [\rn]
+.endm
+
+.macro  ldrh_dpre       rt,  rn,  rm
+A       ldrh            \rt, [\rn, -\rm]!
+T       sub             \rn, \rn, \rm
+T       ldrh            \rt, [\rn]
+.endm
+
+.macro  ldrh_post       rt,  rn,  rm
+A       ldrh            \rt, [\rn], \rm
+T       ldrh            \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  ldrb_post       rt,  rn,  rm
+A       ldrb            \rt, [\rn], \rm
+T       ldrb            \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  str_post       rt,  rn,  rm:vararg
+A       str             \rt, [\rn], \rm
+T       str             \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  strb_post       rt,  rn,  rm:vararg
+A       strb            \rt, [\rn], \rm
+T       strb            \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  strd_post       rt,  rt2, rn,  rm
+A       strd            \rt, \rt2, [\rn], \rm
+T       strd            \rt, \rt2, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  strh_pre        rt,  rn,  rm
+A       strh            \rt, [\rn, \rm]!
+T       add             \rn, \rn, \rm
+T       strh            \rt, [\rn]
+.endm
+
+.macro  strh_dpre       rt,  rn,  rm
+A       strh            \rt, [\rn, -\rm]!
+T       sub             \rn, \rn, \rm
+T       strh            \rt, [\rn]
+.endm
+
+.macro  strh_post       rt,  rn,  rm
+A       strh            \rt, [\rn], \rm
+T       strh            \rt, [\rn]
+T       add             \rn, \rn, \rm
+.endm
+
+.macro  strh_dpost       rt,  rn,  rm
+A       strh            \rt, [\rn], -\rm
+T       strh            \rt, [\rn]
+T       sub             \rn, \rn, \rm
+.endm
+
+#if HAVE_VFP_ARGS
+ELF     .eabi_attribute 28, 1
+#   define VFP
+#   define NOVFP @
+#else
+#   define VFP   @
+#   define NOVFP
+#endif
+
+#define GLUE(a, b) a ## b
+#define JOIN(a, b) GLUE(a, b)
+#define X(s) JOIN(EXTERN_ASM, s)
diff --git a/libs/ffmpeg/libavutil/arm/bswap.h b/libs/ffmpeg/libavutil/arm/bswap.h
new file mode 100644
index 000000000000..48fefa4da368
--- /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.c b/libs/ffmpeg/libavutil/arm/cpu.c
new file mode 100644
index 000000000000..2e2977efc97a
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/cpu.c
@@ -0,0 +1,194 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/cpu.h"
+#include "libavutil/cpu_internal.h"
+#include "config.h"
+
+#define CORE_FLAG(f) \
+    (AV_CPU_FLAG_ ## f * (HAVE_ ## f ## _EXTERNAL || HAVE_ ## f ## _INLINE))
+
+#define CORE_CPU_FLAGS                          \
+    (CORE_FLAG(ARMV5TE) |                       \
+     CORE_FLAG(ARMV6)   |                       \
+     CORE_FLAG(ARMV6T2) |                       \
+     CORE_FLAG(VFP)     |                       \
+     CORE_FLAG(VFPV3)   |                       \
+     CORE_FLAG(NEON))
+
+#if defined __linux__ || defined __ANDROID__ || HAVE_ELF_AUX_INFO
+
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "libavutil/avstring.h"
+
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+#include <sys/auxv.h>
+#endif
+
+#ifndef AT_HWCAP
+#define AT_HWCAP        16
+#endif
+
+/* Relevant HWCAP values from kernel headers */
+#define HWCAP_ARM_VFP     (1 << 6)
+#define HWCAP_ARM_EDSP    (1 << 7)
+#define HWCAP_ARM_THUMBEE (1 << 11)
+#define HWCAP_ARM_NEON    (1 << 12)
+#define HWCAP_ARM_VFPv3   (1 << 13)
+#define HWCAP_ARM_TLS     (1 << 15)
+
+static int get_auxval(uint32_t *hwcap)
+{
+#if HAVE_GETAUXVAL || HAVE_ELF_AUX_INFO
+    unsigned long ret = ff_getauxval(AT_HWCAP);
+    if (ret == 0)
+        return -1;
+    *hwcap = ret;
+    return 0;
+#else
+    return -1;
+#endif
+}
+
+#if defined __linux__ || defined __ANDROID__
+static int get_hwcap(uint32_t *hwcap)
+{
+    struct { uint32_t a_type; uint32_t a_val; } auxv;
+    FILE *f = fopen("/proc/self/auxv", "r");
+    int err = -1;
+
+    if (!f)
+        return -1;
+
+    while (fread(&auxv, sizeof(auxv), 1, f) > 0) {
+        if (auxv.a_type == AT_HWCAP) {
+            *hwcap = auxv.a_val;
+            err = 0;
+            break;
+        }
+    }
+
+    fclose(f);
+    return err;
+}
+
+static int get_cpuinfo(uint32_t *hwcap)
+{
+    FILE *f = fopen("/proc/cpuinfo", "r");
+    char buf[200];
+
+    if (!f)
+        return -1;
+
+    *hwcap = 0;
+    while (fgets(buf, sizeof(buf), f)) {
+        if (av_strstart(buf, "Features", NULL)) {
+            if (strstr(buf, " edsp "))
+                *hwcap |= HWCAP_ARM_EDSP;
+            if (strstr(buf, " tls "))
+                *hwcap |= HWCAP_ARM_TLS;
+            if (strstr(buf, " thumbee "))
+                *hwcap |= HWCAP_ARM_THUMBEE;
+            if (strstr(buf, " vfp "))
+                *hwcap |= HWCAP_ARM_VFP;
+            if (strstr(buf, " vfpv3 "))
+                *hwcap |= HWCAP_ARM_VFPv3;
+            if (strstr(buf, " neon ") || strstr(buf, " asimd "))
+                *hwcap |= HWCAP_ARM_NEON;
+            if (strstr(buf, " fp ")) // Listed on 64 bit ARMv8 kernels
+                *hwcap |= HWCAP_ARM_VFP | HWCAP_ARM_VFPv3;
+            break;
+        }
+    }
+    fclose(f);
+    return 0;
+}
+#endif
+
+int ff_get_cpu_flags_arm(void)
+{
+    int flags = CORE_CPU_FLAGS;
+    uint32_t hwcap;
+
+    if (get_auxval(&hwcap) < 0)
+#if defined __linux__ || defined __ANDROID__
+        if (get_hwcap(&hwcap) < 0)
+            if (get_cpuinfo(&hwcap) < 0)
+#endif
+                return flags;
+
+#define check_cap(cap, flag) do {               \
+        if (hwcap & HWCAP_ARM_ ## cap)          \
+            flags |= AV_CPU_FLAG_ ## flag;      \
+    } while (0)
+
+    /* No flags explicitly indicate v6 or v6T2 so check others which
+       imply support. */
+    check_cap(EDSP,    ARMV5TE);
+    check_cap(TLS,     ARMV6);
+    check_cap(THUMBEE, ARMV6T2);
+    check_cap(VFP,     VFP);
+    check_cap(VFPv3,   VFPV3);
+    check_cap(NEON,    NEON);
+
+    /* The v6 checks above are not reliable so let higher flags
+       trickle down. */
+    if (flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON))
+        flags |= AV_CPU_FLAG_ARMV6T2;
+    else if (flags & (AV_CPU_FLAG_ARMV6T2 | AV_CPU_FLAG_ARMV6))
+    /* Some functions use the 'setend' instruction which is deprecated on ARMv8
+     * and serializing on some ARMv7 cores. This ensures such functions
+     * are only enabled on ARMv6. */
+        flags |= AV_CPU_FLAG_SETEND;
+
+    if (flags & AV_CPU_FLAG_ARMV6T2)
+        flags |= AV_CPU_FLAG_ARMV6;
+
+    /* set the virtual VFPv2 vector mode flag */
+    if ((flags & AV_CPU_FLAG_VFP) && !(flags & (AV_CPU_FLAG_VFPV3 | AV_CPU_FLAG_NEON)))
+        flags |= AV_CPU_FLAG_VFP_VM;
+
+    return flags;
+}
+
+#else
+
+int ff_get_cpu_flags_arm(void)
+{
+    return AV_CPU_FLAG_ARMV5TE * HAVE_ARMV5TE |
+           AV_CPU_FLAG_ARMV6   * HAVE_ARMV6   |
+           AV_CPU_FLAG_ARMV6T2 * HAVE_ARMV6T2 |
+           AV_CPU_FLAG_VFP     * HAVE_VFP     |
+           AV_CPU_FLAG_VFPV3   * HAVE_VFPV3   |
+           AV_CPU_FLAG_NEON    * HAVE_NEON    |
+           AV_CPU_FLAG_SETEND  * !(HAVE_NEON | HAVE_VFPV3);
+}
+
+#endif
+
+size_t ff_get_cpu_max_align_arm(void)
+{
+    int flags = av_get_cpu_flags();
+
+    if (flags & AV_CPU_FLAG_NEON)
+        return 16;
+
+    return 8;
+}
diff --git a/libs/ffmpeg/libavutil/arm/cpu.h b/libs/ffmpeg/libavutil/arm/cpu.h
new file mode 100644
index 000000000000..1d6cc65dc486
--- /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/float_dsp_arm.h b/libs/ffmpeg/libavutil/arm/float_dsp_arm.h
new file mode 100644
index 000000000000..fe311cc0d24d
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_arm.h
@@ -0,0 +1,29 @@
+/*
+ * 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_FLOAT_DSP_ARM_H
+#define AVUTIL_ARM_FLOAT_DSP_ARM_H
+
+#include "libavutil/float_dsp.h"
+
+void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags);
+void ff_float_dsp_init_neon(AVFloatDSPContext *fdsp);
+
+#endif /* AVUTIL_ARM_FLOAT_DSP_ARM_H */
diff --git a/libs/ffmpeg/libavutil/arm/float_dsp_init_arm.c b/libs/ffmpeg/libavutil/arm/float_dsp_init_arm.c
new file mode 100644
index 000000000000..678762862ec7
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_init_arm.c
@@ -0,0 +1,32 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/attributes.h"
+#include "libavutil/float_dsp.h"
+#include "cpu.h"
+#include "float_dsp_arm.h"
+
+av_cold void ff_float_dsp_init_arm(AVFloatDSPContext *fdsp)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_vfp(cpu_flags))
+        ff_float_dsp_init_vfp(fdsp, cpu_flags);
+    if (have_neon(cpu_flags))
+        ff_float_dsp_init_neon(fdsp);
+}
diff --git a/libs/ffmpeg/libavutil/arm/float_dsp_init_neon.c b/libs/ffmpeg/libavutil/arm/float_dsp_init_neon.c
new file mode 100644
index 000000000000..689aa77c7b0b
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_init_neon.c
@@ -0,0 +1,59 @@
+/*
+ * ARM NEON optimised Float DSP functions
+ * Copyright (c) 2008 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
+ */
+
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/float_dsp.h"
+#include "float_dsp_arm.h"
+
+void ff_vector_fmul_neon(float *dst, const float *src0, const float *src1, int len);
+
+void ff_vector_fmac_scalar_neon(float *dst, const float *src, float mul,
+                                int len);
+
+void ff_vector_fmul_scalar_neon(float *dst, const float *src, float mul,
+                                int len);
+
+void ff_vector_fmul_window_neon(float *dst, const float *src0,
+                                const float *src1, const float *win, int len);
+
+void ff_vector_fmul_add_neon(float *dst, const float *src0, const float *src1,
+                             const float *src2, int len);
+
+void ff_vector_fmul_reverse_neon(float *dst, const float *src0,
+                                 const float *src1, int len);
+
+void ff_butterflies_float_neon(float *v1, float *v2, int len);
+
+float ff_scalarproduct_float_neon(const float *v1, const float *v2, int len);
+
+av_cold void ff_float_dsp_init_neon(AVFloatDSPContext *fdsp)
+{
+    fdsp->vector_fmul = ff_vector_fmul_neon;
+    fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_neon;
+    fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_neon;
+    fdsp->vector_fmul_window = ff_vector_fmul_window_neon;
+    fdsp->vector_fmul_add    = ff_vector_fmul_add_neon;
+    fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_neon;
+    fdsp->butterflies_float = ff_butterflies_float_neon;
+    fdsp->scalarproduct_float = ff_scalarproduct_float_neon;
+}
diff --git a/libs/ffmpeg/libavutil/arm/float_dsp_init_vfp.c b/libs/ffmpeg/libavutil/arm/float_dsp_init_vfp.c
new file mode 100644
index 000000000000..6d6237aae830
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_init_vfp.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2008 Siarhei Siamashka <ssvb@users.sourceforge.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
+ */
+
+#include "libavutil/attributes.h"
+#include "libavutil/float_dsp.h"
+#include "cpu.h"
+#include "float_dsp_arm.h"
+
+void ff_vector_fmul_vfp(float *dst, const float *src0, const float *src1,
+                        int len);
+
+void ff_vector_fmul_window_vfp(float *dst, const float *src0,
+                               const float *src1, const float *win, int len);
+
+void ff_vector_fmul_reverse_vfp(float *dst, const float *src0,
+                                const float *src1, int len);
+
+void ff_butterflies_float_vfp(float *restrict v1, float *restrict v2, int len);
+
+av_cold void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags)
+{
+    if (have_vfp_vm(cpu_flags)) {
+        fdsp->vector_fmul = ff_vector_fmul_vfp;
+        fdsp->vector_fmul_window = ff_vector_fmul_window_vfp;
+    }
+    fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_vfp;
+    if (have_vfp_vm(cpu_flags))
+        fdsp->butterflies_float = ff_butterflies_float_vfp;
+}
diff --git a/libs/ffmpeg/libavutil/arm/float_dsp_neon.S b/libs/ffmpeg/libavutil/arm/float_dsp_neon.S
new file mode 100644
index 000000000000..382322760800
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_neon.S
@@ -0,0 +1,271 @@
+/*
+ * ARM NEON optimised Float DSP functions
+ * Copyright (c) 2008 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
+ */
+
+#include "config.h"
+#include "asm.S"
+
+function ff_vector_fmul_neon, export=1
+        subs            r3,  r3,  #8
+        vld1.32         {d0-d3},  [r1,:128]!
+        vld1.32         {d4-d7},  [r2,:128]!
+        vmul.f32        q8,  q0,  q2
+        vmul.f32        q9,  q1,  q3
+        beq             3f
+        bics            ip,  r3,  #15
+        beq             2f
+1:      subs            ip,  ip,  #16
+        vld1.32         {d0-d1},  [r1,:128]!
+        vld1.32         {d4-d5},  [r2,:128]!
+        vmul.f32        q10, q0,  q2
+        vld1.32         {d2-d3},  [r1,:128]!
+        vld1.32         {d6-d7},  [r2,:128]!
+        vmul.f32        q11, q1,  q3
+        vst1.32         {d16-d19},[r0,:128]!
+        vld1.32         {d0-d1},  [r1,:128]!
+        vld1.32         {d4-d5},  [r2,:128]!
+        vmul.f32        q8,  q0,  q2
+        vld1.32         {d2-d3},  [r1,:128]!
+        vld1.32         {d6-d7},  [r2,:128]!
+        vmul.f32        q9,  q1,  q3
+        vst1.32         {d20-d23},[r0,:128]!
+        bne             1b
+        ands            r3,  r3,  #15
+        beq             3f
+2:      vld1.32         {d0-d1},  [r1,:128]!
+        vld1.32         {d4-d5},  [r2,:128]!
+        vst1.32         {d16-d17},[r0,:128]!
+        vmul.f32        q8,  q0,  q2
+        vld1.32         {d2-d3},  [r1,:128]!
+        vld1.32         {d6-d7},  [r2,:128]!
+        vst1.32         {d18-d19},[r0,:128]!
+        vmul.f32        q9,  q1,  q3
+3:      vst1.32         {d16-d19},[r0,:128]!
+        bx              lr
+endfunc
+
+function ff_vector_fmac_scalar_neon, export=1
+VFP     len .req r2
+VFP     acc .req r3
+NOVFP   len .req r3
+NOVFP   acc .req r2
+VFP     vdup.32         q15, d0[0]
+NOVFP   vdup.32         q15, r2
+        bics            r12, len, #15
+        mov             acc, r0
+        beq             3f
+        vld1.32         {q0},     [r1,:128]!
+        vld1.32         {q8},     [acc,:128]!
+        vld1.32         {q1},     [r1,:128]!
+        vld1.32         {q9},     [acc,:128]!
+1:      vmla.f32        q8,  q0,  q15
+        vld1.32         {q2},     [r1,:128]!
+        vld1.32         {q10},    [acc,:128]!
+        vmla.f32        q9,  q1,  q15
+        vld1.32         {q3},     [r1,:128]!
+        vld1.32         {q11},    [acc,:128]!
+        vmla.f32        q10, q2,  q15
+        vst1.32         {q8},     [r0,:128]!
+        vmla.f32        q11, q3,  q15
+        vst1.32         {q9},     [r0,:128]!
+        subs            r12, r12, #16
+        beq             2f
+        vld1.32         {q0},     [r1,:128]!
+        vld1.32         {q8},     [acc,:128]!
+        vst1.32         {q10},    [r0,:128]!
+        vld1.32         {q1},     [r1,:128]!
+        vld1.32         {q9},     [acc,:128]!
+        vst1.32         {q11},    [r0,:128]!
+        b               1b
+2:      vst1.32         {q10},    [r0,:128]!
+        vst1.32         {q11},    [r0,:128]!
+        ands            len, len, #15
+        it              eq
+        bxeq            lr
+3:      vld1.32         {q0},     [r1,:128]!
+        vld1.32         {q8},     [acc,:128]!
+        vmla.f32        q8,  q0,  q15
+        vst1.32         {q8},     [r0,:128]!
+        subs            len, len, #4
+        bgt             3b
+        bx              lr
+        .unreq          len
+endfunc
+
+function ff_vector_fmul_scalar_neon, export=1
+VFP     len .req r2
+NOVFP   len .req r3
+VFP     vdup.32         q8,  d0[0]
+NOVFP   vdup.32         q8,  r2
+        bics            r12, len, #15
+        beq             3f
+        vld1.32         {q0},[r1,:128]!
+        vld1.32         {q1},[r1,:128]!
+1:      vmul.f32        q0,  q0,  q8
+        vld1.32         {q2},[r1,:128]!
+        vmul.f32        q1,  q1,  q8
+        vld1.32         {q3},[r1,:128]!
+        vmul.f32        q2,  q2,  q8
+        vst1.32         {q0},[r0,:128]!
+        vmul.f32        q3,  q3,  q8
+        vst1.32         {q1},[r0,:128]!
+        subs            r12, r12, #16
+        beq             2f
+        vld1.32         {q0},[r1,:128]!
+        vst1.32         {q2},[r0,:128]!
+        vld1.32         {q1},[r1,:128]!
+        vst1.32         {q3},[r0,:128]!
+        b               1b
+2:      vst1.32         {q2},[r0,:128]!
+        vst1.32         {q3},[r0,:128]!
+        ands            len, len, #15
+        it              eq
+        bxeq            lr
+3:      vld1.32         {q0},[r1,:128]!
+        vmul.f32        q0,  q0,  q8
+        vst1.32         {q0},[r0,:128]!
+        subs            len, len, #4
+        bgt             3b
+        bx              lr
+        .unreq          len
+endfunc
+
+function ff_vector_fmul_window_neon, export=1
+        push            {r4,r5,lr}
+        ldr             lr,  [sp, #12]
+        sub             r2,  r2,  #8
+        sub             r5,  lr,  #2
+        add             r2,  r2,  r5, lsl #2
+        add             r4,  r3,  r5, lsl #3
+        add             ip,  r0,  r5, lsl #3
+        mov             r5,  #-16
+        vld1.32         {d0,d1},  [r1,:128]!
+        vld1.32         {d2,d3},  [r2,:128], r5
+        vld1.32         {d4,d5},  [r3,:128]!
+        vld1.32         {d6,d7},  [r4,:128], r5
+1:      subs            lr,  lr,  #4
+        vmul.f32        d22, d0,  d4
+        vrev64.32       q3,  q3
+        vmul.f32        d23, d1,  d5
+        vrev64.32       q1,  q1
+        vmul.f32        d20, d0,  d7
+        vmul.f32        d21, d1,  d6
+        beq             2f
+        vmla.f32        d22, d3,  d7
+        vld1.32         {d0,d1},  [r1,:128]!
+        vmla.f32        d23, d2,  d6
+        vld1.32         {d18,d19},[r2,:128], r5
+        vmls.f32        d20, d3,  d4
+        vld1.32         {d24,d25},[r3,:128]!
+        vmls.f32        d21, d2,  d5
+        vld1.32         {d6,d7},  [r4,:128], r5
+        vmov            q1,  q9
+        vrev64.32       q11, q11
+        vmov            q2,  q12
+        vswp            d22, d23
+        vst1.32         {d20,d21},[r0,:128]!
+        vst1.32         {d22,d23},[ip,:128], r5
+        b               1b
+2:      vmla.f32        d22, d3,  d7
+        vmla.f32        d23, d2,  d6
+        vmls.f32        d20, d3,  d4
+        vmls.f32        d21, d2,  d5
+        vrev64.32       q11, q11
+        vswp            d22, d23
+        vst1.32         {d20,d21},[r0,:128]!
+        vst1.32         {d22,d23},[ip,:128], r5
+        pop             {r4,r5,pc}
+endfunc
+
+function ff_vector_fmul_add_neon, export=1
+        ldr             r12, [sp]
+        vld1.32         {q0-q1},  [r1,:128]!
+        vld1.32         {q8-q9},  [r2,:128]!
+        vld1.32         {q2-q3},  [r3,:128]!
+        vmul.f32        q10, q0,  q8
+        vmul.f32        q11, q1,  q9
+1:      vadd.f32        q12, q2,  q10
+        vadd.f32        q13, q3,  q11
+        pld             [r1, #16]
+        pld             [r2, #16]
+        pld             [r3, #16]
+        subs            r12, r12, #8
+        beq             2f
+        vld1.32         {q0},     [r1,:128]!
+        vld1.32         {q8},     [r2,:128]!
+        vmul.f32        q10, q0,  q8
+        vld1.32         {q1},     [r1,:128]!
+        vld1.32         {q9},     [r2,:128]!
+        vmul.f32        q11, q1,  q9
+        vld1.32         {q2-q3},  [r3,:128]!
+        vst1.32         {q12-q13},[r0,:128]!
+        b               1b
+2:      vst1.32         {q12-q13},[r0,:128]!
+        bx              lr
+endfunc
+
+function ff_vector_fmul_reverse_neon, export=1
+        add             r2,  r2,  r3,  lsl #2
+        sub             r2,  r2,  #32
+        mov             r12, #-32
+        vld1.32         {q0-q1},  [r1,:128]!
+        vld1.32         {q2-q3},  [r2,:128], r12
+1:      pld             [r1, #32]
+        vrev64.32       q3,  q3
+        vmul.f32        d16, d0,  d7
+        vmul.f32        d17, d1,  d6
+        pld             [r2, #-32]
+        vrev64.32       q2,  q2
+        vmul.f32        d18, d2,  d5
+        vmul.f32        d19, d3,  d4
+        subs            r3,  r3,  #8
+        beq             2f
+        vld1.32         {q0-q1},  [r1,:128]!
+        vld1.32         {q2-q3},  [r2,:128], r12
+        vst1.32         {q8-q9},  [r0,:128]!
+        b               1b
+2:      vst1.32         {q8-q9},  [r0,:128]!
+        bx              lr
+endfunc
+
+function ff_butterflies_float_neon, export=1
+1:      vld1.32         {q0},[r0,:128]
+        vld1.32         {q1},[r1,:128]
+        vsub.f32        q2,  q0,  q1
+        vadd.f32        q1,  q0,  q1
+        vst1.32         {q2},[r1,:128]!
+        vst1.32         {q1},[r0,:128]!
+        subs            r2,  r2,  #4
+        bgt             1b
+        bx              lr
+endfunc
+
+function ff_scalarproduct_float_neon, export=1
+        vmov.f32        q2,  #0.0
+1:      vld1.32         {q0},[r0,:128]!
+        vld1.32         {q1},[r1,:128]!
+        vmla.f32        q2,  q0,  q1
+        subs            r2,  r2,  #4
+        bgt             1b
+        vadd.f32        d0,  d4,  d5
+        vpadd.f32       d0,  d0,  d0
+NOVFP   vmov.32         r0,  d0[0]
+        bx              lr
+endfunc
diff --git a/libs/ffmpeg/libavutil/arm/float_dsp_vfp.S b/libs/ffmpeg/libavutil/arm/float_dsp_vfp.S
new file mode 100644
index 000000000000..7db24522848b
--- /dev/null
+++ b/libs/ffmpeg/libavutil/arm/float_dsp_vfp.S
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2008 Siarhei Siamashka <ssvb@users.sourceforge.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
+ */
+
+#include "config.h"
+#include "asm.S"
+
+/**
+ * Assume that len is a positive number and is multiple of 8
+ */
+@ void ff_vector_fmul_vfp(float *dst, const float *src0, const float *src1, int len)
+function ff_vector_fmul_vfp, export=1
+        vpush           {d8-d15}
+        fmrx            r12, fpscr
+        orr             r12, r12, #(3 << 16) /* set vector size to 4 */
+        fmxr            fpscr, r12
+
+        vldmia          r1!, {s0-s3}
+        vldmia          r2!, {s8-s11}
+        vldmia          r1!, {s4-s7}
+        vldmia          r2!, {s12-s15}
+        vmul.f32        s8,  s0,  s8
+1:
+        subs            r3,  r3,  #16
+        vmul.f32        s12, s4,  s12
+        itttt           ge
+        vldmiage        r1!, {s16-s19}
+        vldmiage        r2!, {s24-s27}
+        vldmiage        r1!, {s20-s23}
+        vldmiage        r2!, {s28-s31}
+        it              ge
+        vmulge.f32      s24, s16, s24
+        vstmia          r0!, {s8-s11}
+        vstmia          r0!, {s12-s15}
+        it              ge
+        vmulge.f32      s28, s20, s28
+        itttt           gt
+        vldmiagt        r1!, {s0-s3}
+        vldmiagt        r2!, {s8-s11}
+        vldmiagt        r1!, {s4-s7}
+        vldmiagt        r2!, {s12-s15}
+        ittt            ge
+        vmulge.f32      s8,  s0,  s8
+        vstmiage        r0!, {s24-s27}
+        vstmiage        r0!, {s28-s31}
+        bgt             1b
+
+        bic             r12, r12, #(7 << 16) /* set vector size back to 1 */
+        fmxr            fpscr, r12
+        vpop            {d8-d15}
+        bx              lr
+endfunc
+
+/**
+ * ARM VFP implementation of 'vector_fmul_window_c' function
+ * Assume that len is a positive non-zero number
+ */
+@ void ff_vector_fmul_window_vfp(float *dst, const float *src0,
+@                                const float *src1, const float *win, int len)
+function ff_vector_fmul_window_vfp, export=1
+DST0    .req    a1
+SRC0    .req    a2
+SRC1    .req    a3
+WIN0    .req    a4
+LEN     .req    v1
+DST1    .req    v2
+WIN1    .req    v3
+OLDFPSCR .req   ip
+
+        push    {v1-v3,lr}
+        ldr     LEN, [sp, #4*4+0]
+        vpush   {s16-s31}
+        fmrx    OLDFPSCR, FPSCR
+        add     DST1, DST0, LEN, lsl #3
+        add     SRC1, SRC1, LEN, lsl #2
+        add     WIN1, WIN0, LEN, lsl #3
+
+        tst     LEN, #7
+        beq     4f                          @ common case: len is a multiple of 8
+
+        ldr     lr, =0x03000000             @ RunFast mode, scalar mode
+        fmxr    FPSCR, lr
+
+        tst     LEN, #1
+        beq     1f
+        vldmdb  WIN1!, {s0}
+        vldmia  SRC0!, {s8}
+        vldmia  WIN0!, {s16}
+        vmul.f  s24, s0, s8
+        vldmdb  SRC1!, {s20}
+        vmul.f  s8, s16, s8
+        vmls.f  s24, s16, s20
+        vmla.f  s8, s0, s20
+        vstmia  DST0!, {s24}
+        vstmdb  DST1!, {s8}
+1:
+        tst     LEN, #2
+        beq     2f
+        vldmdb  WIN1!, {s0}
+        vldmdb  WIN1!, {s1}
+        vldmia  SRC0!, {s8-s9}
+        vldmia  WIN0!, {s16-s17}
+        vmul.f  s24, s0, s8
+        vmul.f  s25, s1, s9
+        vldmdb  SRC1!, {s20}
+        vldmdb  SRC1!, {s21}
+        vmul.f  s8, s16, s8
+        vmul.f  s9, s17, s9
+        vmls.f  s24, s16, s20
+        vmls.f  s25, s17, s21
+        vmla.f  s8, s0, s20
+        vmla.f  s9, s1, s21
+        vstmia  DST0!, {s24-s25}
+        vstmdb  DST1!, {s8}
+        vstmdb  DST1!, {s9}
+2:
+        tst     LEN, #4
+        beq     3f
+        vldmdb  WIN1!, {s0}
+        vldmdb  WIN1!, {s1}
+        vldmdb  WIN1!, {s2}
+        vldmdb  WIN1!, {s3}
+        vldmia  SRC0!, {s8-s11}
+        vldmia  WIN0!, {s16-s19}
+        vmul.f  s24, s0, s8
+        vmul.f  s25, s1, s9
+        vmul.f  s26, s2, s10
+        vmul.f  s27, s3, s11
+        vldmdb  SRC1!, {s20}
+        vldmdb  SRC1!, {s21}
+        vldmdb  SRC1!, {s22}
+        vldmdb  SRC1!, {s23}
+        vmul.f  s8, s16, s8
+        vmul.f  s9, s17, s9
+        vmul.f  s10, s18, s10
+        vmul.f  s11, s19, s11
+        vmls.f  s24, s16, s20
+        vmls.f  s25, s17, s21
+        vmls.f  s26, s18, s22
+        vmls.f  s27, s19, s23
+        vmla.f  s8, s0, s20
+        vmla.f  s9, s1, s21
+        vmla.f  s10, s2, s22
+        vmla.f  s11, s3, s23
+        vstmia  DST0!, {s24-s27}
+        vstmdb  DST1!, {s8}
+        vstmdb  DST1!, {s9}
+        vstmdb  DST1!, {s10}
+        vstmdb  DST1!, {s11}
+3:
+        bics    LEN, LEN, #7
+        beq     7f
+4:
+        ldr     lr, =0x03030000             @ RunFast mode, short vectors of length 4, stride 1
+        fmxr    FPSCR, lr
+
+        vldmdb  WIN1!, {s0}
+        vldmdb  WIN1!, {s1}
+        vldmdb  WIN1!, {s2}
+        vldmdb  WIN1!, {s3}
+        vldmia  SRC0!, {s8-s11}
+        vldmia  WIN0!, {s16-s19}
+        vmul.f  s24, s0, s8                     @ vector * vector
+        vldmdb  SRC1!, {s20}
+        vldmdb  SRC1!, {s21}
+        vldmdb  SRC1!, {s22}
+        vldmdb  SRC1!, {s23}
+        vmul.f  s8, s16, s8                     @ vector * vector
+        vmls.f  s24, s16, s20                   @ vector * vector
+            vldmdb  WIN1!, {s4}
+            vldmdb  WIN1!, {s5}
+            vldmdb  WIN1!, {s6}
+            vldmdb  WIN1!, {s7}
+            vldmia  SRC0!, {s12-s13}
+        vmla.f  s8, s0, s20                     @ vector * vector
+            vldmia  SRC0!, {s14-s15}
+        subs    LEN, LEN, #8
+        beq     6f
+5:          vldmia  WIN0!, {s20-s23}
+            vmul.f  s28, s4, s12                @ vector * vector
+        vstmia  DST0!, {s24-s25}
+            vldmdb  SRC1!, {s16}
+            vldmdb  SRC1!, {s17}
+            vldmdb  SRC1!, {s18}
+            vldmdb  SRC1!, {s19}
+            vmul.f  s12, s20, s12               @ vector * vector
+        vstmia  DST0!, {s26-s27}
+        vstmdb  DST1!, {s8}
+        vstmdb  DST1!, {s9}
+        vstmdb  DST1!, {s10}
+        vstmdb  DST1!, {s11}
+            vmls.f  s28, s20, s16               @ vector * vector
+                vldmdb  WIN1!, {s0}
+                vldmdb  WIN1!, {s1}
+                vldmdb  WIN1!, {s2}
+                vldmdb  WIN1!, {s3}
+                vldmia  SRC0!, {s8-s9}
+            vmla.f  s12, s4, s16                @ vector * vector
+                vldmia  SRC0!, {s10-s11}
+        subs    LEN, LEN, #8
+                vldmia  WIN0!, {s16-s19}
+                vmul.f  s24, s0, s8             @ vector * vector
+            vstmia  DST0!, {s28-s29}
+                vldmdb  SRC1!, {s20}
+                vldmdb  SRC1!, {s21}
+                vldmdb  SRC1!, {s22}
+                vldmdb  SRC1!, {s23}
+                vmul.f  s8, s16, s8             @ vector * vector
+            vstmia  DST0!, {s30-s31}
+            vstmdb  DST1!, {s12}
+            vstmdb  DST1!, {s13}
+            vstmdb  DST1!, {s14}
+            vstmdb  DST1!, {s15}
+                vmls.f  s24, s16, s20           @ vector * vector
+                    vldmdb  WIN1!, {s4}
+                    vldmdb  WIN1!, {s5}
+                    vldmdb  WIN1!, {s6}
+                    vldmdb  WIN1!, {s7}
+                    vldmia  SRC0!, {s12-s13}
+                vmla.f  s8, s0, s20             @ vector * vector
+                    vldmia  SRC0!, {s14-s15}
+        bne     5b
+6:                  vldmia  WIN0!, {s20-s23}
+                    vmul.f  s28, s4, s12        @ vector * vector
+                vstmia  DST0!, {s24-s25}
+                    vldmdb  SRC1!, {s16}
+                    vldmdb  SRC1!, {s17}
+                    vldmdb  SRC1!, {s18}
+                    vldmdb  SRC1!, {s19}
+                    vmul.f  s12, s20, s12       @ vector * vector
+                vstmia  DST0!, {s26-s27}
+                vstmdb  DST1!, {s8}
+                vstmdb  DST1!, {s9}
+                vstmdb  DST1!, {s10}
+                vstmdb  DST1!, {s11}
+                    vmls.f  s28, s20, s16       @ vector * vector
+                    vmla.f  s12, s4, s16        @ vector * vector
+                    vstmia  DST0!, {s28-s31}
+                    vstmdb  DST1!, {s12}
+                    vstmdb  DST1!, {s13}
+                    vstmdb  DST1!, {s14}
+                    vstmdb  DST1!, {s15}
+7:
+        fmxr    FPSCR, OLDFPSCR
+        vpop    {s16-s31}
+        pop     {v1-v3,pc}
+
+        .unreq  DST0
+        .unreq  SRC0
+        .unreq  SRC1
+        .unreq  WIN0
+        .unreq  LEN
+        .unreq  OLDFPSCR
+        .unreq  DST1
+        .unreq  WIN1
+endfunc
+
+/**
+ * ARM VFP optimized implementation of 'vector_fmul_reverse_c' function.
+ * Assume that len is a positive number and is multiple of 8
+ */
+@ void ff_vector_fmul_reverse_vfp(float *dst, const float *src0,
+@                                 const float *src1, int len)
+function ff_vector_fmul_reverse_vfp, export=1
+        vpush           {d8-d15}
+        add             r2,  r2,  r3, lsl #2
+        vldmdb          r2!, {s0-s3}
+        vldmia          r1!, {s8-s11}
+        vldmdb          r2!, {s4-s7}
+        vldmia          r1!, {s12-s15}
+        vmul.f32        s8,  s3,  s8
+        vmul.f32        s9,  s2,  s9
+        vmul.f32        s10, s1,  s10
+        vmul.f32        s11, s0,  s11
+1:
+        subs            r3,  r3,  #16
+        it              ge
+        vldmdbge        r2!, {s16-s19}
+        vmul.f32        s12, s7,  s12
+        it              ge
+        vldmiage        r1!, {s24-s27}
+        vmul.f32        s13, s6,  s13
+        it              ge
+        vldmdbge        r2!, {s20-s23}
+        vmul.f32        s14, s5,  s14
+        it              ge
+        vldmiage        r1!, {s28-s31}
+        vmul.f32        s15, s4,  s15
+        it              ge
+        vmulge.f32      s24, s19, s24
+        it              gt
+        vldmdbgt        r2!, {s0-s3}
+        it              ge
+        vmulge.f32      s25, s18, s25
+        vstmia          r0!, {s8-s13}
+        it              ge
+        vmulge.f32      s26, s17, s26
+        it              gt
+        vldmiagt        r1!, {s8-s11}
+        itt             ge
+        vmulge.f32      s27, s16, s27
+        vmulge.f32      s28, s23, s28
+        it              gt
+        vldmdbgt        r2!, {s4-s7}
+        it              ge
+        vmulge.f32      s29, s22, s29
+        vstmia          r0!, {s14-s15}
+        ittt            ge
+        vmulge.f32      s30, s21, s30
+        vmulge.f32      s31, s20, s31
+        vmulge.f32      s8,  s3,  s8
+        it              gt
+        vldmiagt        r1!, {s12-s15}
+        itttt           ge
+        vmulge.f32      s9,  s2,  s9
+        vmulge.f32      s10, s1,  s10
+        vstmiage        r0!, {s24-s27}
+        vmulge.f32      s11, s0,  s11
+        it              ge
+        vstmiage        r0!, {s28-s31}
+        bgt             1b
+
+        vpop            {d8-d15}
+        bx              lr
+endfunc
+
+/**
+ * ARM VFP implementation of 'butterflies_float_c' function
+ * Assume that len is a positive non-zero number
+ */
+@ void ff_butterflies_float_vfp(float *restrict v1, float *restrict v2, int len)
+function ff_butterflies_float_vfp, export=1
+BASE1   .req    a1
+BASE2   .req    a2
+LEN     .req    a3
+OLDFPSCR .req   a4
+
+        vpush   {s16-s31}
+        fmrx    OLDFPSCR, FPSCR
+
+        tst     LEN, #7
+        beq     4f                          @ common case: len is a multiple of 8
+
+        ldr     ip, =0x03000000             @ RunFast mode, scalar mode
+        fmxr    FPSCR, ip
+
+        tst     LEN, #1
+        beq     1f
+        vldmia  BASE1!, {s0}
+        vldmia  BASE2!, {s8}
+        vadd.f  s16, s0, s8
+        vsub.f  s24, s0, s8
+        vstr    s16, [BASE1, #0-4*1]
+        vstr    s24, [BASE2, #0-4*1]
+1:
+        tst     LEN, #2
+        beq     2f
+        vldmia  BASE1!, {s0-s1}
+        vldmia  BASE2!, {s8-s9}
+        vadd.f  s16, s0, s8
+        vadd.f  s17, s1, s9
+        vsub.f  s24, s0, s8
+        vsub.f  s25, s1, s9
+        vstr    d8, [BASE1, #0-8*1]    @ s16,s17
+        vstr    d12, [BASE2, #0-8*1]   @ s24,s25
+2:
+        tst     LEN, #4
+        beq     3f
+        vldmia  BASE1!, {s0-s1}
+        vldmia  BASE2!, {s8-s9}
+        vldmia  BASE1!, {s2-s3}
+        vldmia  BASE2!, {s10-s11}
+        vadd.f  s16, s0, s8
+        vadd.f  s17, s1, s9
+        vsub.f  s24, s0, s8
+        vsub.f  s25, s1, s9
+        vadd.f  s18, s2, s10
+        vadd.f  s19, s3, s11
+        vsub.f  s26, s2, s10
+        vsub.f  s27, s3, s11
+        vstr    d8, [BASE1, #0-16*1]    @ s16,s17
+        vstr    d12, [BASE2, #0-16*1]   @ s24,s25
+        vstr    d9, [BASE1, #8-16*1]    @ s18,s19
+        vstr    d13, [BASE2, #8-16*1]   @ s26,s27
+3:
+        bics    LEN, LEN, #7
+        beq     7f
+4:
+        ldr     ip, =0x03030000             @ RunFast mode, short vectors of length 4, stride 1
+        fmxr    FPSCR, ip
+
+        vldmia  BASE1!, {s0-s1}
+        vldmia  BASE2!, {s8-s9}
+        vldmia  BASE1!, {s2-s3}
+        vldmia  BASE2!, {s10-s11}
+        vadd.f  s16, s0, s8
+            vldmia  BASE1!, {s4-s5}
+            vldmia  BASE2!, {s12-s13}
+            vldmia  BASE1!, {s6-s7}
+            vldmia  BASE2!, {s14-s15}
+        vsub.f  s24, s0, s8
+            vadd.f  s20, s4, s12
+        subs    LEN, LEN, #8
+        beq     6f
+5:              vldmia  BASE1!, {s0-s3}
+                vldmia  BASE2!, {s8-s11}
+            vsub.f  s28, s4, s12
+        vstr    d8, [BASE1, #0-16*3]    @ s16,s17
+        vstr    d9, [BASE1, #8-16*3]    @ s18,s19
+        vstr    d12, [BASE2, #0-16*3]   @ s24,s25
+        vstr    d13, [BASE2, #8-16*3]   @ s26,s27
+                vadd.f  s16, s0, s8
+                    vldmia  BASE1!, {s4-s7}
+                    vldmia  BASE2!, {s12-s15}
+                vsub.f  s24, s0, s8
+            vstr    d10, [BASE1, #0-16*3]   @ s20,s21
+            vstr    d11, [BASE1, #8-16*3]   @ s22,s23
+            vstr    d14, [BASE2, #0-16*3]   @ s28,s29
+            vstr    d15, [BASE2, #8-16*3]   @ s30,s31
+                    vadd.f  s20, s4, s12
+        subs    LEN, LEN, #8
+        bne     5b
+6:                   vsub.f  s28, s4, s12
+                vstr    d8, [BASE1, #0-16*2]    @ s16,s17
+                vstr    d9, [BASE1, #8-16*2]    @ s18,s19
+                vstr    d12, [BASE2, #0-16*2]   @ s24,s25
+                vstr    d13, [BASE2, #8-16*2]   @ s26,s27
+                    vstr    d10, [BASE1, #0-16*1]   @ s20,s21
+                    vstr    d11, [BASE1, #8-16*1]   @ s22,s23
+                    vstr    d14, [BASE2, #0-16*1]   @ s28,s29
+                    vstr    d15, [BASE2, #8-16*1]   @ s30,s31
+7:
+        fmxr    FPSCR, OLDFPSCR
+        vpop    {s16-s31}
+        bx      lr
+
+        .unreq  BASE1
+        .unreq  BASE2
+        .unreq  LEN
+        .unreq  OLDFPSCR
+endfunc
diff --git a/libs/ffmpeg/libavutil/arm/intmath.h b/libs/ffmpeg/libavutil/arm/intmath.h
new file mode 100644
index 000000000000..f19b21e98d36
--- /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 000000000000..08e4095d84d9
--- /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 000000000000..649f37feb234
--- /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
+
+#if defined __clang__ && !defined __WINESRC__
+#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 000000000000..15d89120ad0e
--- /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 000000000000..dc2dea9b2dcb
--- /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 000000000000..fa5f59a2bef2
--- /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 000000000000..e316a3c90d69
--- /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 000000000000..8558b35027f1
--- /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 000000000000..94f7710043ee
--- /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 000000000000..281c5cdc88f5
--- /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 000000000000..17f7b03db528
--- /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 000000000000..c8ae114ab6f3
--- /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 000000000000..69e11e6f5e1d
--- /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 000000000000..2954c12d4271
--- /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 000000000000..6df60150ea95
--- /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 000000000000..9e289a40dabe
--- /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 000000000000..11e0f08774d9
--- /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", "&amp;");  break;
+            case '<' : av_bprintf(dstbuf, "%s", "&lt;");   break;
+            case '>' : av_bprintf(dstbuf, "%s", "&gt;");   break;
+            case '\'':
+                if (!(flags & AV_ESCAPE_FLAG_XML_SINGLE_QUOTES))
+                    goto XML_DEFAULT_HANDLING;
+
+                av_bprintf(dstbuf, "%s", "&apos;");
+                break;
+            case '"' :
+                if (!(flags & AV_ESCAPE_FLAG_XML_DOUBLE_QUOTES))
+                    goto XML_DEFAULT_HANDLING;
+
+                av_bprintf(dstbuf, "%s", "&quot;");
+                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 000000000000..4ac857056187
--- /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 000000000000..c1e6591ce009
--- /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 000000000000..a8101d83f013
--- /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 000000000000..e1ef5b7f07fc
--- /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 000000000000..adb916aaa225
--- /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 000000000000..3fc3b0829131
--- /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 000000000000..96787102e2ac
--- /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 000000000000..e1d2c5cadd4e
--- /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 000000000000..ad5b347e685e
--- /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 000000000000..cfa8e05d56fd
--- /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 000000000000..5ad2d5ed98f2
--- /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 000000000000..bf23aa50b0cf
--- /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 000000000000..34a78e7ef316
--- /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 000000000000..ff9249311f68
--- /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 000000000000..07b90aa90a1d
--- /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 000000000000..464d4cd5dffd
--- /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 000000000000..8dca62334a0b
--- /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 000000000000..c8ccaf816211
--- /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 000000000000..7f59812a18c9
--- /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 000000000000..8ff53cff5faf
--- /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.pdf)
+ * 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 000000000000..9d75ccbb6406
--- /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 000000000000..e0e9a86660fd
--- /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 000000000000..3a3e6fa47cef
--- /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 000000000000..cb157b355bdb
--- /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 000000000000..011988052c23
--- /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 000000000000..fafb454fd381
--- /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(&copy_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 000000000000..93c7cbf1286c
--- /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 000000000000..d31061283cf8
--- /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 000000000000..50f2b44caf57
--- /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 000000000000..dfa4a438ed4c
--- /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 000000000000..c102bf384f46
--- /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 000000000000..7e6c3e854d31
--- /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 000000000000..221cf5bf9baf
--- /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 000000000000..3a7e146422a1
--- /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 000000000000..2b9a456223d8
--- /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 000000000000..e4ff015b3713
--- /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 000000000000..8fe7ebfe4320
--- /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 000000000000..2c9f0028bd2c
--- /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 000000000000..1efa86c4c106
--- /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 000000000000..56123a3831e1
--- /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 000000000000..0d3eaeb3fbc8
--- /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 000000000000..bfce2ac444c8
--- /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 000000000000..0eb21c10c878
--- /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 000000000000..aad1347f26d4
--- /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 000000000000..c1a8d885e890
--- /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 000000000000..8806c668d7e4
--- /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 000000000000..f2206c35f524
--- /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 000000000000..4ef940a6c3ce
--- /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 000000000000..fced17010829
--- /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 000000000000..121a562fcb6b
--- /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 000000000000..6a0000474167
--- /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 000000000000..0a6004b6b308
--- /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 000000000000..2915611c9c1e
--- /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 000000000000..74cefdb145cf
--- /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 000000000000..9b566af67581
--- /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/float_dsp.c b/libs/ffmpeg/libavutil/float_dsp.c
new file mode 100644
index 000000000000..5bfa1008d139
--- /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 000000000000..ab34277c2083
--- /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 000000000000..e95e67fde1dd
--- /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 000000000000..be30eb09d2a8
--- /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 000000000000..771c9ce4537e
--- /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 000000000000..4de2180a197e
--- /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 000000000000..dbd5e7150fb8
--- /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 000000000000..fbc24194dea4
--- /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 000000000000..94151ded7cbc
--- /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 000000000000..7033f060c0a4
--- /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 000000000000..5100ed6f41f7
--- /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 000000000000..32da01f5875a
--- /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 000000000000..d45b4a0f658d
--- /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 000000000000..6daca00b8fee
--- /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 000000000000..ca4da6a689d9
--- /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 000000000000..83bd7457e8e6
--- /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 000000000000..29374cf0a7e3
--- /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 000000000000..dcfdc2016a30
--- /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 000000000000..76707563cbb5
--- /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 &param_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 = &param_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 = &param_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 = &param_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 000000000000..a755e7d682e7
--- /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 000000000000..8ff8a6be4193
--- /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 000000000000..123a9e5c0d21
--- /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 000000000000..3e47731a5095
--- /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 000000000000..ae87c467b2db
--- /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 = &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(&quot, 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 000000000000..2d9b5bb10fa7
--- /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 000000000000..2a8517079570
--- /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 000000000000..fe3d7ec4a5b6
--- /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 000000000000..b0c00e1cadd9
--- /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 000000000000..b177a848c699
--- /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 000000000000..ffd15a150296
--- /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 000000000000..46b04d24039f
--- /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 000000000000..043d0ab3430f
--- /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 000000000000..e560885d5d5c
--- /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 000000000000..27168009c54d
--- /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 000000000000..7acef4eff884
--- /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.h b/libs/ffmpeg/libavutil/log.h
new file mode 100644
index 000000000000..f0104ad2cfc8
--- /dev/null
+++ b/libs/ffmpeg/libavutil/log.h
@@ -0,0 +1,484 @@
+/*
+ * 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
+ */
+static inline const char *av_default_item_name(void *ptr)
+{
+    return (*(AVClass **) ptr)->class_name;
+}
+static inline AVClassCategory av_default_get_category(void *ptr)
+{
+    return (*(AVClass **) ptr)->category;
+}
+
+/**
+ * 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);
+
+/**
+ * @}
+ */
+
+#include "wine/debug.h"
+#undef OUT
+
+WINE_DECLARE_DEBUG_CHANNEL(ffmpeg);
+
+static enum __wine_debug_class wine_dbglog_from_level( int level )
+{
+    if (level >= 0) level &= 0xff;
+    if (level < 0) return __WINE_DBCL_TRACE;
+    if (level <= AV_LOG_ERROR) return __WINE_DBCL_ERR;
+    if (level <= AV_LOG_WARNING) return __WINE_DBCL_WARN;
+    return __WINE_DBCL_TRACE;
+}
+
+#define av_log( a, b, c, ... ) wine_av_log( __func__, a, b, c, ##__VA_ARGS__ )
+static inline void wine_av_log( const char *func, void *avcl, int level, const char *fmt, ... )
+{
+    enum __wine_debug_class dbcl = wine_dbglog_from_level( level );
+    va_list args;
+
+    if (!(__wine_dbch_ffmpeg.flags & (1 << dbcl))) return;
+    va_start( args, fmt );
+    wine_dbg_vlog( dbcl, &__wine_dbch_ffmpeg, func, fmt, args );
+    va_end( args );
+}
+
+#define av_log_once( a, b, c, d, e, ... ) wine_av_log_once( __func__, a, b, c, d, e, ##__VA_ARGS__ )
+static inline void wine_av_log_once( const char *func, void *avcl, int initial_level, int subsequent_level,
+                                     int *state, const char *fmt, ... )
+{
+    enum __wine_debug_class dbcl;
+    va_list args;
+    int level;
+
+    level = InterlockedExchange( (LONG *)state, 1 ) ? subsequent_level : initial_level;
+    dbcl = wine_dbglog_from_level( level );
+
+    if (!(__wine_dbch_ffmpeg.flags & (1 << dbcl))) return;
+    va_start( args, fmt );
+    wine_dbg_vlog( dbcl, &__wine_dbch_ffmpeg, func, fmt, args );
+    va_end( args );
+}
+
+#define av_vlog( a, b, c, d ) wine_av_vlog( __func__, a, b, c, d )
+static inline void wine_av_vlog( const char *func, void *avcl, int level, const char *fmt, va_list args )
+{
+    enum __wine_debug_class dbcl = wine_dbglog_from_level( level );
+    if (!(__wine_dbch_ffmpeg.flags & (1 << dbcl))) return;
+    wine_dbg_vlog( dbcl, &__wine_dbch_ffmpeg, func, fmt, args );
+}
+
+#endif /* AVUTIL_LOG_H */
diff --git a/libs/ffmpeg/libavutil/loongarch/cpu.h b/libs/ffmpeg/libavutil/loongarch/cpu.h
new file mode 100644
index 000000000000..1a445c69bcb3
--- /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 000000000000..bcbe2c861d7b
--- /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 000000000000..c03403992d5f
--- /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 000000000000..2a7567c3ea8f
--- /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 000000000000..dd37ed7d0e1d
--- /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 000000000000..52fcef9e3711
--- /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 000000000000..61aeb7c02928
--- /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 000000000000..486de530f2e4
--- /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 000000000000..c01820da2dfe
--- /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 000000000000..fc2eabdb162f
--- /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 000000000000..b205d3fb2564
--- /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 000000000000..ab7648ac5705
--- /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, &current_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, &current_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 000000000000..78adc4f40793
--- /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 000000000000..c88a236a0c2d
--- /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 000000000000..d90bc2fcd131
--- /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 000000000000..7c6a01068a8c
--- /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 000000000000..ab24fae7779f
--- /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 000000000000..9f57b16ec27b
--- /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 000000000000..dad5c2775b26
--- /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 000000000000..90f9596defdb
--- /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 000000000000..0cc70eb64c64
--- /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 000000000000..8e91f0a2cca1
--- /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 000000000000..7a997cde1c8a
--- /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 000000000000..2e7b6457e02b
--- /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 000000000000..36973a54ea0b
--- /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 000000000000..6014f88be320
--- /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 000000000000..e08ab7b12e84
--- /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 000000000000..8a47be967968
--- /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 000000000000..1b7c6350e99d
--- /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 000000000000..30ac2aced76e
--- /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 000000000000..74c1f4892e68
--- /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 000000000000..0c72a88ecd7b
--- /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 000000000000..7a5eb2482665
--- /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 000000000000..4e9d78eb0ad2
--- /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 000000000000..105eb03dda4c
--- /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 000000000000..4eb612393281
--- /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 000000000000..e3104efc9fa9
--- /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 000000000000..9df9f905f3de
--- /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 000000000000..e1be5f0547af
--- /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 000000000000..6e55d711401f
--- /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 000000000000..a1593a0a7bf3
--- /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 000000000000..0df044032fb2
--- /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 000000000000..2e1220abd121
--- /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 000000000000..0574a46f94d9
--- /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 000000000000..a4a3f23db30e
--- /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 000000000000..bbbeb70ecd10
--- /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 000000000000..8275aa35a5c2
--- /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 000000000000..7650fc66ad73
--- /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 000000000000..f6f6f302c444
--- /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 000000000000..71342faea9a6
--- /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 000000000000..4b78978eb942
--- /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/parametricimmersive
+     */
+    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 000000000000..d6de47653288
--- /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 000000000000..c0a4ab3f2d39
--- /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 000000000000..26192a1d2f53
--- /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 000000000000..8629775a2b54
--- /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 000000000000..93a3795368e6
--- /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 000000000000..dd929bdafdc4
--- /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 000000000000..184e2d8c5f68
--- /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 000000000000..20b3882033dd
--- /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 000000000000..42ce655f365a
--- /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 000000000000..740afc478508
--- /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 000000000000..dc169b064a0d
--- /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 000000000000..d0f007ab1c4f
--- /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 000000000000..316100759e09
--- /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 000000000000..fe0fc835764c
--- /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 000000000000..259ebf166466
--- /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 000000000000..8ef43d1f98c2
--- /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 000000000000..03706b0d103b
--- /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 000000000000..6c231a517d32
--- /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 000000000000..fa53a46b9876
--- /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 000000000000..7b57b2d39a78
--- /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 000000000000..bbb8fbb1262e
--- /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 000000000000..9f9687eccbae
--- /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 000000000000..67f359e88c2e
--- /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 000000000000..05c132ada178
--- /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 000000000000..c950095735d7
--- /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 000000000000..7ea4283c947b
--- /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 000000000000..018f2a21accd
--- /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 000000000000..9261013bf612
--- /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 000000000000..d3fcdbf56349
--- /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 000000000000..26b9d74b584a
--- /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 000000000000..fc431fdd60c9
--- /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 000000000000..3f5075c06608
--- /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 000000000000..748b7ed3c944
--- /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 000000000000..afab190336f2
--- /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 000000000000..c61f6b0e9cd0
--- /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 000000000000..e4db2e34dbe5
--- /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 000000000000..33592dc12843
--- /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 000000000000..62265a5c0642
--- /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 000000000000..431716ab675a
--- /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 000000000000..8e8af0ae90cb
--- /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 000000000000..1370a084c91b
--- /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/9260c249140ef90b4299d0fe1aa3037e25228518/src/libraries/Common/src/System/IO/PathInternal.Windows.cs#L165
+ */
+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/9260c249140ef90b4299d0fe1aa3037e25228518/src/libraries/Common/src/System/IO/PathInternal.Windows.cs#L132
+ */
+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/2a99e18eedabcf1add064c099da59d9301ce45e0/src/libraries/System.Private.CoreLib/src/System/IO/PathHelper.Windows.cs#L70
+ */
+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/2a99e18eedabcf1add064c099da59d9301ce45e0/src/libraries/System.Private.CoreLib/src/System/IO/PathHelper.Windows.cs#L25
+ */
+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/9260c249140ef90b4299d0fe1aa3037e25228518/src/libraries/Common/src/System/IO/PathInternal.Windows.cs#L107
+ */
+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/2a99e18eedabcf1add064c099da59d9301ce45e0/src/libraries/System.Private.CoreLib/src/System/IO/Path.Windows.cs#L126
+ */
+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/9260c249140ef90b4299d0fe1aa3037e25228518/src/libraries/Common/src/System/IO/PathInternal.Windows.cs#L92
+     */
+    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 000000000000..f06ea2503523
--- /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 000000000000..1ce9dcfc650a
--- /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.c b/libs/ffmpeg/libavutil/x86/cpu.c
new file mode 100644
index 000000000000..431f8a180c4d
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/cpu.c
@@ -0,0 +1,291 @@
+/*
+ * CPU detection code, extracted from mmx.h
+ * (c)1997-99 by H. Dietz and R. Fisher
+ * Converted to C and improved by 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/cpu.h"
+#include "libavutil/cpu_internal.h"
+
+#if HAVE_X86ASM
+
+#define cpuid(index, eax, ebx, ecx, edx)        \
+    ff_cpu_cpuid(index, &eax, &ebx, &ecx, &edx)
+
+#define xgetbv(index, eax, edx)                 \
+    ff_cpu_xgetbv(index, &eax, &edx)
+
+#elif HAVE_INLINE_ASM
+
+/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
+#define cpuid(index, eax, ebx, ecx, edx)                        \
+    __asm__ volatile (                                          \
+        "mov    %%"FF_REG_b", %%"FF_REG_S" \n\t"                \
+        "cpuid                       \n\t"                      \
+        "xchg   %%"FF_REG_b", %%"FF_REG_S                       \
+        : "=a" (eax), "=S" (ebx), "=c" (ecx), "=d" (edx)        \
+        : "0" (index), "2"(0))
+
+#define xgetbv(index, eax, edx)                                 \
+    __asm__ (".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c" (index))
+
+#define get_eflags(x)                           \
+    __asm__ volatile ("pushfl     \n"           \
+                      "pop    %0  \n"           \
+                      : "=r"(x))
+
+#define set_eflags(x)                           \
+    __asm__ volatile ("push    %0 \n"           \
+                      "popfl      \n"           \
+                      :: "r"(x))
+
+#endif /* HAVE_INLINE_ASM */
+
+#if ARCH_X86_64
+
+#define cpuid_test() 1
+
+#elif HAVE_X86ASM
+
+#define cpuid_test ff_cpu_cpuid_test
+
+#elif HAVE_INLINE_ASM
+
+static int cpuid_test(void)
+{
+    x86_reg a, c;
+
+    /* Check if CPUID is supported by attempting to toggle the ID bit in
+     * the EFLAGS register. */
+    get_eflags(a);
+    set_eflags(a ^ 0x200000);
+    get_eflags(c);
+
+    return a != c;
+}
+#endif
+
+/* Function to test if multimedia instructions are supported...  */
+int ff_get_cpu_flags_x86(void)
+{
+    int rval = 0;
+
+#ifdef cpuid
+
+    int eax, ebx, ecx, edx;
+    int max_std_level, max_ext_level, std_caps = 0, ext_caps = 0;
+    int family = 0, model = 0;
+    union { int i[3]; char c[12]; } vendor;
+    int xcr0_lo = 0, xcr0_hi = 0;
+
+    if (!cpuid_test())
+        return 0; /* CPUID not supported */
+
+    cpuid(0, max_std_level, vendor.i[0], vendor.i[2], vendor.i[1]);
+
+    if (max_std_level >= 1) {
+        cpuid(1, eax, ebx, ecx, std_caps);
+        family = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
+        model  = ((eax >> 4) & 0xf) + ((eax >> 12) & 0xf0);
+        if (std_caps & (1 << 15))
+            rval |= AV_CPU_FLAG_CMOV;
+        if (std_caps & (1 << 23))
+            rval |= AV_CPU_FLAG_MMX;
+        if (std_caps & (1 << 25))
+            rval |= AV_CPU_FLAG_MMXEXT;
+#if HAVE_SSE
+        if (std_caps & (1 << 25))
+            rval |= AV_CPU_FLAG_SSE;
+        if (std_caps & (1 << 26))
+            rval |= AV_CPU_FLAG_SSE2;
+        if (ecx & 1)
+            rval |= AV_CPU_FLAG_SSE3;
+        if (ecx & 0x2)
+            rval |= AV_CPU_FLAG_CLMUL;
+        if (ecx & 0x00000200 )
+            rval |= AV_CPU_FLAG_SSSE3;
+        if (ecx & 0x00080000 )
+            rval |= AV_CPU_FLAG_SSE4;
+        if (ecx & 0x00100000 )
+            rval |= AV_CPU_FLAG_SSE42;
+        if (ecx & 0x02000000 )
+            rval |= AV_CPU_FLAG_AESNI;
+#if HAVE_AVX
+        /* Check OXSAVE and AVX bits */
+        if ((ecx & 0x18000000) == 0x18000000) {
+            /* Check for OS support */
+            xgetbv(0, xcr0_lo, xcr0_hi);
+            if ((xcr0_lo & 0x6) == 0x6) {
+                rval |= AV_CPU_FLAG_AVX;
+                if (ecx & 0x00001000)
+                    rval |= AV_CPU_FLAG_FMA3;
+            }
+        }
+#endif /* HAVE_AVX */
+#endif /* HAVE_SSE */
+    }
+    if (max_std_level >= 7) {
+        cpuid(7, eax, ebx, ecx, edx);
+#if HAVE_AVX2
+        if ((rval & AV_CPU_FLAG_AVX) && (ebx & 0x00000020))
+            rval |= AV_CPU_FLAG_AVX2;
+#if HAVE_AVX512 /* F, CD, BW, DQ, VL */
+        if ((xcr0_lo & 0xe0) == 0xe0) { /* OPMASK/ZMM state */
+            if ((rval & AV_CPU_FLAG_AVX2) && (ebx & 0xd0030000) == 0xd0030000) {
+                rval |= AV_CPU_FLAG_AVX512;
+#if HAVE_AVX512ICL
+                if ((ebx & 0xd0200000) == 0xd0200000 && (ecx & 0x5f42) == 0x5f42)
+                    rval |= AV_CPU_FLAG_AVX512ICL;
+#endif /* HAVE_AVX512ICL */
+            }
+        }
+#endif /* HAVE_AVX512 */
+#endif /* HAVE_AVX2 */
+        /* BMI1/2 don't need OS support */
+        if (ebx & 0x00000008) {
+            rval |= AV_CPU_FLAG_BMI1;
+            if (ebx & 0x00000100)
+                rval |= AV_CPU_FLAG_BMI2;
+        }
+    }
+
+    cpuid(0x80000000, max_ext_level, ebx, ecx, edx);
+
+    if (max_ext_level >= 0x80000001) {
+        cpuid(0x80000001, eax, ebx, ecx, ext_caps);
+        if (ext_caps & (1U << 31))
+            rval |= AV_CPU_FLAG_3DNOW;
+        if (ext_caps & (1 << 30))
+            rval |= AV_CPU_FLAG_3DNOWEXT;
+        if (ext_caps & (1 << 23))
+            rval |= AV_CPU_FLAG_MMX;
+        if (ext_caps & (1 << 22))
+            rval |= AV_CPU_FLAG_MMXEXT;
+
+        if (!strncmp(vendor.c, "AuthenticAMD", 12)) {
+        /* Allow for selectively disabling SSE2 functions on AMD processors
+           with SSE2 support but not SSE4a. This includes Athlon64, some
+           Opteron, and some Sempron processors. MMX, SSE, or 3DNow! are faster
+           than SSE2 often enough to utilize this special-case flag.
+           AV_CPU_FLAG_SSE2 and AV_CPU_FLAG_SSE2SLOW are both set in this case
+           so that SSE2 is used unless explicitly disabled by checking
+           AV_CPU_FLAG_SSE2SLOW. */
+            if (rval & AV_CPU_FLAG_SSE2 && !(ecx & 0x00000040))
+                rval |= AV_CPU_FLAG_SSE2SLOW;
+
+        /* Similar to the above but for AVX functions on AMD processors.
+           This is necessary only for functions using YMM registers on Bulldozer
+           and Jaguar based CPUs as they lack 256-bit execution units. SSE/AVX
+           functions using XMM registers are always faster on them.
+           AV_CPU_FLAG_AVX and AV_CPU_FLAG_AVXSLOW are both set so that AVX is
+           used unless explicitly disabled by checking AV_CPU_FLAG_AVXSLOW. */
+            if ((family == 0x15 || family == 0x16) && (rval & AV_CPU_FLAG_AVX))
+                rval |= AV_CPU_FLAG_AVXSLOW;
+
+        /* Zen 3 and earlier have slow gather */
+            if ((family <= 0x19) && (rval & AV_CPU_FLAG_AVX2))
+                rval |= AV_CPU_FLAG_SLOW_GATHER;
+        }
+
+        /* XOP and FMA4 use the AVX instruction coding scheme, so they can't be
+         * used unless the OS has AVX support. */
+        if (rval & AV_CPU_FLAG_AVX) {
+            if (ecx & 0x00000800)
+                rval |= AV_CPU_FLAG_XOP;
+            if (ecx & 0x00010000)
+                rval |= AV_CPU_FLAG_FMA4;
+        }
+    }
+
+    if (!strncmp(vendor.c, "GenuineIntel", 12)) {
+        if (family == 6 && (model == 9 || model == 13 || model == 14)) {
+            /* 6/9 (pentium-m "banias"), 6/13 (pentium-m "dothan"), and
+             * 6/14 (core1 "yonah") theoretically support sse2, but it's
+             * usually slower than mmx, so let's just pretend they don't.
+             * AV_CPU_FLAG_SSE2 is disabled and AV_CPU_FLAG_SSE2SLOW is
+             * enabled so that SSE2 is not used unless explicitly enabled
+             * by checking AV_CPU_FLAG_SSE2SLOW. The same situation
+             * applies for AV_CPU_FLAG_SSE3 and AV_CPU_FLAG_SSE3SLOW. */
+            if (rval & AV_CPU_FLAG_SSE2)
+                rval ^= AV_CPU_FLAG_SSE2SLOW | AV_CPU_FLAG_SSE2;
+            if (rval & AV_CPU_FLAG_SSE3)
+                rval ^= AV_CPU_FLAG_SSE3SLOW | AV_CPU_FLAG_SSE3;
+        }
+        /* The Atom processor has SSSE3 support, which is useful in many cases,
+         * but sometimes the SSSE3 version is slower than the SSE2 equivalent
+         * on the Atom, but is generally faster on other processors supporting
+         * SSSE3. This flag allows for selectively disabling certain SSSE3
+         * functions on the Atom. */
+        if (family == 6 && model == 28)
+            rval |= AV_CPU_FLAG_ATOM;
+
+        /* Conroe has a slow shuffle unit. Check the model number to ensure not
+         * to include crippled low-end Penryns and Nehalems that lack SSE4. */
+        if ((rval & AV_CPU_FLAG_SSSE3) && !(rval & AV_CPU_FLAG_SSE4) &&
+            family == 6 && model < 23)
+            rval |= AV_CPU_FLAG_SSSE3SLOW;
+
+        /* Ice Lake and below have slow gather due to Gather Data Sampling
+         * mitigation. */
+        if ((rval & AV_CPU_FLAG_AVX2) && family == 6 && model < 143)
+            rval |= AV_CPU_FLAG_SLOW_GATHER;
+    }
+
+#endif /* cpuid */
+
+    return rval;
+}
+
+size_t ff_get_cpu_max_align_x86(void)
+{
+    int flags = av_get_cpu_flags();
+
+    if (flags & AV_CPU_FLAG_AVX512)
+        return 64;
+    if (flags & (AV_CPU_FLAG_AVX2      |
+                 AV_CPU_FLAG_AVX       |
+                 AV_CPU_FLAG_XOP       |
+                 AV_CPU_FLAG_FMA4      |
+                 AV_CPU_FLAG_FMA3      |
+                 AV_CPU_FLAG_AVXSLOW))
+        return 32;
+    if (flags & (AV_CPU_FLAG_AESNI     |
+                 AV_CPU_FLAG_SSE42     |
+                 AV_CPU_FLAG_SSE4      |
+                 AV_CPU_FLAG_SSSE3     |
+                 AV_CPU_FLAG_SSE3      |
+                 AV_CPU_FLAG_SSE2      |
+                 AV_CPU_FLAG_SSE       |
+                 AV_CPU_FLAG_ATOM      |
+                 AV_CPU_FLAG_SSSE3SLOW |
+                 AV_CPU_FLAG_SSE3SLOW  |
+                 AV_CPU_FLAG_SSE2SLOW))
+        return 16;
+
+    return 8;
+}
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/cpu.h b/libs/ffmpeg/libavutil/x86/cpu.h
new file mode 100644
index 000000000000..af081b2ed8ce
--- /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/cpuid.asm b/libs/ffmpeg/libavutil/x86/cpuid.asm
new file mode 100644
index 000000000000..766f77fcdfe2
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/cpuid.asm
@@ -0,0 +1,91 @@
+;*****************************************************************************
+;* Copyright (C) 2005-2010 x264 project
+;*
+;* Authors: Loren Merritt <lorenm@u.washington.edu>
+;*          Fiona Glaser <fiona@x264.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/x86/x86util.asm"
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; void ff_cpu_cpuid(int index, int *eax, int *ebx, int *ecx, int *edx)
+;-----------------------------------------------------------------------------
+cglobal cpu_cpuid, 5,7
+    push rbx
+    push  r4
+    push  r3
+    push  r2
+    push  r1
+    mov  eax, r0d
+    xor  ecx, ecx
+    cpuid
+    pop   r4
+    mov [r4], eax
+    pop   r4
+    mov [r4], ebx
+    pop   r4
+    mov [r4], ecx
+    pop   r4
+    mov [r4], edx
+    pop  rbx
+    RET
+
+;-----------------------------------------------------------------------------
+; void ff_cpu_xgetbv(int op, int *eax, int *edx)
+;-----------------------------------------------------------------------------
+cglobal cpu_xgetbv, 3,7
+    push  r2
+    push  r1
+    mov  ecx, r0d
+    xgetbv
+    pop   r4
+    mov [r4], eax
+    pop   r4
+    mov [r4], edx
+    RET
+
+%if ARCH_X86_64 == 0
+;-----------------------------------------------------------------------------
+; int ff_cpu_cpuid_test(void)
+; return 0 if unsupported
+;-----------------------------------------------------------------------------
+cglobal cpu_cpuid_test
+    pushfd
+    push    ebx
+    push    ebp
+    push    esi
+    push    edi
+    pushfd
+    pop     eax
+    mov     ebx, eax
+    xor     eax, 0x200000
+    push    eax
+    popfd
+    pushfd
+    pop     eax
+    xor     eax, ebx
+    pop     edi
+    pop     esi
+    pop     ebp
+    pop     ebx
+    popfd
+    ret
+%endif
diff --git a/libs/ffmpeg/libavutil/x86/crc.asm b/libs/ffmpeg/libavutil/x86/crc.asm
new file mode 100644
index 000000000000..9eaf2d6b1b4f
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/crc.asm
@@ -0,0 +1,298 @@
+;*****************************************************************************
+;* 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
+;******************************************************************************
+
+%include "libavutil/x86/x86util.asm"
+
+SECTION_RODATA
+reverse_shuffle: db 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
+
+partial_bytes_shuf_tab: db 255, 254, 253, 252, 251, 250, 249, 248,\
+                           247, 246, 245, 244, 243, 242, 241, 240,\
+                             0,   1,   2,   3,   4,   5,   6,   7,\
+                             8,   9,  10,  11,  12,  13,  14,  15
+
+SECTION .text
+
+%macro FOLD_128_TO_64 4
+; %1 LE ; %2 128 bit fold reg ; %3 pre-computed constant reg ; %4 tmp reg
+%if %1 == 1
+    mova      %4, %2
+    pclmulqdq %2, %3, 0x00
+    psrldq    %4, 8
+    pxor      %2, %4
+    mova      %4, %2
+    psllq     %4, 32
+    pclmulqdq %4, %3, 0x10
+    pxor      %2, %4
+%else
+    movq      %4, %2
+    pclmulqdq %2, %3, 0x11
+    pslldq    %4, 4
+    pxor      %4, %2
+    mova      %2, %4
+    pclmulqdq %4, %3, 0x01
+    pxor      %2, %4
+%endif
+%endmacro
+
+%macro FOLD_64_TO_32 4
+; %1 LE ; %2 128 bit fold reg ; %3 pre-computed constant reg ; %4 tmp reg
+%if %1 == 1
+    pxor      %4, %4
+    pblendw   %4, %2, 0xfc
+    mova      %2, %4
+    pclmulqdq %4, %3, 0x00
+    pxor      %4, %2
+    pclmulqdq %4, %3, 0x10
+    pxor      %2, %4
+    pextrd   eax, %2, 2
+%else
+    mova      %4, %2
+    pclmulqdq %2, %3, 0x00
+    pclmulqdq %2, %3, 0x11
+    pxor      %2, %4
+    movd     eax, %2
+    bswap    eax
+%endif
+%endmacro
+
+%macro FOLD_SINGLE 4
+; %1 temp ; %2 fold reg ; %3 pre-computed constants ; %4 input data block
+    mova      %1, %2
+    pclmulqdq %1, %3, 0x01
+    pxor      %1, %4
+    pclmulqdq %2, %3, 0x10
+    pxor      %2, %1
+%endmacro
+
+%macro XMM_SHIFT_LEFT 4
+; %1 xmm input reg ; %2 shift bytes amount ; %3 temp xmm register ; %4 temp gpr
+    lea    %4, [partial_bytes_shuf_tab]
+    movu   %3, [%4 + 16 - (%2)]
+    pshufb %1, %3
+%endmacro
+
+%macro MEMCPY_0_15 6
+; %1 dst ; %2 src ; %3 len ; %4, %5 temp gpr register; %6 done label
+    cmp %3, 8
+    jae .between_8_15
+    cmp %3, 4
+    jae .between_4_7
+    cmp %3, 1
+    ja .between_2_3
+    jb %6
+    mov  %4b, [%2]
+    mov [%1], %4b
+    jmp %6
+
+.between_8_15:
+%if ARCH_X86_64
+    mov           %4q, [%2]
+    mov           %5q, [%2 + %3 - 8]
+    mov          [%1], %4q
+    mov [%1 + %3 - 8], %5q
+    jmp %6
+%else
+    xor            %5, %5
+.copy4b:
+        mov       %4d, [%2 + %5]
+        mov [%1 + %5], %4d
+        add        %5, 4
+        lea        %4, [%5 + 4]
+        cmp        %4, %3
+        jb        .copy4b
+
+    mov           %4d, [%2 + %3 - 4]
+    mov [%1 + %3 - 4], %4d
+    jmp %6
+%endif
+.between_4_7:
+    mov           %4d, [%2]
+    mov           %5d, [%2 + %3 - 4]
+    mov          [%1], %4d
+    mov [%1 + %3 - 4], %5d
+    jmp %6
+.between_2_3:
+    mov           %4w, [%2]
+    mov           %5w, [%2 + %3 - 2]
+    mov          [%1], %4w
+    mov [%1 + %3 - 2], %5w
+    ; fall through, %6 label is expected to be next instruction
+%endmacro
+
+%macro CRC 1
+%define CTX r0+4
+;-----------------------------------------------------------------------------------------------
+; ff_crc[_le]_clmul(const uint8_t *ctx, uint32_t crc, const uint8_t *buffer, size_t length
+;-----------------------------------------------------------------------------------------------
+; %1 == 1 - LE format
+%if %1 == 1
+cglobal crc_le, 4, 6, 6+4*ARCH_X86_64, 0x10
+%else
+cglobal crc,    4, 6, 7+4*ARCH_X86_64, 0x10
+%endif
+
+%if ARCH_X86_32
+    %define m10 m6
+%endif
+
+%if %1 == 0
+    mova  m10, [reverse_shuffle]
+%endif
+
+    movd   m4, r1d
+%if ARCH_X86_32
+    ; skip 4x unrolled loop due to only 8 XMM reg being available in X86_32
+    jmp   .less_than_64bytes
+%else
+    cmp    r3, 64
+    jb    .less_than_64bytes
+    movu   m1, [r2 +  0]
+    movu   m3, [r2 + 16]
+    movu   m2, [r2 + 32]
+    movu   m0, [r2 + 48]
+    pxor   m1, m4
+%if %1 == 0
+    pshufb m0, m10
+    pshufb m1, m10
+    pshufb m2, m10
+    pshufb m3, m10
+%endif
+    mov    r4, 64
+    cmp    r3, 128
+    jb    .reduce_4x_to_1
+    movu   m4, [CTX]
+
+.fold_4x_loop:
+        movu        m6, [r2 + r4 +  0]
+        movu        m7, [r2 + r4 + 16]
+        movu        m8, [r2 + r4 + 32]
+        movu        m9, [r2 + r4 + 48]
+%if %1 == 0
+        pshufb      m6, m10
+        pshufb      m7, m10
+        pshufb      m8, m10
+        pshufb      m9, m10
+%endif
+        FOLD_SINGLE m5, m1, m4, m6
+        FOLD_SINGLE m5, m3, m4, m7
+        FOLD_SINGLE m5, m2, m4, m8
+        FOLD_SINGLE m5, m0, m4, m9
+        add         r4, 64
+        lea         r5, [r4 + 64]
+        cmp         r5, r3
+        jbe        .fold_4x_loop
+
+.reduce_4x_to_1:
+    movu        m4, [CTX + 16]
+    FOLD_SINGLE m5, m1, m4, m3
+    FOLD_SINGLE m5, m1, m4, m2
+    FOLD_SINGLE m5, m1, m4, m0
+%endif
+
+.fold_1x_pre:
+    lea  r5, [r4 + 16]
+    cmp  r5, r3
+    ja  .partial_block
+
+.fold_1x_loop:
+        movu        m2, [r2 + r4]
+%if %1 == 0
+        pshufb      m2, m10
+%endif
+        FOLD_SINGLE m5, m1, m4, m2
+        add         r4, 16
+        lea         r5, [r4 + 16]
+        cmp         r5, r3
+        jbe        .fold_1x_loop
+
+.partial_block:
+    cmp         r4, r3
+    jae        .reduce_128_to_64
+    movu        m2, [r2 + r3 - 16]
+    and         r3, 0xf
+    lea         r4, [partial_bytes_shuf_tab]
+    movu        m0, [r3 + r4]
+%if %1 == 0
+    pshufb      m1, m10
+%endif
+    mova        m3, m1
+    pcmpeqd     m5, m5 ; m5 = _mm_set1_epi8(0xff)
+    pxor        m5, m0
+    pshufb      m3, m5
+    pblendvb    m2, m3, m0
+    pshufb      m1, m0
+%if %1 == 0
+    pshufb      m1, m10
+    pshufb      m2, m10
+%endif
+    FOLD_SINGLE m5, m1, m4, m2
+
+.reduce_128_to_64:
+    movu           m4, [CTX + 32]
+    FOLD_128_TO_64 %1, m1, m4, m5
+.reduce_64_to_32:
+    movu           m4, [CTX + 48]
+    FOLD_64_TO_32  %1, m1, m4, m5
+    RET
+
+.less_than_64bytes:
+    cmp    r3, 16
+    jb    .less_than_16bytes
+    movu   m1, [r2]
+    pxor   m1, m4
+%if %1 == 0
+    pshufb m1, m10
+%endif
+    mov    r4, 16
+    movu   m4, [CTX + 16]
+    jmp   .fold_1x_pre
+
+.less_than_16bytes:
+    pxor           m1, m1
+    movu        [rsp], m1
+    MEMCPY_0_15   rsp, r2, r3, r1, r4, .memcpy_done
+
+.memcpy_done:
+    movu           m1, [rsp]
+    pxor           m1, m4
+    cmp            r3, 5
+    jb            .less_than_5bytes
+    XMM_SHIFT_LEFT m1, (16 - r3), m2, r4
+%if %1 == 0
+    pshufb         m1, m10
+%endif
+    jmp           .reduce_128_to_64
+
+.less_than_5bytes:
+%if %1 == 0
+    XMM_SHIFT_LEFT m1, (4 - r3), m2, r4
+    movq          m10, [reverse_shuffle + 8] ; 0x0001020304050607
+    pshufb         m1, m10
+%else
+    XMM_SHIFT_LEFT m1, (8 - r3), m2, r4
+%endif
+    jmp .reduce_64_to_32
+
+%endmacro
+
+INIT_XMM clmul
+CRC 0
+CRC 1
diff --git a/libs/ffmpeg/libavutil/x86/crc.h b/libs/ffmpeg/libavutil/x86/crc.h
new file mode 100644
index 000000000000..c836c090c622
--- /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/fixed_dsp.asm b/libs/ffmpeg/libavutil/x86/fixed_dsp.asm
new file mode 100644
index 000000000000..2f411850f456
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/fixed_dsp.asm
@@ -0,0 +1,48 @@
+;*****************************************************************************
+;* x86-optimized Float DSP functions
+;*
+;* Copyright 2016 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 "libavutil/x86/x86util.asm"
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; void ff_butterflies_fixed(float *src0, float *src1, int len);
+;-----------------------------------------------------------------------------
+INIT_XMM sse2
+cglobal butterflies_fixed, 3,3,3, src0, src1, len
+    shl       lend, 2
+    add      src0q, lenq
+    add      src1q, lenq
+    neg       lenq
+
+align 16
+.loop:
+    mova        m0, [src0q + lenq]
+    mova        m1, [src1q + lenq]
+    mova        m2, m0
+    paddd       m0, m1
+    psubd       m2, m1
+    mova        [src0q + lenq], m0
+    mova        [src1q + lenq], m2
+    add       lenq, mmsize
+    jl .loop
+    RET
diff --git a/libs/ffmpeg/libavutil/x86/fixed_dsp_init.c b/libs/ffmpeg/libavutil/x86/fixed_dsp_init.c
new file mode 100644
index 000000000000..ed8c43a4d41b
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/fixed_dsp_init.c
@@ -0,0 +1,37 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/fixed_dsp.h"
+#include "cpu.h"
+
+void ff_butterflies_fixed_sse2(int *restrict src0, int *restrict src1, int len);
+
+av_cold void ff_fixed_dsp_init_x86(AVFixedDSPContext *fdsp)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        fdsp->butterflies_fixed = ff_butterflies_fixed_sse2;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/float_dsp.asm b/libs/ffmpeg/libavutil/x86/float_dsp.asm
new file mode 100644
index 000000000000..cac2a2b66815
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/float_dsp.asm
@@ -0,0 +1,640 @@
+;*****************************************************************************
+;* x86-optimized Float DSP functions
+;*
+;* 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 "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+pd_reverse: dd 7, 6, 5, 4, 3, 2, 1, 0
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; void vector_fmul(float *dst, const float *src0, const float *src1, int len)
+;-----------------------------------------------------------------------------
+%macro VECTOR_FMUL 0
+cglobal vector_fmul, 4,4,2, dst, src0, src1, len
+    lea       lenq, [lend*4 - 64]
+ALIGN 16
+.loop:
+%assign a 0
+%rep 32/mmsize
+    mova      m0,   [src0q + lenq + (a+0)*mmsize]
+    mova      m1,   [src0q + lenq + (a+1)*mmsize]
+    mulps     m0, m0, [src1q + lenq + (a+0)*mmsize]
+    mulps     m1, m1, [src1q + lenq + (a+1)*mmsize]
+    mova      [dstq + lenq + (a+0)*mmsize], m0
+    mova      [dstq + lenq + (a+1)*mmsize], m1
+%assign a a+2
+%endrep
+
+    sub       lenq, 64
+    jge       .loop
+    RET
+%endmacro
+
+INIT_XMM sse
+VECTOR_FMUL
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_FMUL
+%endif
+
+;-----------------------------------------------------------------------------
+; void vector_dmul(double *dst, const double *src0, const double *src1, int len)
+;-----------------------------------------------------------------------------
+%macro VECTOR_DMUL 0
+cglobal vector_dmul, 4,4,4, dst, src0, src1, len
+    lea       lend, [lenq*8 - mmsize*4]
+ALIGN 16
+.loop:
+    movaps    m0,     [src0q + lenq + 0*mmsize]
+    movaps    m1,     [src0q + lenq + 1*mmsize]
+    movaps    m2,     [src0q + lenq + 2*mmsize]
+    movaps    m3,     [src0q + lenq + 3*mmsize]
+    mulpd     m0, m0, [src1q + lenq + 0*mmsize]
+    mulpd     m1, m1, [src1q + lenq + 1*mmsize]
+    mulpd     m2, m2, [src1q + lenq + 2*mmsize]
+    mulpd     m3, m3, [src1q + lenq + 3*mmsize]
+    movaps    [dstq + lenq + 0*mmsize], m0
+    movaps    [dstq + lenq + 1*mmsize], m1
+    movaps    [dstq + lenq + 2*mmsize], m2
+    movaps    [dstq + lenq + 3*mmsize], m3
+
+    sub       lenq, mmsize*4
+    jge       .loop
+    RET
+%endmacro
+
+INIT_XMM sse2
+VECTOR_DMUL
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_DMUL
+%endif
+
+;------------------------------------------------------------------------------
+; void ff_vector_fmac_scalar(float *dst, const float *src, float mul, int len)
+;------------------------------------------------------------------------------
+
+%macro VECTOR_FMAC_SCALAR 0
+%if UNIX64
+cglobal vector_fmac_scalar, 3,3,5, dst, src, len
+%else
+cglobal vector_fmac_scalar, 4,4,5, dst, src, mul, len
+%endif
+%if ARCH_X86_32
+    VBROADCASTSS m0, mulm
+%else
+%if WIN64
+    SWAP 0, 2
+%endif
+    shufps      xm0, xm0, 0
+%if cpuflag(avx)
+    vinsertf128  m0, m0, xm0, 1
+%endif
+%endif
+    lea    lenq, [lend*4-64]
+.loop:
+%if cpuflag(fma3)
+    mova     m1,     [dstq+lenq]
+    mova     m2,     [dstq+lenq+1*mmsize]
+    fmaddps  m1, m0, [srcq+lenq], m1
+    fmaddps  m2, m0, [srcq+lenq+1*mmsize], m2
+%else ; cpuflag
+    mulps    m1, m0, [srcq+lenq]
+    mulps    m2, m0, [srcq+lenq+1*mmsize]
+%if mmsize < 32
+    mulps    m3, m0, [srcq+lenq+2*mmsize]
+    mulps    m4, m0, [srcq+lenq+3*mmsize]
+%endif ; mmsize
+    addps    m1, m1, [dstq+lenq]
+    addps    m2, m2, [dstq+lenq+1*mmsize]
+%if mmsize < 32
+    addps    m3, m3, [dstq+lenq+2*mmsize]
+    addps    m4, m4, [dstq+lenq+3*mmsize]
+%endif ; mmsize
+%endif ; cpuflag
+    mova  [dstq+lenq], m1
+    mova  [dstq+lenq+1*mmsize], m2
+%if mmsize < 32
+    mova  [dstq+lenq+2*mmsize], m3
+    mova  [dstq+lenq+3*mmsize], m4
+%endif ; mmsize
+    sub    lenq, 64
+    jge .loop
+    RET
+%endmacro
+
+INIT_XMM sse
+VECTOR_FMAC_SCALAR
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_FMAC_SCALAR
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+VECTOR_FMAC_SCALAR
+%endif
+
+;------------------------------------------------------------------------------
+; void ff_vector_fmul_scalar(float *dst, const float *src, float mul, int len)
+;------------------------------------------------------------------------------
+
+%macro VECTOR_FMUL_SCALAR 0
+%if UNIX64
+cglobal vector_fmul_scalar, 3,3,2, dst, src, len
+%else
+cglobal vector_fmul_scalar, 4,4,3, dst, src, mul, len
+%endif
+%if ARCH_X86_32
+    movss    m0, mulm
+%elif WIN64
+    SWAP 0, 2
+%endif
+    shufps   m0, m0, 0
+    lea    lenq, [lend*4-mmsize]
+.loop:
+    mova     m1, [srcq+lenq]
+    mulps    m1, m0
+    mova  [dstq+lenq], m1
+    sub    lenq, mmsize
+    jge .loop
+    RET
+%endmacro
+
+INIT_XMM sse
+VECTOR_FMUL_SCALAR
+
+;------------------------------------------------------------------------------
+; void ff_vector_dmac_scalar(double *dst, const double *src, double mul,
+;                            int len)
+;------------------------------------------------------------------------------
+
+%macro VECTOR_DMAC_SCALAR 0
+%if ARCH_X86_32
+cglobal vector_dmac_scalar, 2,4,5, dst, src, mul, len, lenaddr
+    mov          lenq, lenaddrm
+    VBROADCASTSD m0, mulm
+%else
+%if UNIX64
+cglobal vector_dmac_scalar, 3,3,5, dst, src, len
+%else
+cglobal vector_dmac_scalar, 4,4,5, dst, src, mul, len
+    SWAP 0, 2
+%endif
+    movlhps     xm0, xm0
+%if cpuflag(avx)
+    vinsertf128  m0, m0, xm0, 1
+%endif
+%endif
+    lea    lenq, [lend*8-mmsize*4]
+.loop:
+%if cpuflag(fma3)
+    movaps   m1,     [dstq+lenq]
+    movaps   m2,     [dstq+lenq+1*mmsize]
+    movaps   m3,     [dstq+lenq+2*mmsize]
+    movaps   m4,     [dstq+lenq+3*mmsize]
+    fmaddpd  m1, m0, [srcq+lenq], m1
+    fmaddpd  m2, m0, [srcq+lenq+1*mmsize], m2
+    fmaddpd  m3, m0, [srcq+lenq+2*mmsize], m3
+    fmaddpd  m4, m0, [srcq+lenq+3*mmsize], m4
+%else ; cpuflag
+    mulpd    m1, m0, [srcq+lenq]
+    mulpd    m2, m0, [srcq+lenq+1*mmsize]
+    mulpd    m3, m0, [srcq+lenq+2*mmsize]
+    mulpd    m4, m0, [srcq+lenq+3*mmsize]
+    addpd    m1, m1, [dstq+lenq]
+    addpd    m2, m2, [dstq+lenq+1*mmsize]
+    addpd    m3, m3, [dstq+lenq+2*mmsize]
+    addpd    m4, m4, [dstq+lenq+3*mmsize]
+%endif ; cpuflag
+    movaps [dstq+lenq], m1
+    movaps [dstq+lenq+1*mmsize], m2
+    movaps [dstq+lenq+2*mmsize], m3
+    movaps [dstq+lenq+3*mmsize], m4
+    sub    lenq, mmsize*4
+    jge .loop
+    RET
+%endmacro
+
+INIT_XMM sse2
+VECTOR_DMAC_SCALAR
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_DMAC_SCALAR
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+VECTOR_DMAC_SCALAR
+%endif
+
+;------------------------------------------------------------------------------
+; void ff_vector_dmul_scalar(double *dst, const double *src, double mul,
+;                            int len)
+;------------------------------------------------------------------------------
+
+%macro VECTOR_DMUL_SCALAR 0
+%if ARCH_X86_32
+cglobal vector_dmul_scalar, 3,4,3, dst, src, mul, len, lenaddr
+    mov          lenq, lenaddrm
+%elif UNIX64
+cglobal vector_dmul_scalar, 3,3,3, dst, src, len
+%else
+cglobal vector_dmul_scalar, 4,4,3, dst, src, mul, len
+%endif
+%if ARCH_X86_32
+    VBROADCASTSD   m0, mulm
+%else
+%if WIN64
+    SWAP 0, 2
+%endif
+    movlhps       xm0, xm0
+%if cpuflag(avx)
+    vinsertf128   ym0, ym0, xm0, 1
+%endif
+%endif
+    lea          lenq, [lend*8-2*mmsize]
+.loop:
+    mulpd          m1, m0, [srcq+lenq       ]
+    mulpd          m2, m0, [srcq+lenq+mmsize]
+    movaps [dstq+lenq       ], m1
+    movaps [dstq+lenq+mmsize], m2
+    sub          lenq, 2*mmsize
+    jge .loop
+    RET
+%endmacro
+
+INIT_XMM sse2
+VECTOR_DMUL_SCALAR
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_DMUL_SCALAR
+%endif
+
+;-----------------------------------------------------------------------------
+; vector_fmul_window(float *dst, const float *src0,
+;                    const float *src1, const float *win, int len);
+;-----------------------------------------------------------------------------
+INIT_XMM sse
+cglobal vector_fmul_window, 5, 6, 6, dst, src0, src1, win, len, len1
+    shl     lend, 2
+    lea    len1q, [lenq - mmsize]
+    add    src0q, lenq
+    add     dstq, lenq
+    add     winq, lenq
+    neg     lenq
+.loop:
+    mova      m0, [winq  + lenq]
+    mova      m4, [src0q + lenq]
+    mova      m1, [winq  + len1q]
+    mova      m5, [src1q + len1q]
+    shufps    m1, m1, 0x1b
+    shufps    m5, m5, 0x1b
+    mova      m2, m0
+    mova      m3, m1
+    mulps     m2, m4
+    mulps     m3, m5
+    mulps     m1, m4
+    mulps     m0, m5
+    addps     m2, m3
+    subps     m1, m0
+    shufps    m2, m2, 0x1b
+    mova      [dstq + lenq], m1
+    mova      [dstq + len1q], m2
+    sub       len1q, mmsize
+    add       lenq,  mmsize
+    jl .loop
+    RET
+
+;-----------------------------------------------------------------------------
+; vector_fmul_add(float *dst, const float *src0, const float *src1,
+;                 const float *src2, int len)
+;-----------------------------------------------------------------------------
+%macro VECTOR_FMUL_ADD 0
+cglobal vector_fmul_add, 5,5,4, dst, src0, src1, src2, len
+    lea       lenq, [lend*4 - 2*mmsize]
+ALIGN 16
+.loop:
+    mova    m0,   [src0q + lenq]
+    mova    m1,   [src0q + lenq + mmsize]
+%if cpuflag(fma3)
+    mova    m2,     [src2q + lenq]
+    mova    m3,     [src2q + lenq + mmsize]
+    fmaddps m0, m0, [src1q + lenq], m2
+    fmaddps m1, m1, [src1q + lenq + mmsize], m3
+%else
+    mulps   m0, m0, [src1q + lenq]
+    mulps   m1, m1, [src1q + lenq + mmsize]
+    addps   m0, m0, [src2q + lenq]
+    addps   m1, m1, [src2q + lenq + mmsize]
+%endif
+    mova    [dstq + lenq], m0
+    mova    [dstq + lenq + mmsize], m1
+
+    sub     lenq,   2*mmsize
+    jge     .loop
+    RET
+%endmacro
+
+INIT_XMM sse
+VECTOR_FMUL_ADD
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_FMUL_ADD
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+VECTOR_FMUL_ADD
+%endif
+
+;-----------------------------------------------------------------------------
+; void vector_fmul_reverse(float *dst, const float *src0, const float *src1,
+;                          int len)
+;-----------------------------------------------------------------------------
+%macro VECTOR_FMUL_REVERSE 0
+cglobal vector_fmul_reverse, 4,4,2, dst, src0, src1, len
+%if cpuflag(avx2)
+    movaps  m2, [pd_reverse]
+%endif
+    lea       lenq, [lend*4 - 2*mmsize]
+ALIGN 16
+.loop:
+%if cpuflag(avx2)
+    vpermps m0, m2, [src1q]
+    vpermps m1, m2, [src1q+mmsize]
+%elif cpuflag(avx)
+    vmovaps     xmm0, [src1q + 16]
+    vinsertf128 m0, m0, [src1q], 1
+    vshufps     m0, m0, m0, q0123
+    vmovaps     xmm1, [src1q + mmsize + 16]
+    vinsertf128 m1, m1, [src1q + mmsize], 1
+    vshufps     m1, m1, m1, q0123
+%else
+    mova    m0, [src1q]
+    mova    m1, [src1q + mmsize]
+    shufps  m0, m0, q0123
+    shufps  m1, m1, q0123
+%endif
+    mulps   m0, m0, [src0q + lenq + mmsize]
+    mulps   m1, m1, [src0q + lenq]
+    movaps  [dstq + lenq + mmsize], m0
+    movaps  [dstq + lenq], m1
+    add     src1q, 2*mmsize
+    sub     lenq,  2*mmsize
+    jge     .loop
+    RET
+%endmacro
+
+INIT_XMM sse
+VECTOR_FMUL_REVERSE
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+VECTOR_FMUL_REVERSE
+%endif
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+VECTOR_FMUL_REVERSE
+%endif
+
+; float scalarproduct_float_sse(const float *v1, const float *v2, int len)
+INIT_XMM sse
+cglobal scalarproduct_float, 3,3,2, v1, v2, offset
+    shl   offsetd, 2
+    add       v1q, offsetq
+    add       v2q, offsetq
+    neg   offsetq
+    xorps    xmm0, xmm0
+.loop:
+    movaps   xmm1, [v1q+offsetq]
+    mulps    xmm1, [v2q+offsetq]
+    addps    xmm0, xmm1
+    add   offsetq, 16
+    js .loop
+    movhlps  xmm1, xmm0
+    addps    xmm0, xmm1
+    movss    xmm1, xmm0
+    shufps   xmm0, xmm0, 1
+    addss    xmm0, xmm1
+%if ARCH_X86_64 == 0
+    movss     r0m,  xmm0
+    fld dword r0m
+%endif
+    RET
+
+INIT_YMM fma3
+cglobal scalarproduct_float, 3,5,8, v1, v2, size, len, offset
+    xor   offsetq, offsetq
+    xorps      m0, m0, m0
+    shl     sized, 2
+    mov      lenq, sizeq
+    cmp      lenq, 32
+    jl   .l16
+    cmp      lenq, 64
+    jl   .l32
+    xorps    m1, m1, m1
+    cmp      lenq, 128
+    jl   .l64
+    and    lenq, ~127
+    xorps    m2, m2, m2
+    xorps    m3, m3, m3
+.loop128:
+    movups   m4, [v1q+offsetq]
+    movups   m5, [v1q+offsetq + 32]
+    movups   m6, [v1q+offsetq + 64]
+    movups   m7, [v1q+offsetq + 96]
+    fmaddps  m0, m4, [v2q+offsetq     ], m0
+    fmaddps  m1, m5, [v2q+offsetq + 32], m1
+    fmaddps  m2, m6, [v2q+offsetq + 64], m2
+    fmaddps  m3, m7, [v2q+offsetq + 96], m3
+    add   offsetq, 128
+    cmp   offsetq, lenq
+    jl .loop128
+    addps    m0, m0, m2
+    addps    m1, m1, m3
+    mov      lenq, sizeq
+    and      lenq, 127
+    cmp      lenq, 64
+    jge .l64
+    addps    m0, m0, m1
+    cmp      lenq, 32
+    jge .l32
+    vextractf128 xmm2, m0, 1
+    addps    xmm0, xmm2
+    cmp      lenq, 16
+    jge .l16
+    movhlps  xmm1, xmm0
+    addps    xmm0, xmm1
+    movss    xmm1, xmm0
+    shufps   xmm0, xmm0, 1
+    addss    xmm0, xmm1
+%if ARCH_X86_64 == 0
+    movss r0m, xm0
+    fld dword r0m
+%endif
+    RET
+.l64:
+    and    lenq, ~63
+    add    lenq, offsetq
+.loop64:
+    movups   m4, [v1q+offsetq]
+    movups   m5, [v1q+offsetq + 32]
+    fmaddps  m0, m4, [v2q+offsetq], m0
+    fmaddps  m1, m5, [v2q+offsetq + 32], m1
+    add   offsetq, 64
+    cmp   offsetq, lenq
+    jl .loop64
+    addps    m0, m0, m1
+    mov      lenq, sizeq
+    and      lenq, 63
+    cmp      lenq, 32
+    jge .l32
+    vextractf128 xmm2, m0, 1
+    addps    xmm0, xmm2
+    cmp      lenq, 16
+    jge .l16
+    movhlps  xmm1, xmm0
+    addps    xmm0, xmm1
+    movss    xmm1, xmm0
+    shufps   xmm0, xmm0, 1
+    addss    xmm0, xmm1
+%if ARCH_X86_64 == 0
+    movss r0m, xm0
+    fld dword r0m
+%endif
+    RET
+.l32:
+    and    lenq, ~31
+    add    lenq, offsetq
+.loop32:
+    movups   m4, [v1q+offsetq]
+    fmaddps  m0, m4, [v2q+offsetq], m0
+    add   offsetq, 32
+    cmp   offsetq, lenq
+    jl .loop32
+    vextractf128 xmm2, m0, 1
+    addps    xmm0, xmm2
+    mov      lenq, sizeq
+    and      lenq, 31
+    cmp      lenq, 16
+    jge .l16
+    movhlps  xmm1, xmm0
+    addps    xmm0, xmm1
+    movss    xmm1, xmm0
+    shufps   xmm0, xmm0, 1
+    addss    xmm0, xmm1
+%if ARCH_X86_64 == 0
+    movss r0m, xm0
+    fld dword r0m
+%endif
+    RET
+.l16:
+    and    lenq, ~15
+    add    lenq, offsetq
+.loop16:
+    movaps   xmm1, [v1q+offsetq]
+    mulps    xmm1, [v2q+offsetq]
+    addps    xmm0, xmm1
+    add   offsetq, 16
+    cmp   offsetq, lenq
+    jl .loop16
+    movhlps  xmm1, xmm0
+    addps    xmm0, xmm1
+    movss    xmm1, xmm0
+    shufps   xmm0, xmm0, 1
+    addss    xmm0, xmm1
+%if ARCH_X86_64 == 0
+    movss r0m, xm0
+    fld dword r0m
+%endif
+    RET
+
+;---------------------------------------------------------------------------------
+; double scalarproduct_double(const double *v1, const double *v2, size_t len)
+;---------------------------------------------------------------------------------
+%macro SCALARPRODUCT_DOUBLE 0
+cglobal scalarproduct_double, 3,3,8, v1, v2, offset
+    shl offsetq, 3
+    add     v1q, offsetq
+    add     v2q, offsetq
+    neg offsetq
+    xorpd    m0, m0
+    xorpd    m1, m1
+    movapd   m2, m0
+    movapd   m3, m1
+align 16
+.loop:
+    movapd   m4, [v1q+offsetq+mmsize*0]
+    movapd   m5, [v1q+offsetq+mmsize*1]
+    movapd   m6, [v1q+offsetq+mmsize*2]
+    movapd   m7, [v1q+offsetq+mmsize*3]
+    mulpd    m4, [v2q+offsetq+mmsize*0]
+    mulpd    m5, [v2q+offsetq+mmsize*1]
+    mulpd    m6, [v2q+offsetq+mmsize*2]
+    mulpd    m7, [v2q+offsetq+mmsize*3]
+    addpd    m0, m4
+    addpd    m1, m5
+    addpd    m2, m6
+    addpd    m3, m7
+    add offsetq, mmsize*4
+    jl .loop
+    addpd    m0, m1
+    addpd    m2, m3
+    addpd    m0, m2
+%if mmsize == 32
+    vextractf128 xm1, m0, 1
+    addpd   xm0, xm1
+%endif
+    movhlps xm1, xm0
+    addsd   xm0, xm1
+%if ARCH_X86_64 == 0
+    movsd   r0m, xm0
+    fld qword r0m
+%endif
+    RET
+%endmacro
+
+INIT_XMM sse2
+SCALARPRODUCT_DOUBLE
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+SCALARPRODUCT_DOUBLE
+%endif
+
+;-----------------------------------------------------------------------------
+; void ff_butterflies_float(float *src0, float *src1, int len);
+;-----------------------------------------------------------------------------
+INIT_XMM sse
+cglobal butterflies_float, 3,3,3, src0, src1, len
+    shl       lend, 2
+    add      src0q, lenq
+    add      src1q, lenq
+    neg       lenq
+.loop:
+    mova        m0, [src0q + lenq]
+    mova        m1, [src1q + lenq]
+    subps       m2, m0, m1
+    addps       m0, m0, m1
+    mova        [src1q + lenq], m2
+    mova        [src0q + lenq], m0
+    add       lenq, mmsize
+    jl .loop
+    RET
diff --git a/libs/ffmpeg/libavutil/x86/float_dsp_init.c b/libs/ffmpeg/libavutil/x86/float_dsp_init.c
new file mode 100644
index 000000000000..335f7b5e760c
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/float_dsp_init.c
@@ -0,0 +1,124 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/float_dsp.h"
+#include "cpu.h"
+
+void ff_vector_fmul_sse(float *dst, const float *src0, const float *src1,
+                        int len);
+void ff_vector_fmul_avx(float *dst, const float *src0, const float *src1,
+                        int len);
+
+void ff_vector_dmul_sse2(double *dst, const double *src0, const double *src1,
+                         int len);
+void ff_vector_dmul_avx(double *dst, const double *src0, const double *src1,
+                        int len);
+
+void ff_vector_fmac_scalar_sse(float *dst, const float *src, float mul,
+                               int len);
+void ff_vector_fmac_scalar_avx(float *dst, const float *src, float mul,
+                               int len);
+void ff_vector_fmac_scalar_fma3(float *dst, const float *src, float mul,
+                                int len);
+
+void ff_vector_fmul_scalar_sse(float *dst, const float *src, float mul,
+                               int len);
+
+void ff_vector_dmac_scalar_sse2(double *dst, const double *src, double mul,
+                                int len);
+void ff_vector_dmac_scalar_avx(double *dst, const double *src, double mul,
+                               int len);
+void ff_vector_dmac_scalar_fma3(double *dst, const double *src, double mul,
+                                int len);
+
+void ff_vector_dmul_scalar_sse2(double *dst, const double *src,
+                                double mul, int len);
+void ff_vector_dmul_scalar_avx(double *dst, const double *src,
+                               double mul, int len);
+
+void ff_vector_fmul_window_sse(float *dst, const float *src0,
+                               const float *src1, const float *win, int len);
+
+void ff_vector_fmul_add_sse(float *dst, const float *src0, const float *src1,
+                            const float *src2, int len);
+void ff_vector_fmul_add_avx(float *dst, const float *src0, const float *src1,
+                            const float *src2, int len);
+void ff_vector_fmul_add_fma3(float *dst, const float *src0, const float *src1,
+                             const float *src2, int len);
+
+void ff_vector_fmul_reverse_sse(float *dst, const float *src0,
+                                const float *src1, int len);
+void ff_vector_fmul_reverse_avx(float *dst, const float *src0,
+                                const float *src1, int len);
+void ff_vector_fmul_reverse_avx2(float *dst, const float *src0,
+                                 const float *src1, int len);
+
+float ff_scalarproduct_float_sse(const float *v1, const float *v2, int order);
+float ff_scalarproduct_float_fma3(const float *v1, const float *v2, int order);
+
+double ff_scalarproduct_double_sse2(const double *v1, const double *v2, size_t order);
+double ff_scalarproduct_double_avx(const double *v1, const double *v2, size_t order);
+
+void ff_butterflies_float_sse(float *restrict src0, float *restrict src1, int len);
+
+av_cold void ff_float_dsp_init_x86(AVFloatDSPContext *fdsp)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (EXTERNAL_SSE(cpu_flags)) {
+        fdsp->vector_fmul = ff_vector_fmul_sse;
+        fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_sse;
+        fdsp->vector_fmul_scalar = ff_vector_fmul_scalar_sse;
+        fdsp->vector_fmul_window = ff_vector_fmul_window_sse;
+        fdsp->vector_fmul_add    = ff_vector_fmul_add_sse;
+        fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_sse;
+        fdsp->scalarproduct_float = ff_scalarproduct_float_sse;
+        fdsp->butterflies_float   = ff_butterflies_float_sse;
+    }
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        fdsp->vector_dmul = ff_vector_dmul_sse2;
+        fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_sse2;
+        fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_sse2;
+        fdsp->scalarproduct_double = ff_scalarproduct_double_sse2;
+    }
+    if (EXTERNAL_AVX_FAST(cpu_flags)) {
+        fdsp->vector_fmul = ff_vector_fmul_avx;
+        fdsp->vector_dmul = ff_vector_dmul_avx;
+        fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_avx;
+        fdsp->vector_dmul_scalar = ff_vector_dmul_scalar_avx;
+        fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_avx;
+        fdsp->vector_fmul_add    = ff_vector_fmul_add_avx;
+        fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx;
+        fdsp->scalarproduct_double = ff_scalarproduct_double_avx;
+    }
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_avx2;
+    }
+    if (EXTERNAL_FMA3_FAST(cpu_flags)) {
+        fdsp->vector_fmac_scalar = ff_vector_fmac_scalar_fma3;
+        fdsp->vector_fmul_add    = ff_vector_fmul_add_fma3;
+        fdsp->vector_dmac_scalar = ff_vector_dmac_scalar_fma3;
+        fdsp->scalarproduct_float = ff_scalarproduct_float_fma3;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/imgutils.asm b/libs/ffmpeg/libavutil/x86/imgutils.asm
new file mode 100644
index 000000000000..3cca56cdca84
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/imgutils.asm
@@ -0,0 +1,53 @@
+;*****************************************************************************
+;* Copyright 2016 Anton Khirnov
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General 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/x86/x86util.asm"
+
+SECTION .text
+
+INIT_XMM sse4
+cglobal image_copy_plane_uc_from, 6, 7, 4, dst, dst_linesize, src, src_linesize, bw, height, rowpos
+    add dstq, bwq
+    add srcq, bwq
+    neg bwq
+
+.row_start:
+    mov rowposq, bwq
+
+.loop:
+    movntdqa m0, [srcq + rowposq + 0 * mmsize]
+    movntdqa m1, [srcq + rowposq + 1 * mmsize]
+    movntdqa m2, [srcq + rowposq + 2 * mmsize]
+    movntdqa m3, [srcq + rowposq + 3 * mmsize]
+
+    mova [dstq + rowposq + 0 * mmsize], m0
+    mova [dstq + rowposq + 1 * mmsize], m1
+    mova [dstq + rowposq + 2 * mmsize], m2
+    mova [dstq + rowposq + 3 * mmsize], m3
+
+    add rowposq, 4 * mmsize
+    jnz .loop
+
+    add srcq, src_linesizeq
+    add dstq, dst_linesizeq
+    dec heightd
+    jnz .row_start
+
+    RET
diff --git a/libs/ffmpeg/libavutil/x86/imgutils_init.c b/libs/ffmpeg/libavutil/x86/imgutils_init.c
new file mode 100644
index 000000000000..952d325566a9
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/imgutils_init.c
@@ -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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "libavutil/cpu.h"
+#include "libavutil/error.h"
+#include "libavutil/imgutils_internal.h"
+#include "libavutil/macros.h"
+
+#include "cpu.h"
+
+void ff_image_copy_plane_uc_from_sse4(uint8_t *dst, ptrdiff_t dst_linesize,
+                                      const uint8_t *src, ptrdiff_t src_linesize,
+                                      ptrdiff_t bytewidth, int height);
+
+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)
+{
+    int cpu_flags = av_get_cpu_flags();
+    ptrdiff_t bw_aligned = FFALIGN(bytewidth, 64);
+
+    if (EXTERNAL_SSE4(cpu_flags) &&
+        bw_aligned <= dst_linesize && bw_aligned <= src_linesize)
+        ff_image_copy_plane_uc_from_sse4(dst, dst_linesize, src, src_linesize,
+                                         bw_aligned, height);
+    else
+        return AVERROR(ENOSYS);
+
+    return 0;
+}
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/intmath.h b/libs/ffmpeg/libavutil/x86/intmath.h
new file mode 100644
index 000000000000..d8d1f19b243d
--- /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 000000000000..c92b75ed1249
--- /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/lls.asm b/libs/ffmpeg/libavutil/x86/lls.asm
new file mode 100644
index 000000000000..e8141e6c4ffa
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/lls.asm
@@ -0,0 +1,290 @@
+;******************************************************************************
+;* linear least squares model
+;*
+;* Copyright (c) 2013 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 "libavutil/x86/x86util.asm"
+
+SECTION .text
+
+%define MAX_VARS 32
+%define MAX_VARS_ALIGN (MAX_VARS+4)
+%define COVAR_STRIDE MAX_VARS_ALIGN*8
+%define COVAR(x,y) [covarq + (x)*8 + (y)*COVAR_STRIDE]
+
+struc LLSModel
+    .covariance:  resq MAX_VARS_ALIGN*MAX_VARS_ALIGN
+    .coeff:       resq MAX_VARS*MAX_VARS
+    .variance:    resq MAX_VARS
+    .indep_count: resd 1
+endstruc
+
+%macro ADDPD_MEM 2
+%if cpuflag(avx)
+    vaddpd %2, %2, %1
+%else
+    addpd  %2, %1
+%endif
+    mova   %1, %2
+%endmacro
+
+INIT_XMM sse2
+%define movdqa movaps
+cglobal update_lls, 2,5,8, ctx, var, i, j, covar2
+    %define covarq ctxq
+    mov     id, [ctxq + LLSModel.indep_count]
+    lea   varq, [varq + iq*8]
+    neg     iq
+    mov covar2q, covarq
+.loopi:
+    ; Compute all 3 pairwise products of a 2x2 block that lies on the diagonal
+    mova    m1, [varq + iq*8]
+    mova    m3, [varq + iq*8 + 16]
+    pshufd  m4, m1, q1010
+    pshufd  m5, m1, q3232
+    pshufd  m6, m3, q1010
+    pshufd  m7, m3, q3232
+    mulpd   m0, m1, m4
+    mulpd   m1, m1, m5
+    lea covarq, [covar2q + 16]
+    ADDPD_MEM COVAR(-2,0), m0
+    ADDPD_MEM COVAR(-2,1), m1
+    lea     jq, [iq + 2]
+    cmp     jd, -2
+    jg .skip4x4
+.loop4x4:
+    ; Compute all 16 pairwise products of a 4x4 block
+    mulpd   m0, m4, m3
+    mulpd   m1, m5, m3
+    mulpd   m2, m6, m3
+    mulpd   m3, m3, m7
+    ADDPD_MEM COVAR(0,0), m0
+    ADDPD_MEM COVAR(0,1), m1
+    ADDPD_MEM COVAR(0,2), m2
+    ADDPD_MEM COVAR(0,3), m3
+    mova    m3, [varq + jq*8 + 16]
+    mulpd   m0, m4, m3
+    mulpd   m1, m5, m3
+    mulpd   m2, m6, m3
+    mulpd   m3, m3, m7
+    ADDPD_MEM COVAR(2,0), m0
+    ADDPD_MEM COVAR(2,1), m1
+    ADDPD_MEM COVAR(2,2), m2
+    ADDPD_MEM COVAR(2,3), m3
+    mova    m3, [varq + jq*8 + 32]
+    add covarq, 32
+    add     jq, 4
+    cmp     jd, -2
+    jle .loop4x4
+.skip4x4:
+    test    jd, jd
+    jg .skip2x4
+    mulpd   m4, m3
+    mulpd   m5, m3
+    mulpd   m6, m3
+    mulpd   m7, m3
+    ADDPD_MEM COVAR(0,0), m4
+    ADDPD_MEM COVAR(0,1), m5
+    ADDPD_MEM COVAR(0,2), m6
+    ADDPD_MEM COVAR(0,3), m7
+.skip2x4:
+    add     iq, 4
+    add covar2q, 4*COVAR_STRIDE+32
+    cmp     id, -2
+    jle .loopi
+    test    id, id
+    jg .ret
+    mov     jq, iq
+    %define covarq covar2q
+.loop2x1:
+    movsd   m0, [varq + iq*8]
+    movlhps m0, m0
+    mulpd   m0, [varq + jq*8]
+    ADDPD_MEM COVAR(0,0), m0
+    inc     iq
+    add covarq, COVAR_STRIDE
+    test    id, id
+    jle .loop2x1
+.ret:
+    RET
+
+%macro UPDATE_LLS 0
+cglobal update_lls, 3,6,8, ctx, var, count, i, j, count2
+    %define covarq ctxq
+    mov  countd, [ctxq + LLSModel.indep_count]
+    lea count2d, [countq-2]
+    xor     id, id
+.loopi:
+    ; Compute all 10 pairwise products of a 4x4 block that lies on the diagonal
+    mova    ymm1, [varq + iq*8]
+    vbroadcastsd ymm4, [varq + iq*8]
+    vbroadcastsd ymm5, [varq + iq*8 + 8]
+    vbroadcastsd ymm6, [varq + iq*8 + 16]
+    vbroadcastsd ymm7, [varq + iq*8 + 24]
+    vextractf128 xmm3, ymm1, 1
+%if cpuflag(fma3)
+    mova ymm0, COVAR(iq  ,0)
+    mova xmm2, COVAR(iq+2,2)
+    fmaddpd ymm0, ymm1, ymm4, ymm0
+    fmaddpd xmm2, xmm3, xmm6, xmm2
+    fmaddpd ymm1, ymm5, ymm1, COVAR(iq  ,1)
+    fmaddpd xmm3, xmm7, xmm3, COVAR(iq+2,3)
+    mova COVAR(iq  ,0), ymm0
+    mova COVAR(iq  ,1), ymm1
+    mova COVAR(iq+2,2), xmm2
+    mova COVAR(iq+2,3), xmm3
+%else
+    vmulpd  ymm0, ymm1, ymm4
+    vmulpd  ymm1, ymm1, ymm5
+    vmulpd  xmm2, xmm3, xmm6
+    vmulpd  xmm3, xmm3, xmm7
+    ADDPD_MEM COVAR(iq  ,0), ymm0
+    ADDPD_MEM COVAR(iq  ,1), ymm1
+    ADDPD_MEM COVAR(iq+2,2), xmm2
+    ADDPD_MEM COVAR(iq+2,3), xmm3
+%endif ; cpuflag(fma3)
+    lea     jd, [iq + 4]
+    cmp     jd, count2d
+    jg .skip4x4
+.loop4x4:
+    ; Compute all 16 pairwise products of a 4x4 block
+    mova    ymm3, [varq + jq*8]
+%if cpuflag(fma3)
+    mova ymm0, COVAR(jq, 0)
+    mova ymm1, COVAR(jq, 1)
+    mova ymm2, COVAR(jq, 2)
+    fmaddpd ymm0, ymm3, ymm4, ymm0
+    fmaddpd ymm1, ymm3, ymm5, ymm1
+    fmaddpd ymm2, ymm3, ymm6, ymm2
+    fmaddpd ymm3, ymm7, ymm3, COVAR(jq,3)
+    mova COVAR(jq, 0), ymm0
+    mova COVAR(jq, 1), ymm1
+    mova COVAR(jq, 2), ymm2
+    mova COVAR(jq, 3), ymm3
+%else
+    vmulpd  ymm0, ymm3, ymm4
+    vmulpd  ymm1, ymm3, ymm5
+    vmulpd  ymm2, ymm3, ymm6
+    vmulpd  ymm3, ymm3, ymm7
+    ADDPD_MEM COVAR(jq,0), ymm0
+    ADDPD_MEM COVAR(jq,1), ymm1
+    ADDPD_MEM COVAR(jq,2), ymm2
+    ADDPD_MEM COVAR(jq,3), ymm3
+%endif ; cpuflag(fma3)
+    add     jd, 4
+    cmp     jd, count2d
+    jle .loop4x4
+.skip4x4:
+    cmp     jd, countd
+    jg .skip2x4
+    mova    xmm3, [varq + jq*8]
+%if cpuflag(fma3)
+    mova xmm0, COVAR(jq, 0)
+    mova xmm1, COVAR(jq, 1)
+    mova xmm2, COVAR(jq, 2)
+    fmaddpd xmm0, xmm3, xmm4, xmm0
+    fmaddpd xmm1, xmm3, xmm5, xmm1
+    fmaddpd xmm2, xmm3, xmm6, xmm2
+    fmaddpd xmm3, xmm7, xmm3, COVAR(jq,3)
+    mova COVAR(jq, 0), xmm0
+    mova COVAR(jq, 1), xmm1
+    mova COVAR(jq, 2), xmm2
+    mova COVAR(jq, 3), xmm3
+%else
+    vmulpd  xmm0, xmm3, xmm4
+    vmulpd  xmm1, xmm3, xmm5
+    vmulpd  xmm2, xmm3, xmm6
+    vmulpd  xmm3, xmm3, xmm7
+    ADDPD_MEM COVAR(jq,0), xmm0
+    ADDPD_MEM COVAR(jq,1), xmm1
+    ADDPD_MEM COVAR(jq,2), xmm2
+    ADDPD_MEM COVAR(jq,3), xmm3
+%endif ; cpuflag(fma3)
+.skip2x4:
+    add     id, 4
+    add covarq, 4*COVAR_STRIDE
+    cmp     id, count2d
+    jle .loopi
+    cmp     id, countd
+    jg .ret
+    mov     jd, id
+.loop2x1:
+    vmovddup xmm0, [varq + iq*8]
+%if cpuflag(fma3)
+    mova xmm1, [varq + jq*8]
+    fmaddpd xmm0, xmm1, xmm0, COVAR(jq,0)
+    mova COVAR(jq,0), xmm0
+%else
+    vmulpd   xmm0, [varq + jq*8]
+    ADDPD_MEM COVAR(jq,0), xmm0
+%endif ; cpuflag(fma3)
+    inc     id
+    add covarq, COVAR_STRIDE
+    cmp     id, countd
+    jle .loop2x1
+.ret:
+    RET
+%endmacro ; UPDATE_LLS
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+UPDATE_LLS
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+UPDATE_LLS
+%endif
+
+INIT_XMM sse2
+cglobal evaluate_lls, 3,4,2, ctx, var, order, i
+    ; This function is often called on the same buffer as update_lls, but with
+    ; an offset. They can't both be aligned.
+    ; Load halves rather than movu to avoid store-forwarding stalls, since the
+    ; input was initialized immediately prior to this function using scalar math.
+    %define coefsq ctxq
+    mov     id, orderd
+    imul    orderd, MAX_VARS
+    lea     coefsq, [ctxq + LLSModel.coeff + orderq*8]
+    movsd   m0, [varq]
+    movhpd  m0, [varq + 8]
+    mulpd   m0, [coefsq]
+    lea coefsq, [coefsq + iq*8]
+    lea   varq, [varq + iq*8]
+    neg     iq
+    add     iq, 2
+.loop:
+    movsd   m1, [varq + iq*8]
+    movhpd  m1, [varq + iq*8 + 8]
+    mulpd   m1, [coefsq + iq*8]
+    addpd   m0, m1
+    add     iq, 2
+    jl .loop
+    jg .skip1
+    movsd   m1, [varq + iq*8]
+    mulsd   m1, [coefsq + iq*8]
+    addpd   m0, m1
+.skip1:
+    movhlps m1, m0
+    addsd   m0, m1
+%if ARCH_X86_32
+    movsd  r0m, m0
+    fld   qword r0m
+%endif
+    RET
diff --git a/libs/ffmpeg/libavutil/x86/lls_init.c b/libs/ffmpeg/libavutil/x86/lls_init.c
new file mode 100644
index 000000000000..83d6377c2b4b
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/lls_init.c
@@ -0,0 +1,50 @@
+/*
+ * linear least squares model
+ *
+ * Copyright (c) 2013 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/lls.h"
+#include "libavutil/x86/cpu.h"
+
+void ff_update_lls_sse2(LLSModel *m, const double *var);
+void ff_update_lls_avx(LLSModel *m, const double *var);
+void ff_update_lls_fma3(LLSModel *m, const double *var);
+double ff_evaluate_lls_sse2(LLSModel *m, const double *var, int order);
+
+av_cold void ff_init_lls_x86(LLSModel *m)
+{
+    int cpu_flags = av_get_cpu_flags();
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        m->update_lls = ff_update_lls_sse2;
+        if (m->indep_count >= 4)
+            m->evaluate_lls = ff_evaluate_lls_sse2;
+    }
+    if (EXTERNAL_AVX_FAST(cpu_flags)) {
+        m->update_lls = ff_update_lls_avx;
+    }
+    if (EXTERNAL_FMA3_FAST(cpu_flags)) {
+        m->update_lls = ff_update_lls_fma3;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/timer.h b/libs/ffmpeg/libavutil/x86/timer.h
new file mode 100644
index 000000000000..4d1e88def0de
--- /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/x86/tx_float.asm b/libs/ffmpeg/libavutil/x86/tx_float.asm
new file mode 100644
index 000000000000..87be21c2d629
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/tx_float.asm
@@ -0,0 +1,1934 @@
+;******************************************************************************
+;* Copyright (c) Lynne
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General Public
+;* License along with FFmpeg; if not, write to the Free Software
+;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;******************************************************************************
+
+; Open `doc/transforms.md` to see the code upon which the transforms here were
+; based upon and compare.
+
+; Intra-asm call convention:
+;       320 bytes of stack available
+;       14 GPRs available (last 4 must not be clobbered)
+;       Additionally, don't clobber ctx, in, out, stride, len, lut
+;       All vector regs available
+
+; TODO:
+;       carry over registers from smaller transforms to save on ~8 loads/stores
+;       check if vinsertf could be faster than verpm2f128 for duplication
+;       even faster FFT8 (current one is very #instructions optimized)
+;       replace some xors with blends + addsubs?
+;       replace some shuffles with vblends?
+;       avx512 split-radix
+
+%include "libavutil/x86/x86util.asm"
+
+%define private_prefix ff_tx
+
+%if ARCH_X86_64
+%define ptr resq
+%else
+%define ptr resd
+%endif
+
+%assign i 16
+%rep 14
+cextern tab_ %+ i %+ _float ; ff_tab_i_float...
+%assign i (i << 1)
+%endrep
+
+cextern tab_53_float
+
+struc AVTXContext
+    .len:          resd 1 ; Length
+    .inv           resd 1 ; Inverse flag
+    .map:           ptr 1 ; Lookup table(s)
+    .exp:           ptr 1 ; Exponentiation factors
+    .tmp:           ptr 1 ; Temporary data
+
+    .sub:           ptr 1 ; Subcontexts
+    .fn:            ptr 4 ; Subcontext functions
+    .nb_sub:       resd 1 ; Subcontext count
+
+    ; Everything else is inaccessible
+endstruc
+
+SECTION_RODATA 32
+
+%define POS 0x00000000
+%define NEG 0x80000000
+
+%define M_SQRT1_2 0.707106781186547524401
+%define COS16_1   0.92387950420379638671875
+%define COS16_3   0.3826834261417388916015625
+
+d8_mult_odd:   dd M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, \
+                  M_SQRT1_2, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2
+
+s8_mult_odd:   dd 1.0, 1.0, -1.0, 1.0, -M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2, M_SQRT1_2
+s8_perm_even:  dd 1, 3, 0, 2, 1, 3, 2, 0
+s8_perm_odd1:  dd 3, 3, 1, 1, 1, 1, 3, 3
+s8_perm_odd2:  dd 1, 2, 0, 3, 1, 0, 0, 1
+
+s16_mult_even: dd 1.0, 1.0, M_SQRT1_2, M_SQRT1_2, 1.0, -1.0, M_SQRT1_2, -M_SQRT1_2
+s16_mult_odd1: dd COS16_1,  COS16_1,  COS16_3,  COS16_3,  COS16_1, -COS16_1,  COS16_3, -COS16_3
+s16_mult_odd2: dd COS16_3, -COS16_3,  COS16_1, -COS16_1, -COS16_3, -COS16_3, -COS16_1, -COS16_1
+s16_perm:      dd 0, 1, 2, 3, 1, 0, 3, 2
+
+s15_perm:      dd 0, 6, 5, 3, 2, 4, 7, 1
+
+mask_mmppmmmm: dd NEG, NEG, POS, POS, NEG, NEG, NEG, NEG
+mask_mmmmpppm: dd NEG, NEG, NEG, NEG, POS, POS, POS, NEG
+mask_ppmpmmpm: dd POS, POS, NEG, POS, NEG, NEG, POS, NEG
+mask_mppmmpmp: dd NEG, POS, POS, NEG, NEG, POS, NEG, POS
+mask_mpmppmpm: dd NEG, POS, NEG, POS, POS, NEG, POS, NEG
+mask_pmmppmmp: dd POS, NEG, NEG, POS, POS, NEG, NEG, POS
+mask_pmpmpmpm: times 4 dd POS, NEG
+
+SECTION .text
+
+; Load complex values (64 bits) via a lookup table
+; %1 - output register
+; %2 - GRP of base input memory address
+; %3 - GPR of LUT (int32_t indices) address
+; %4 - LUT offset
+; %5 - temporary GPR (only used if vgather is not used)
+; %6 - temporary register (for avx only)
+; %7 - temporary register (for avx only, enables vgatherdpd (AVX2) if FMA3 is set)
+%macro LOAD64_LUT 5-7
+%if %0 > 6 && cpuflag(avx2)
+    pcmpeqd %7, %7 ; pcmpeqq has a 0.5 throughput on Zen 3, this has 0.25
+    movupd xmm%6, [%3 + %4] ; float mov since vgatherdpd is a float instruction
+    vgatherdpd %1, [%2 + xmm%6*8], %7 ; must use separate registers for args
+%else
+    mov      %5d, [%3 + %4 + 0]
+    movsd  xmm%1, [%2 + %5q*8]
+%if sizeof%1 > 16 && %0 > 5
+    mov      %5d, [%3 + %4 + 8]
+    movsd  xmm%6, [%2 + %5q*8]
+%endif
+    mov      %5d, [%3 + %4 + 4]
+    movhps xmm%1, [%2 + %5q*8]
+%if sizeof%1 > 16 && %0 > 5
+    mov      %5d, [%3 + %4 + 12]
+    movhps xmm%6, [%2 + %5q*8]
+    vinsertf128 %1, %1, xmm%6, 1
+%endif
+%endif
+%endmacro
+
+; Single 2-point in-place complex FFT (will do 2 transforms at once in AVX mode)
+; %1 - coefficients (r0.reim, r1.reim)
+; %2 - temporary
+%macro FFT2 2
+    shufps   %2, %1, %1, q3322
+    shufps   %1, %1, %1, q1100
+
+    addsubps %1, %1, %2
+
+    shufps   %1, %1, %1, q2031
+%endmacro
+
+; Single 4-point in-place complex FFT (will do 2 transforms at once in [AVX] mode)
+; %1 - even coefficients (r0.reim, r2.reim, r4.reim, r6.reim)
+; %2 - odd coefficients  (r1.reim, r3.reim, r5.reim, r7.reim)
+; %3 - temporary
+%macro FFT4 3
+    subps  %3, %1, %2         ;  r1234, [r5678]
+    addps  %1, %1, %2         ;  t1234, [t5678]
+
+    shufps %2, %1, %3, q1010  ;  t12, r12
+    shufps %1, %1, %3, q2332  ;  t34, r43
+
+    subps  %3, %2, %1         ;  a34, b32
+    addps  %2, %2, %1         ;  a12, b14
+
+    shufps %1, %2, %3, q1010  ;  a1234     even
+
+    shufps %2, %2, %3, q2332  ;  b1423
+    shufps %2, %2, %2, q1320  ;  b1234     odd
+%endmacro
+
+; Single/Dual 8-point in-place complex FFT (will do 2 transforms in [AVX] mode)
+; %1 - even coefficients (a0.reim, a2.reim, [b0.reim, b2.reim])
+; %2 - even coefficients (a4.reim, a6.reim, [b4.reim, b6.reim])
+; %3 - odd coefficients  (a1.reim, a3.reim, [b1.reim, b3.reim])
+; %4 - odd coefficients  (a5.reim, a7.reim, [b5.reim, b7.reim])
+; %5 - temporary
+; %6 - temporary
+%macro FFT8 6
+    addps    %5, %1, %3               ; q1-8
+    addps    %6, %2, %4               ; k1-8
+
+    subps    %1, %1, %3               ; r1-8
+    subps    %2, %2, %4               ; j1-8
+
+    shufps   %4, %1, %1, q2323        ; r4343
+    shufps   %3, %5, %6, q3032        ; q34, k14
+
+    shufps   %1, %1, %1, q1010        ; r1212
+    shufps   %5, %5, %6, q1210        ; q12, k32
+
+    xorps    %4, %4, [mask_pmmppmmp]  ; r4343 * pmmp
+    addps    %6, %5, %3               ; s12, g12
+
+    mulps    %2, %2, [d8_mult_odd]    ; r8 * d8_mult_odd
+    subps    %5, %5, %3               ; s34, g43
+
+    addps    %3, %1, %4               ; z1234
+    unpcklpd %1, %6, %5               ; s1234
+
+    shufps   %4, %2, %2, q2301        ; j2143
+    shufps   %6, %6, %5, q2332        ; g1234
+
+    addsubps %2, %2, %4               ; l2143
+    shufps   %5, %2, %2, q0123        ; l3412
+    addsubps %5, %5, %2               ; t1234
+
+    subps    %2, %1, %6               ; h1234 even
+    subps    %4, %3, %5               ; u1234 odd
+
+    addps    %1, %1, %6               ; w1234 even
+    addps    %3, %3, %5               ; o1234 odd
+%endmacro
+
+; Single 8-point in-place complex FFT in 20 instructions
+; %1 - even coefficients (r0.reim, r2.reim, r4.reim, r6.reim)
+; %2 - odd coefficients  (r1.reim, r3.reim, r5.reim, r7.reim)
+; %3 - temporary
+; %4 - temporary
+%macro FFT8_AVX 4
+    subps      %3, %1, %2               ;  r1234, r5678
+    addps      %1, %1, %2               ;  q1234, q5678
+
+    vpermilps  %2, %3, [s8_perm_odd1]   ;  r4422, r6688
+    shufps     %4, %1, %1, q3322        ;  q1122, q5566
+
+    movsldup   %3, %3                   ;  r1133, r5577
+    shufps     %1, %1, %1, q1100        ;  q3344, q7788
+
+    addsubps   %3, %3, %2               ;  z1234, z5678
+    addsubps   %1, %1, %4               ;  s3142, s7586
+
+    mulps      %3, %3, [s8_mult_odd]    ;  z * s8_mult_odd
+    vpermilps  %1, %1, [s8_perm_even]   ;  s1234, s5687 !
+
+    shufps     %2, %3, %3, q2332        ;   junk, z7887
+    xorps      %4, %1, [mask_mmmmpppm]  ;  e1234, e5687 !
+
+    vpermilps  %3, %3, [s8_perm_odd2]   ;  z2314, z6556
+    vperm2f128 %1, %1, %4, 0x03         ;  e5687, s1234
+
+    addsubps   %2, %2, %3               ;   junk, t5678
+    subps      %1, %1, %4               ;  w1234, w5678 even
+
+    vperm2f128 %2, %2, %2, 0x11         ;  t5678, t5678
+    vperm2f128 %3, %3, %3, 0x00         ;  z2314, z2314
+
+    xorps      %2, %2, [mask_ppmpmmpm]  ;  t * ppmpmmpm
+    addps      %2, %3, %2               ;  u1234, u5678 odd
+%endmacro
+
+; Single 16-point in-place complex FFT
+; %1 - even coefficients (r0.reim, r2.reim,  r4.reim,  r6.reim)
+; %2 - even coefficients (r8.reim, r10.reim, r12.reim, r14.reim)
+; %3 - odd coefficients  (r1.reim, r3.reim,  r5.reim,  r7.reim)
+; %4 - odd coefficients  (r9.reim, r11.reim, r13.reim, r15.reim)
+; %5, %6 - temporary
+; %7, %8 - temporary (optional)
+%macro FFT16 6-8
+    FFT4       %3, %4, %5
+%if %0 > 7
+    FFT8_AVX   %1, %2, %6, %7
+    movaps     %8, [mask_mpmppmpm]
+    movaps     %7, [s16_perm]
+%define mask %8
+%define perm %7
+%elif %0 > 6
+    FFT8_AVX   %1, %2, %6, %7
+    movaps     %7, [s16_perm]
+%define mask [mask_mpmppmpm]
+%define perm %7
+%else
+    FFT8_AVX   %1, %2, %6, %5
+%define mask [mask_mpmppmpm]
+%define perm [s16_perm]
+%endif
+    xorps      %5, %5, %5                   ; 0
+
+    shufps     %6, %4, %4, q2301            ; z12.imre, z13.imre...
+    shufps     %5, %5, %3, q2301            ; 0, 0, z8.imre...
+
+    mulps      %4, %4, [s16_mult_odd1]      ; z.reim * costab
+    xorps      %5, %5, [mask_mppmmpmp]
+%if cpuflag(fma3)
+    fmaddps    %6, %6, [s16_mult_odd2], %4  ; s[8..15]
+    addps      %5, %3, %5                   ; s[0...7]
+%else
+    mulps      %6, %6, [s16_mult_odd2]      ; z.imre * costab
+
+    addps      %5, %3, %5                   ; s[0...7]
+    addps      %6, %4, %6                   ; s[8..15]
+%endif
+    mulps      %5, %5, [s16_mult_even]      ; s[0...7]*costab
+
+    xorps      %4, %6, mask                 ; s[8..15]*mpmppmpm
+    xorps      %3, %5, mask                 ; s[0...7]*mpmppmpm
+
+    vperm2f128 %4, %4, %4, 0x01             ; s[12..15, 8..11]
+    vperm2f128 %3, %3, %3, 0x01             ; s[4..7, 0..3]
+
+    addps      %6, %6, %4                   ; y56, u56, y34, u34
+    addps      %5, %5, %3                   ; w56, x56, w34, x34
+
+    vpermilps  %6, %6, perm                 ; y56, u56, y43, u43
+    vpermilps  %5, %5, perm                 ; w56, x56, w43, x43
+
+    subps      %4, %2, %6                   ; odd  part 2
+    addps      %3, %2, %6                   ; odd  part 1
+
+    subps      %2, %1, %5                   ; even part 2
+    addps      %1, %1, %5                   ; even part 1
+%undef mask
+%undef perm
+%endmacro
+
+; Single 15-point complex FFT
+; Input:
+; xm0 must contain in[0,1].reim
+; m2 - in[3-6].reim
+; m3 - in[7-11].reim
+; m4 - in[12-15].reim
+; xm5 must contain in[2].reimreim
+;
+; Output:
+; m0, m1, m2 - ACs
+; xm14 - out[0]
+; xm15 - out[10, 5]
+%macro FFT15 0
+    shufps xm1, xm0, xm0, q3223      ; in[1].imrereim
+    shufps xm0, xm0, xm0, q1001      ; in[0].imrereim
+
+    xorps xm1, xm11
+    addps xm1, xm0                   ; pc[0,1].imre
+
+    shufps xm0, xm1, xm1, q3232      ; pc[1].reimreim
+    addps xm0, xm5                   ; dc[0].reimreim
+
+    mulps xm1, xm9                   ; tab[0123]*pc[01]
+
+    shufpd xm6, xm1, xm1, 01b        ; pc[1,0].reim
+    xorps xm1, xm11
+    addps xm1, xm1, xm6
+    addsubps xm1, xm5, xm1           ; dc[1,2].reim
+
+    subps m7, m2, m3                 ; q[0-3].imre
+    addps m6, m2, m3                 ; q[4-7]
+    shufps m7, m7, m7, q2301         ; q[0-3].reim
+
+    addps m5, m4, m6                 ; y[0-3]
+
+    vperm2f128 m14, m9, m9, 0x11     ; tab[23232323]
+    vbroadcastsd m15, xm9            ; tab[01010101]
+
+    mulps m6, m14
+    mulps m7, m15
+
+    subps m2, m6, m7                 ; k[0-3]
+    addps m3, m6, m7                 ; k[4-7]
+
+    shufps m12, m11, m11, q3232      ; ppppmmmm
+
+    addsubps m6, m4, m2              ; k[0-3]
+    addsubps m7, m4, m3              ; k[4-7]
+
+    ; 15pt from here on
+    vpermpd m2, m5, q0123            ; y[3-0]
+    vpermpd m3, m6, q0123            ; k[3-0]
+    vpermpd m4, m7, q0123            ; k[7-4]
+
+    xorps m5, m12
+    xorps m6, m12
+    xorps m7, m12
+
+    addps m2, m5                     ; t[0-3]
+    addps m3, m6                     ; t[4-7]
+    addps m4, m7                     ; t[8-11]
+
+    movlhps xm14, xm2                ; out[0]
+    unpcklpd xm15, xm3, xm4          ; out[10,5]
+    unpckhpd xm5, xm3, xm4           ; out[10,5]
+
+    addps xm14, xm2                  ; out[0]
+    addps xm15, xm5                  ; out[10,5]
+    addps xm14, xm0                  ; out[0]
+    addps xm15, xm1                  ; out[10,5]
+
+    shufps m12, m10, m10, q3232      ; tab5 4 5 4 5  8  9  8  9
+    shufps m13, m10, m10, q1010      ; tab5 6 7 6 7 10 11 10 11
+
+    mulps m5, m2, m12                ; t[0-3]
+    mulps m6, m3, m12                ; t[4-7]
+    mulps m7, m4, m12                ; t[8-11]
+
+    mulps m2, m13                    ; r[0-3]
+    mulps m3, m13                    ; r[4-7]
+    mulps m4, m13                    ; r[8-11]
+
+    shufps m5, m5, m5, q1032         ; t[1,0,3,2].reim
+    shufps m6, m6, m6, q1032         ; t[5,4,7,6].reim
+    shufps m7, m7, m7, q1032         ; t[9,8,11,10].reim
+
+    vperm2f128 m13, m11, m11, 0x01   ; mmmmmmpp
+    shufps m12, m11, m11, q3232      ; ppppmmmm
+
+    xorps m5, m13
+    xorps m6, m13
+    xorps m7, m13
+
+    addps m2, m5                     ; r[0,1,2,3]
+    addps m3, m6                     ; r[4,5,6,7]
+    addps m4, m7                     ; r[8,9,10,11]
+
+    shufps m5, m2, m2, q2301
+    shufps m6, m3, m3, q2301
+    shufps m7, m4, m4, q2301
+
+    xorps m2, m12
+    xorps m3, m12
+    xorps m4, m12
+
+    vpermpd m5, m5, q0123
+    vpermpd m6, m6, q0123
+    vpermpd m7, m7, q0123
+
+    addps m5, m2
+    addps m6, m3
+    addps m7, m4
+
+    vpermps m5, m8, m5
+    vpermps m6, m8, m6
+    vpermps m7, m8, m7
+
+    vbroadcastsd m0, xm0             ; dc[0]
+    vpermpd m2, m1, q1111            ; dc[2]
+    vbroadcastsd m1, xm1             ; dc[1]
+
+    addps m0, m5
+    addps m1, m6
+    addps m2, m7
+%endmacro
+
+; Cobmines m0...m8 (tx1[even, even, odd, odd], tx2,3[even], tx2,3[odd]) coeffs
+; Uses all 16 of registers.
+; Output is slightly permuted such that tx2,3's coefficients are interleaved
+; on a 2-point basis (look at `doc/transforms.md`)
+%macro SPLIT_RADIX_COMBINE 17
+%if %1 && mmsize == 32
+    vperm2f128 %14, %6, %7, 0x20     ; m2[0], m2[1], m3[0], m3[1] even
+    vperm2f128 %16, %9, %8, 0x20     ; m2[0], m2[1], m3[0], m3[1] odd
+    vperm2f128 %15, %6, %7, 0x31     ; m2[2], m2[3], m3[2], m3[3] even
+    vperm2f128 %17, %9, %8, 0x31     ; m2[2], m2[3], m3[2], m3[3] odd
+%endif
+
+    shufps     %12, %10, %10, q2200  ; cos00224466
+    shufps     %13, %11, %11, q1133  ; wim77553311
+    movshdup   %10, %10              ; cos11335577
+    shufps     %11, %11, %11, q0022  ; wim66442200
+
+%if %1 && mmsize == 32
+    shufps     %6, %14, %14, q2301   ; m2[0].imre, m2[1].imre, m2[2].imre, m2[3].imre even
+    shufps     %8, %16, %16, q2301   ; m2[0].imre, m2[1].imre, m2[2].imre, m2[3].imre odd
+    shufps     %7, %15, %15, q2301   ; m3[0].imre, m3[1].imre, m3[2].imre, m3[3].imre even
+    shufps     %9, %17, %17, q2301   ; m3[0].imre, m3[1].imre, m3[2].imre, m3[3].imre odd
+
+    mulps      %14, %14, %13         ; m2[0123]reim * wim7531 even
+    mulps      %16, %16, %11         ; m2[0123]reim * wim7531 odd
+    mulps      %15, %15, %13         ; m3[0123]reim * wim7531 even
+    mulps      %17, %17, %11         ; m3[0123]reim * wim7531 odd
+%else
+    mulps      %14, %6, %13          ; m2,3[01]reim * wim7531 even
+    mulps      %16, %8, %11          ; m2,3[01]reim * wim7531 odd
+    mulps      %15, %7, %13          ; m2,3[23]reim * wim7531 even
+    mulps      %17, %9, %11          ; m2,3[23]reim * wim7531 odd
+    ; reorder the multiplies to save movs reg, reg in the %if above
+    shufps     %6, %6, %6, q2301     ; m2[0].imre, m2[1].imre, m3[0].imre, m3[1].imre even
+    shufps     %8, %8, %8, q2301     ; m2[0].imre, m2[1].imre, m3[0].imre, m3[1].imre odd
+    shufps     %7, %7, %7, q2301     ; m2[2].imre, m2[3].imre, m3[2].imre, m3[3].imre even
+    shufps     %9, %9, %9, q2301     ; m2[2].imre, m2[3].imre, m3[2].imre, m3[3].imre odd
+%endif
+
+%if cpuflag(fma3) ; 11 - 5 = 6 instructions saved through FMA!
+    fmaddsubps %6, %6, %12, %14      ; w[0..8] even
+    fmaddsubps %8, %8, %10, %16      ; w[0..8] odd
+    fmsubaddps %7, %7, %12, %15      ; j[0..8] even
+    fmsubaddps %9, %9, %10, %17      ; j[0..8] odd
+    movaps     %13, [mask_pmpmpmpm]  ; "subaddps? pfft, who needs that!"
+%else
+    mulps      %6, %6, %12           ; m2,3[01]imre * cos0246
+    mulps      %8, %8, %10           ; m2,3[01]imre * cos0246
+    movaps     %13, [mask_pmpmpmpm]  ; "subaddps? pfft, who needs that!"
+    mulps      %7, %7, %12           ; m2,3[23]reim * cos0246
+    mulps      %9, %9, %10           ; m2,3[23]reim * cos0246
+    addsubps   %6, %6, %14           ; w[0..8]
+    addsubps   %8, %8, %16           ; w[0..8]
+    xorps      %15, %15, %13         ; +-m2,3[23]imre * wim7531
+    xorps      %17, %17, %13         ; +-m2,3[23]imre * wim7531
+    addps      %7, %7, %15           ; j[0..8]
+    addps      %9, %9, %17           ; j[0..8]
+%endif
+
+    addps      %14, %6, %7           ; t10235476 even
+    addps      %16, %8, %9           ; t10235476 odd
+    subps      %15, %6, %7           ; +-r[0..7] even
+    subps      %17, %8, %9           ; +-r[0..7] odd
+
+    shufps     %14, %14, %14, q2301  ; t[0..7] even
+    shufps     %16, %16, %16, q2301  ; t[0..7] odd
+    xorps      %15, %15, %13         ; r[0..7] even
+    xorps      %17, %17, %13         ; r[0..7] odd
+
+    subps      %6, %2, %14           ; m2,3[01] even
+    subps      %8, %4, %16           ; m2,3[01] odd
+    subps      %7, %3, %15           ; m2,3[23] even
+    subps      %9, %5, %17           ; m2,3[23] odd
+
+    addps      %2, %2, %14           ; m0 even
+    addps      %4, %4, %16           ; m0 odd
+    addps      %3, %3, %15           ; m1 even
+    addps      %5, %5, %17           ; m1 odd
+%endmacro
+
+; Same as above, only does one parity at a time, takes 3 temporary registers,
+; however, if the twiddles aren't needed after this, the registers they use
+; can be used as any of the temporary registers.
+%macro SPLIT_RADIX_COMBINE_HALF 10
+%if %1
+    shufps     %8, %6, %6, q2200     ; cos00224466
+    shufps     %9, %7, %7, q1133     ; wim77553311
+%else
+    shufps     %8, %6, %6, q3311     ; cos11335577
+    shufps     %9, %7, %7, q0022     ; wim66442200
+%endif
+
+    mulps      %10, %4, %9           ; m2,3[01]reim * wim7531 even
+    mulps      %9, %9, %5            ; m2,3[23]reim * wim7531 even
+
+    shufps     %4, %4, %4, q2301     ; m2[0].imre, m2[1].imre, m3[0].imre, m3[1].imre even
+    shufps     %5, %5, %5, q2301     ; m2[2].imre, m2[3].imre, m3[2].imre, m3[3].imre even
+
+%if cpuflag(fma3)
+    fmaddsubps %4, %4, %8, %10       ; w[0..8] even
+    fmsubaddps %5, %5, %8, %9        ; j[0..8] even
+    movaps     %10, [mask_pmpmpmpm]
+%else
+    mulps      %4, %4, %8            ; m2,3[01]imre * cos0246
+    mulps      %5, %5, %8            ; m2,3[23]reim * cos0246
+    addsubps   %4, %4, %10           ; w[0..8]
+    movaps     %10, [mask_pmpmpmpm]
+    xorps      %9, %9, %10           ; +-m2,3[23]imre * wim7531
+    addps      %5, %5, %9            ; j[0..8]
+%endif
+
+    addps      %8, %4, %5            ; t10235476
+    subps      %9, %4, %5            ; +-r[0..7]
+
+    shufps     %8, %8, %8, q2301     ; t[0..7]
+    xorps      %9, %9, %10           ; r[0..7]
+
+    subps      %4, %2, %8            ; %3,3[01]
+    subps      %5, %3, %9            ; %3,3[23]
+
+    addps      %2, %2, %8            ; m0
+    addps      %3, %3, %9            ; m1
+%endmacro
+
+; Same as above, tries REALLY hard to use 2 temporary registers.
+%macro SPLIT_RADIX_COMBINE_LITE 9
+%if %1
+    shufps     %8, %6, %6, q2200        ; cos00224466
+    shufps     %9, %7, %7, q1133        ; wim77553311
+%else
+    shufps     %8, %6, %6, q3311        ; cos11335577
+    shufps     %9, %7, %7, q0022        ; wim66442200
+%endif
+
+    mulps      %9, %9, %4               ; m2,3[01]reim * wim7531 even
+    shufps     %4, %4, %4, q2301        ; m2[0].imre, m2[1].imre, m3[0].imre, m3[1].imre even
+
+%if cpuflag(fma3)
+    fmaddsubps %4, %4, %8, %9           ; w[0..8] even
+%else
+    mulps      %4, %4, %8               ; m2,3[01]imre * cos0246
+    addsubps   %4, %4, %9               ; w[0..8]
+%endif
+
+%if %1
+    shufps     %9, %7, %7, q1133        ; wim77553311
+%else
+    shufps     %9, %7, %7, q0022        ; wim66442200
+%endif
+
+    mulps      %9, %9, %5               ; m2,3[23]reim * wim7531 even
+    shufps     %5, %5, %5, q2301        ; m2[2].imre, m2[3].imre, m3[2].imre, m3[3].imre even
+%if cpuflag (fma3)
+    fmsubaddps %5, %5, %8, %9           ; j[0..8] even
+%else
+    mulps      %5, %5, %8               ; m2,3[23]reim * cos0246
+    xorps      %9, %9, [mask_pmpmpmpm]  ; +-m2,3[23]imre * wim7531
+    addps      %5, %5, %9               ; j[0..8]
+%endif
+
+    addps      %8, %4, %5               ; t10235476
+    subps      %9, %4, %5               ; +-r[0..7]
+
+    shufps     %8, %8, %8, q2301        ; t[0..7]
+    xorps      %9, %9, [mask_pmpmpmpm]  ; r[0..7]
+
+    subps      %4, %2, %8               ; %3,3[01]
+    subps      %5, %3, %9               ; %3,3[23]
+
+    addps      %2, %2, %8               ; m0
+    addps      %3, %3, %9               ; m1
+%endmacro
+
+%macro SPLIT_RADIX_COMBINE_64 0
+    SPLIT_RADIX_COMBINE_LITE 1, m0, m1, tx1_e0, tx2_e0, tw_e, tw_o, tmp1, tmp2
+
+    movaps [outq +  0*mmsize], m0
+    movaps [outq +  4*mmsize], m1
+    movaps [outq +  8*mmsize], tx1_e0
+    movaps [outq + 12*mmsize], tx2_e0
+
+    SPLIT_RADIX_COMBINE_HALF 0, m2, m3, tx1_o0, tx2_o0, tw_e, tw_o, tmp1, tmp2, m0
+
+    movaps [outq +  2*mmsize], m2
+    movaps [outq +  6*mmsize], m3
+    movaps [outq + 10*mmsize], tx1_o0
+    movaps [outq + 14*mmsize], tx2_o0
+
+    movaps tw_e,           [tab_64_float + mmsize]
+    vperm2f128 tw_o, tw_o, [tab_64_float + 64 - 4*7 - mmsize], 0x23
+
+    movaps m0, [outq +  1*mmsize]
+    movaps m1, [outq +  3*mmsize]
+    movaps m2, [outq +  5*mmsize]
+    movaps m3, [outq +  7*mmsize]
+
+    SPLIT_RADIX_COMBINE 0, m0, m2, m1, m3, tx1_e1, tx2_e1, tx1_o1, tx2_o1, tw_e, tw_o, \
+                           tmp1, tmp2, tx2_o0, tx1_o0, tx2_e0, tx1_e0 ; temporary registers
+
+    movaps [outq +  1*mmsize], m0
+    movaps [outq +  3*mmsize], m1
+    movaps [outq +  5*mmsize], m2
+    movaps [outq +  7*mmsize], m3
+
+    movaps [outq +  9*mmsize], tx1_e1
+    movaps [outq + 11*mmsize], tx1_o1
+    movaps [outq + 13*mmsize], tx2_e1
+    movaps [outq + 15*mmsize], tx2_o1
+%endmacro
+
+; Perform a single even/odd split radix combination with loads and stores
+; The _4 indicates this is a quarter of the iterations required to complete a full
+; combine loop
+; %1 must contain len*2, %2 must contain len*4, %3 must contain len*6
+%macro SPLIT_RADIX_LOAD_COMBINE_4 8
+    movaps m8,         [rtabq + (%5)*mmsize + %7]
+    vperm2f128 m9, m9, [itabq - (%5)*mmsize + %8], 0x23
+
+    movaps m0, [outq +      (0 + %4)*mmsize + %6]
+    movaps m2, [outq +      (2 + %4)*mmsize + %6]
+    movaps m1, [outq + %1 + (0 + %4)*mmsize + %6]
+    movaps m3, [outq + %1 + (2 + %4)*mmsize + %6]
+
+    movaps m4, [outq + %2 + (0 + %4)*mmsize + %6]
+    movaps m6, [outq + %2 + (2 + %4)*mmsize + %6]
+    movaps m5, [outq + %3 + (0 + %4)*mmsize + %6]
+    movaps m7, [outq + %3 + (2 + %4)*mmsize + %6]
+
+    SPLIT_RADIX_COMBINE 0, m0, m1, m2, m3, \
+                           m4, m5, m6, m7, \
+                           m8, m9, \
+                           m10, m11, m12, m13, m14, m15
+
+    movaps [outq +      (0 + %4)*mmsize + %6], m0
+    movaps [outq +      (2 + %4)*mmsize + %6], m2
+    movaps [outq + %1 + (0 + %4)*mmsize + %6], m1
+    movaps [outq + %1 + (2 + %4)*mmsize + %6], m3
+
+    movaps [outq + %2 + (0 + %4)*mmsize + %6], m4
+    movaps [outq + %2 + (2 + %4)*mmsize + %6], m6
+    movaps [outq + %3 + (0 + %4)*mmsize + %6], m5
+    movaps [outq + %3 + (2 + %4)*mmsize + %6], m7
+%endmacro
+
+%macro SPLIT_RADIX_LOAD_COMBINE_FULL 2-5
+%if %0 > 2
+%define offset_c %3
+%else
+%define offset_c 0
+%endif
+%if %0 > 3
+%define offset_r %4
+%else
+%define offset_r 0
+%endif
+%if %0 > 4
+%define offset_i %5
+%else
+%define offset_i 0
+%endif
+
+    SPLIT_RADIX_LOAD_COMBINE_4 %1, 2*%1, %2, 0, 0, offset_c, offset_r, offset_i
+    SPLIT_RADIX_LOAD_COMBINE_4 %1, 2*%1, %2, 1, 1, offset_c, offset_r, offset_i
+    SPLIT_RADIX_LOAD_COMBINE_4 %1, 2*%1, %2, 4, 2, offset_c, offset_r, offset_i
+    SPLIT_RADIX_LOAD_COMBINE_4 %1, 2*%1, %2, 5, 3, offset_c, offset_r, offset_i
+%endmacro
+
+; Perform a single even/odd split radix combination with loads, deinterleaves and
+; stores. The _2 indicates this is a half of the iterations required to complete
+; a full combine+deinterleave loop
+; %3 must contain len*2, %4 must contain len*4, %5 must contain len*6
+%macro SPLIT_RADIX_COMBINE_DEINTERLEAVE_2 6
+    movaps m8,         [rtabq + (0 + %2)*mmsize]
+    vperm2f128 m9, m9, [itabq - (0 + %2)*mmsize], 0x23
+
+    movaps m0, [outq +      (0 + 0 + %1)*mmsize + %6]
+    movaps m2, [outq +      (2 + 0 + %1)*mmsize + %6]
+    movaps m1, [outq + %3 + (0 + 0 + %1)*mmsize + %6]
+    movaps m3, [outq + %3 + (2 + 0 + %1)*mmsize + %6]
+
+    movaps m4, [outq + %4 + (0 + 0 + %1)*mmsize + %6]
+    movaps m6, [outq + %4 + (2 + 0 + %1)*mmsize + %6]
+    movaps m5, [outq + %5 + (0 + 0 + %1)*mmsize + %6]
+    movaps m7, [outq + %5 + (2 + 0 + %1)*mmsize + %6]
+
+    SPLIT_RADIX_COMBINE 0, m0, m1, m2, m3, \
+       m4, m5, m6, m7, \
+       m8, m9, \
+       m10, m11, m12, m13, m14, m15
+
+    unpckhpd m10, m0, m2
+    unpckhpd m11, m1, m3
+    unpckhpd m12, m4, m6
+    unpckhpd m13, m5, m7
+    unpcklpd m0, m0, m2
+    unpcklpd m1, m1, m3
+    unpcklpd m4, m4, m6
+    unpcklpd m5, m5, m7
+
+    vextractf128 [outq +      (0 + 0 + %1)*mmsize + %6 +  0], m0,  0
+    vextractf128 [outq +      (0 + 0 + %1)*mmsize + %6 + 16], m10, 0
+    vextractf128 [outq + %3 + (0 + 0 + %1)*mmsize + %6 +  0], m1,  0
+    vextractf128 [outq + %3 + (0 + 0 + %1)*mmsize + %6 + 16], m11, 0
+
+    vextractf128 [outq + %4 + (0 + 0 + %1)*mmsize + %6 +  0], m4,  0
+    vextractf128 [outq + %4 + (0 + 0 + %1)*mmsize + %6 + 16], m12, 0
+    vextractf128 [outq + %5 + (0 + 0 + %1)*mmsize + %6 +  0], m5,  0
+    vextractf128 [outq + %5 + (0 + 0 + %1)*mmsize + %6 + 16], m13, 0
+
+    vperm2f128 m10, m10, m0, 0x13
+    vperm2f128 m11, m11, m1, 0x13
+    vperm2f128 m12, m12, m4, 0x13
+    vperm2f128 m13, m13, m5, 0x13
+
+    movaps m8,         [rtabq + (1 + %2)*mmsize]
+    vperm2f128 m9, m9, [itabq - (1 + %2)*mmsize], 0x23
+
+    movaps m0, [outq +      (0 + 1 + %1)*mmsize + %6]
+    movaps m2, [outq +      (2 + 1 + %1)*mmsize + %6]
+    movaps m1, [outq + %3 + (0 + 1 + %1)*mmsize + %6]
+    movaps m3, [outq + %3 + (2 + 1 + %1)*mmsize + %6]
+
+    movaps [outq +      (0 + 1 + %1)*mmsize + %6], m10 ; m0 conflict
+    movaps [outq + %3 + (0 + 1 + %1)*mmsize + %6], m11 ; m1 conflict
+
+    movaps m4, [outq + %4 + (0 + 1 + %1)*mmsize + %6]
+    movaps m6, [outq + %4 + (2 + 1 + %1)*mmsize + %6]
+    movaps m5, [outq + %5 + (0 + 1 + %1)*mmsize + %6]
+    movaps m7, [outq + %5 + (2 + 1 + %1)*mmsize + %6]
+
+    movaps [outq + %4 + (0 + 1 + %1)*mmsize + %6], m12 ; m4 conflict
+    movaps [outq + %5 + (0 + 1 + %1)*mmsize + %6], m13 ; m5 conflict
+
+    SPLIT_RADIX_COMBINE 0, m0, m1, m2, m3, \
+                           m4, m5, m6, m7, \
+                           m8, m9, \
+                           m10, m11, m12, m13, m14, m15 ; temporary registers
+
+    unpcklpd m8,  m0, m2
+    unpcklpd m9,  m1, m3
+    unpcklpd m10, m4, m6
+    unpcklpd m11, m5, m7
+    unpckhpd m0, m0, m2
+    unpckhpd m1, m1, m3
+    unpckhpd m4, m4, m6
+    unpckhpd m5, m5, m7
+
+    vextractf128 [outq +      (2 + 0 + %1)*mmsize + %6 +  0], m8,  0
+    vextractf128 [outq +      (2 + 0 + %1)*mmsize + %6 + 16], m0,  0
+    vextractf128 [outq +      (2 + 1 + %1)*mmsize + %6 +  0], m8,  1
+    vextractf128 [outq +      (2 + 1 + %1)*mmsize + %6 + 16], m0,  1
+
+    vextractf128 [outq + %3 + (2 + 0 + %1)*mmsize + %6 +  0], m9,  0
+    vextractf128 [outq + %3 + (2 + 0 + %1)*mmsize + %6 + 16], m1,  0
+    vextractf128 [outq + %3 + (2 + 1 + %1)*mmsize + %6 +  0], m9,  1
+    vextractf128 [outq + %3 + (2 + 1 + %1)*mmsize + %6 + 16], m1,  1
+
+    vextractf128 [outq + %4 + (2 + 0 + %1)*mmsize + %6 +  0], m10, 0
+    vextractf128 [outq + %4 + (2 + 0 + %1)*mmsize + %6 + 16], m4,  0
+    vextractf128 [outq + %4 + (2 + 1 + %1)*mmsize + %6 +  0], m10, 1
+    vextractf128 [outq + %4 + (2 + 1 + %1)*mmsize + %6 + 16], m4,  1
+
+    vextractf128 [outq + %5 + (2 + 0 + %1)*mmsize + %6 +  0], m11, 0
+    vextractf128 [outq + %5 + (2 + 0 + %1)*mmsize + %6 + 16], m5,  0
+    vextractf128 [outq + %5 + (2 + 1 + %1)*mmsize + %6 +  0], m11, 1
+    vextractf128 [outq + %5 + (2 + 1 + %1)*mmsize + %6 + 16], m5,  1
+%endmacro
+
+%macro SPLIT_RADIX_COMBINE_DEINTERLEAVE_FULL 2-3
+%if %0 > 2
+%define offset %3
+%else
+%define offset 0
+%endif
+    SPLIT_RADIX_COMBINE_DEINTERLEAVE_2 0, 0, %1, %1*2, %2, offset
+    SPLIT_RADIX_COMBINE_DEINTERLEAVE_2 4, 2, %1, %1*2, %2, offset
+%endmacro
+
+INIT_XMM sse3
+cglobal fft2_asm_float, 0, 0, 0, ctx, out, in, stride
+    movaps m0, [inq]
+    FFT2 m0, m1
+    movaps [outq], m0
+    ret
+
+cglobal fft2_float, 4, 4, 2, ctx, out, in, stride
+    movaps m0, [inq]
+    FFT2 m0, m1
+    movaps [outq], m0
+    RET
+
+%macro FFT4_FN 3
+INIT_XMM sse2
+%if %3
+cglobal fft4_ %+ %1 %+ _asm_float, 0, 0, 0, ctx, out, in, stride
+%else
+cglobal fft4_ %+ %1 %+ _float, 4, 4, 3, ctx, out, in, stride
+%endif
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+
+%if %2
+    shufps m2, m1, m0, q3210
+    shufps m0, m0, m1, q3210
+    movaps m1, m2
+%endif
+
+    FFT4 m0, m1, m2
+
+    unpcklpd m2, m0, m1
+    unpckhpd m0, m0, m1
+
+    movaps [outq + 0*mmsize], m2
+    movaps [outq + 1*mmsize], m0
+
+%if %3
+    ret
+%else
+    RET
+%endif
+%endmacro
+
+FFT4_FN fwd, 0, 0
+FFT4_FN fwd, 0, 1
+FFT4_FN inv, 1, 0
+FFT4_FN inv, 1, 1
+
+%macro FFT8_SSE_FN 1
+INIT_XMM sse3
+%if %1
+cglobal fft8_asm_float, 0, 0, 0, ctx, out, in, stride, tmp
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+    movaps m2, [inq + 2*mmsize]
+    movaps m3, [inq + 3*mmsize]
+%else
+cglobal fft8_float, 4, 4, 6, ctx, out, in, tmp
+    mov ctxq, [ctxq + AVTXContext.map]
+    LOAD64_LUT m0, inq, ctxq, (mmsize/2)*0, tmpq
+    LOAD64_LUT m1, inq, ctxq, (mmsize/2)*1, tmpq
+    LOAD64_LUT m2, inq, ctxq, (mmsize/2)*2, tmpq
+    LOAD64_LUT m3, inq, ctxq, (mmsize/2)*3, tmpq
+%endif
+
+    FFT8 m0, m1, m2, m3, m4, m5
+
+    unpcklpd m4, m0, m3
+    unpcklpd m5, m1, m2
+    unpckhpd m0, m0, m3
+    unpckhpd m1, m1, m2
+
+    movups [outq + 0*mmsize], m4
+    movups [outq + 1*mmsize], m0
+    movups [outq + 2*mmsize], m5
+    movups [outq + 3*mmsize], m1
+
+%if %1
+    ret
+%else
+    RET
+%endif
+
+%if %1
+cglobal fft8_ns_float, 4, 5, 6, ctx, out, in, stride, tmp
+    call mangle(ff_tx_fft8_asm_float_sse3)
+    RET
+%endif
+%endmacro
+
+FFT8_SSE_FN 0
+FFT8_SSE_FN 1
+
+%macro FFT8_AVX_FN 1
+INIT_YMM avx
+%if %1
+cglobal fft8_asm_float, 0, 0, 0, ctx, out, in, stride, tmp
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+%else
+cglobal fft8_float, 4, 4, 4, ctx, out, in, tmp
+    mov ctxq, [ctxq + AVTXContext.map]
+    LOAD64_LUT m0, inq, ctxq, (mmsize/2)*0, tmpq, m2
+    LOAD64_LUT m1, inq, ctxq, (mmsize/2)*1, tmpq, m3
+%endif
+
+    FFT8_AVX m0, m1, m2, m3
+
+    unpcklpd m2, m0, m1
+    unpckhpd m0, m0, m1
+
+    ; Around 2% faster than 2x vperm2f128 + 2x movapd
+    vextractf128 [outq + 16*0], m2, 0
+    vextractf128 [outq + 16*1], m0, 0
+    vextractf128 [outq + 16*2], m2, 1
+    vextractf128 [outq + 16*3], m0, 1
+
+%if %1
+    ret
+%else
+    RET
+%endif
+
+%if %1
+cglobal fft8_ns_float, 4, 5, 4, ctx, out, in, stride, tmp
+    call mangle(ff_tx_fft8_asm_float_avx)
+    RET
+%endif
+%endmacro
+
+FFT8_AVX_FN 0
+FFT8_AVX_FN 1
+
+%macro FFT16_FN 2
+INIT_YMM %1
+%if %2
+cglobal fft16_asm_float, 0, 0, 0, ctx, out, in, stride, tmp
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+    movaps m2, [inq + 2*mmsize]
+    movaps m3, [inq + 3*mmsize]
+%else
+cglobal fft16_float, 4, 4, 8, ctx, out, in, tmp
+    mov ctxq, [ctxq + AVTXContext.map]
+    LOAD64_LUT m0, inq, ctxq, (mmsize/2)*0, tmpq, m4
+    LOAD64_LUT m1, inq, ctxq, (mmsize/2)*1, tmpq, m5
+    LOAD64_LUT m2, inq, ctxq, (mmsize/2)*2, tmpq, m6
+    LOAD64_LUT m3, inq, ctxq, (mmsize/2)*3, tmpq, m7
+%endif
+
+    FFT16 m0, m1, m2, m3, m4, m5, m6, m7
+
+    unpcklpd m5, m1, m3
+    unpcklpd m4, m0, m2
+    unpckhpd m1, m1, m3
+    unpckhpd m0, m0, m2
+
+    vextractf128 [outq + 16*0], m4, 0
+    vextractf128 [outq + 16*1], m0, 0
+    vextractf128 [outq + 16*2], m4, 1
+    vextractf128 [outq + 16*3], m0, 1
+    vextractf128 [outq + 16*4], m5, 0
+    vextractf128 [outq + 16*5], m1, 0
+    vextractf128 [outq + 16*6], m5, 1
+    vextractf128 [outq + 16*7], m1, 1
+
+%if %2
+    ret
+%else
+    RET
+%endif
+
+%if %2
+cglobal fft16_ns_float, 4, 5, 8, ctx, out, in, stride, tmp
+    call mangle(ff_tx_fft16_asm_float_ %+ %1)
+    RET
+%endif
+%endmacro
+
+FFT16_FN avx,  0
+FFT16_FN avx,  1
+FFT16_FN fma3, 0
+FFT16_FN fma3, 1
+
+%macro FFT32_FN 2
+INIT_YMM %1
+%if %2
+cglobal fft32_asm_float, 0, 0, 0, ctx, out, in, stride, tmp
+    movaps m4, [inq + 4*mmsize]
+    movaps m5, [inq + 5*mmsize]
+    movaps m6, [inq + 6*mmsize]
+    movaps m7, [inq + 7*mmsize]
+%else
+cglobal fft32_float, 4, 4, 16, ctx, out, in, tmp
+    mov ctxq, [ctxq + AVTXContext.map]
+    LOAD64_LUT m4, inq, ctxq, (mmsize/2)*4, tmpq,  m8, m12
+    LOAD64_LUT m5, inq, ctxq, (mmsize/2)*5, tmpq,  m9, m13
+    LOAD64_LUT m6, inq, ctxq, (mmsize/2)*6, tmpq, m10, m14
+    LOAD64_LUT m7, inq, ctxq, (mmsize/2)*7, tmpq, m11, m15
+%endif
+
+    FFT8 m4, m5, m6, m7, m8, m9
+
+%if %2
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+    movaps m2, [inq + 2*mmsize]
+    movaps m3, [inq + 3*mmsize]
+%else
+    LOAD64_LUT m0, inq, ctxq, (mmsize/2)*0, tmpq,  m8, m12
+    LOAD64_LUT m1, inq, ctxq, (mmsize/2)*1, tmpq,  m9, m13
+    LOAD64_LUT m2, inq, ctxq, (mmsize/2)*2, tmpq, m10, m14
+    LOAD64_LUT m3, inq, ctxq, (mmsize/2)*3, tmpq, m11, m15
+%endif
+
+    movaps m8,         [tab_32_float]
+    vperm2f128 m9, m9, [tab_32_float + 4*8 - 4*7], 0x23
+
+    FFT16 m0, m1, m2, m3, m10, m11, m12, m13
+
+    SPLIT_RADIX_COMBINE 1, m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, \
+                           m10, m11, m12, m13, m14, m15 ; temporary registers
+
+    unpcklpd  m9, m1, m3
+    unpcklpd m10, m5, m7
+    unpcklpd  m8, m0, m2
+    unpcklpd m11, m4, m6
+    unpckhpd  m1, m1, m3
+    unpckhpd  m5, m5, m7
+    unpckhpd  m0, m0, m2
+    unpckhpd  m4, m4, m6
+
+    vextractf128 [outq + 16* 0],  m8, 0
+    vextractf128 [outq + 16* 1],  m0, 0
+    vextractf128 [outq + 16* 2],  m8, 1
+    vextractf128 [outq + 16* 3],  m0, 1
+    vextractf128 [outq + 16* 4],  m9, 0
+    vextractf128 [outq + 16* 5],  m1, 0
+    vextractf128 [outq + 16* 6],  m9, 1
+    vextractf128 [outq + 16* 7],  m1, 1
+
+    vextractf128 [outq + 16* 8], m11, 0
+    vextractf128 [outq + 16* 9],  m4, 0
+    vextractf128 [outq + 16*10], m11, 1
+    vextractf128 [outq + 16*11],  m4, 1
+    vextractf128 [outq + 16*12], m10, 0
+    vextractf128 [outq + 16*13],  m5, 0
+    vextractf128 [outq + 16*14], m10, 1
+    vextractf128 [outq + 16*15],  m5, 1
+
+%if %2
+    ret
+%else
+    RET
+%endif
+
+%if %2
+cglobal fft32_ns_float, 4, 5, 16, ctx, out, in, stride, tmp
+    call mangle(ff_tx_fft32_asm_float_ %+ %1)
+    RET
+%endif
+%endmacro
+
+%if ARCH_X86_64
+FFT32_FN avx,  0
+FFT32_FN avx,  1
+FFT32_FN fma3, 0
+FFT32_FN fma3, 1
+%endif
+
+%macro FFT_SPLIT_RADIX_DEF 1-2
+ALIGN 16
+.%1 %+ pt:
+    PUSH lenq
+    mov lenq, (%1/4)
+
+    add outq, (%1*4) - (%1/1)
+    call .32pt
+
+    add outq, (%1*2) - (%1/2) ; the synth loops also increment outq
+    call .32pt
+
+    POP lenq
+    sub outq, (%1*4) + (%1*2) + (%1/2)
+
+    lea rtabq, [tab_ %+ %1 %+ _float]
+    lea itabq, [tab_ %+ %1 %+ _float + %1 - 4*7]
+
+%if %0 > 1
+    cmp tgtq, %1
+    je .deinterleave
+
+    mov tmpq, %1
+
+.synth_ %+ %1:
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*%1, 6*%1, 0, 0, 0
+    add outq, 8*mmsize
+    add rtabq, 4*mmsize
+    sub itabq, 4*mmsize
+    sub tmpq, 4*mmsize
+    jg .synth_ %+ %1
+
+    cmp lenq, %1
+    jg %2 ; can't do math here, nasm doesn't get it
+    ret
+%endif
+%endmacro
+
+%macro FFT_SPLIT_RADIX_FN 2
+INIT_YMM %1
+%if %2
+cglobal fft_sr_asm_float, 0, 0, 0, ctx, out, in, stride, len, lut, itab, rtab, tgt, tmp
+%else
+cglobal fft_sr_float, 4, 10, 16, 272, ctx, out, in, stride, len, lut, itab, rtab, tgt, tmp
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov lutq, [ctxq + AVTXContext.map]
+%endif
+    mov tgtq, lenq
+
+; Bottom-most/32-point transform ===============================================
+ALIGN 16
+.32pt:
+%if %2
+    movaps m4, [inq + 4*mmsize]
+    movaps m5, [inq + 5*mmsize]
+    movaps m6, [inq + 6*mmsize]
+    movaps m7, [inq + 7*mmsize]
+%else
+    LOAD64_LUT m4, inq, lutq, (mmsize/2)*4, tmpq,  m8, m12
+    LOAD64_LUT m5, inq, lutq, (mmsize/2)*5, tmpq,  m9, m13
+    LOAD64_LUT m6, inq, lutq, (mmsize/2)*6, tmpq, m10, m14
+    LOAD64_LUT m7, inq, lutq, (mmsize/2)*7, tmpq, m11, m15
+%endif
+
+    FFT8 m4, m5, m6, m7, m8, m9
+
+%if %2
+    movaps m0, [inq + 0*mmsize]
+    movaps m1, [inq + 1*mmsize]
+    movaps m2, [inq + 2*mmsize]
+    movaps m3, [inq + 3*mmsize]
+%else
+    LOAD64_LUT m0, inq, lutq, (mmsize/2)*0, tmpq,  m8, m12
+    LOAD64_LUT m1, inq, lutq, (mmsize/2)*1, tmpq,  m9, m13
+    LOAD64_LUT m2, inq, lutq, (mmsize/2)*2, tmpq, m10, m14
+    LOAD64_LUT m3, inq, lutq, (mmsize/2)*3, tmpq, m11, m15
+%endif
+
+    movaps m8,         [tab_32_float]
+    vperm2f128 m9, m9, [tab_32_float + 32 - 4*7], 0x23
+
+    FFT16 m0, m1, m2, m3, m10, m11, m12, m13
+
+    SPLIT_RADIX_COMBINE 1, m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, \
+                           m10, m11, m12, m13, m14, m15 ; temporary registers
+
+    movaps [outq + 1*mmsize], m1
+    movaps [outq + 3*mmsize], m3
+    movaps [outq + 5*mmsize], m5
+    movaps [outq + 7*mmsize], m7
+
+%if %2
+    add inq, 8*mmsize
+%else
+    add lutq, (mmsize/2)*8
+%endif
+    cmp lenq, 32
+    jg .64pt
+
+    movaps [outq + 0*mmsize], m0
+    movaps [outq + 2*mmsize], m2
+    movaps [outq + 4*mmsize], m4
+    movaps [outq + 6*mmsize], m6
+
+    ret
+
+; 64-point transform ===========================================================
+ALIGN 16
+.64pt:
+; Helper defines, these make it easier to track what's happening
+%define tx1_e0 m4
+%define tx1_e1 m5
+%define tx1_o0 m6
+%define tx1_o1 m7
+%define tx2_e0 m8
+%define tx2_e1 m9
+%define tx2_o0 m10
+%define tx2_o1 m11
+%define tw_e m12
+%define tw_o m13
+%define tmp1 m14
+%define tmp2 m15
+
+    SWAP m4, m1
+    SWAP m6, m3
+
+%if %2
+    movaps tx1_e0, [inq + 0*mmsize]
+    movaps tx1_e1, [inq + 1*mmsize]
+    movaps tx1_o0, [inq + 2*mmsize]
+    movaps tx1_o1, [inq + 3*mmsize]
+%else
+    LOAD64_LUT tx1_e0, inq, lutq, (mmsize/2)*0, tmpq, tw_e, tmp1
+    LOAD64_LUT tx1_e1, inq, lutq, (mmsize/2)*1, tmpq, tw_o, tmp2
+    LOAD64_LUT tx1_o0, inq, lutq, (mmsize/2)*2, tmpq, tw_e, tmp1
+    LOAD64_LUT tx1_o1, inq, lutq, (mmsize/2)*3, tmpq, tw_o, tmp2
+%endif
+
+    FFT16 tx1_e0, tx1_e1, tx1_o0, tx1_o1, tw_e, tw_o, tx2_o0, tx2_o1
+
+%if %2
+    movaps tx2_e0, [inq + 4*mmsize]
+    movaps tx2_e1, [inq + 5*mmsize]
+    movaps tx2_o0, [inq + 6*mmsize]
+    movaps tx2_o1, [inq + 7*mmsize]
+%else
+    LOAD64_LUT tx2_e0, inq, lutq, (mmsize/2)*4, tmpq, tw_e, tmp1
+    LOAD64_LUT tx2_e1, inq, lutq, (mmsize/2)*5, tmpq, tw_o, tmp2
+    LOAD64_LUT tx2_o0, inq, lutq, (mmsize/2)*6, tmpq, tw_e, tmp1
+    LOAD64_LUT tx2_o1, inq, lutq, (mmsize/2)*7, tmpq, tw_o, tmp2
+%endif
+
+    FFT16 tx2_e0, tx2_e1, tx2_o0, tx2_o1, tmp1, tmp2, tw_e, tw_o
+
+    movaps tw_e,           [tab_64_float]
+    vperm2f128 tw_o, tw_o, [tab_64_float + 64 - 4*7], 0x23
+
+%if %2
+    add inq, 8*mmsize
+%else
+    add lutq, (mmsize/2)*8
+%endif
+    cmp tgtq, 64
+    je .64pt_deint
+
+    SPLIT_RADIX_COMBINE_64
+
+    cmp lenq, 64
+    jg .128pt
+    ret
+
+; 128-point transform ==========================================================
+ALIGN 16
+.128pt:
+    PUSH lenq
+    mov lenq, 32
+
+    add outq, 16*mmsize
+    call .32pt
+
+    add outq, 8*mmsize
+    call .32pt
+
+    POP lenq
+    sub outq, 24*mmsize
+
+    lea rtabq, [tab_128_float]
+    lea itabq, [tab_128_float + 128 - 4*7]
+
+    cmp tgtq, 128
+    je .deinterleave
+
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*128, 6*128
+
+    cmp lenq, 128
+    jg .256pt
+    ret
+
+; 256-point transform ==========================================================
+ALIGN 16
+.256pt:
+    PUSH lenq
+    mov lenq, 64
+
+    add outq, 32*mmsize
+    call .32pt
+
+    add outq, 16*mmsize
+    call .32pt
+
+    POP lenq
+    sub outq, 48*mmsize
+
+    lea rtabq, [tab_256_float]
+    lea itabq, [tab_256_float + 256 - 4*7]
+
+    cmp tgtq, 256
+    je .deinterleave
+
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*256, 6*256
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*256, 6*256, 8*mmsize, 4*mmsize, -4*mmsize
+
+    cmp lenq, 256
+    jg .512pt
+    ret
+
+; 512-point transform ==========================================================
+ALIGN 16
+.512pt:
+    PUSH lenq
+    mov lenq, 128
+
+    add outq, 64*mmsize
+    call .32pt
+
+    add outq, 32*mmsize
+    call .32pt
+
+    POP lenq
+    sub outq, 96*mmsize
+
+    lea rtabq, [tab_512_float]
+    lea itabq, [tab_512_float + 512 - 4*7]
+
+    cmp tgtq, 512
+    je .deinterleave
+
+    mov tmpq, 4
+
+.synth_512:
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*512, 6*512
+    add outq, 8*mmsize
+    add rtabq, 4*mmsize
+    sub itabq, 4*mmsize
+    sub tmpq, 1
+    jg .synth_512
+
+    cmp lenq, 512
+    jg .1024pt
+    ret
+
+; 1024-point transform ==========================================================
+ALIGN 16
+.1024pt:
+    PUSH lenq
+    mov lenq, 256
+
+    add outq, 96*mmsize
+    call .32pt
+
+    add outq, 64*mmsize
+    call .32pt
+
+    POP lenq
+    sub outq, 192*mmsize
+
+    lea rtabq, [tab_1024_float]
+    lea itabq, [tab_1024_float + 1024 - 4*7]
+
+    cmp tgtq, 1024
+    je .deinterleave
+
+    mov tmpq, 8
+
+.synth_1024:
+    SPLIT_RADIX_LOAD_COMBINE_FULL 2*1024, 6*1024
+    add outq, 8*mmsize
+    add rtabq, 4*mmsize
+    sub itabq, 4*mmsize
+    sub tmpq, 1
+    jg .synth_1024
+
+    cmp lenq, 1024
+    jg .2048pt
+    ret
+
+; 2048 to 131072-point transforms ==============================================
+FFT_SPLIT_RADIX_DEF 2048,  .4096pt
+FFT_SPLIT_RADIX_DEF 4096,  .8192pt
+FFT_SPLIT_RADIX_DEF 8192,  .16384pt
+FFT_SPLIT_RADIX_DEF 16384, .32768pt
+FFT_SPLIT_RADIX_DEF 32768, .65536pt
+FFT_SPLIT_RADIX_DEF 65536, .131072pt
+FFT_SPLIT_RADIX_DEF 131072
+
+;===============================================================================
+; Final synthesis + deinterleaving code
+;===============================================================================
+.deinterleave:
+%if %2
+    PUSH strideq
+%endif
+    mov tgtq, lenq
+    imul tmpq, lenq, 2
+    lea strideq, [4*lenq + tmpq]
+
+.synth_deinterleave:
+    SPLIT_RADIX_COMBINE_DEINTERLEAVE_FULL tmpq, strideq
+    add outq, 8*mmsize
+    add rtabq, 4*mmsize
+    sub itabq, 4*mmsize
+    sub tgtq, 4*mmsize
+    jg .synth_deinterleave
+
+%if %2
+    POP strideq
+    sub outq, tmpq
+    neg tmpq
+    lea inq, [inq + tmpq*4]
+    ret
+%else
+    RET
+%endif
+
+; 64-point deinterleave which only has to load 4 registers =====================
+.64pt_deint:
+    SPLIT_RADIX_COMBINE_LITE 1, m0, m1, tx1_e0, tx2_e0, tw_e, tw_o, tmp1, tmp2
+    SPLIT_RADIX_COMBINE_HALF 0, m2, m3, tx1_o0, tx2_o0, tw_e, tw_o, tmp1, tmp2, tw_e
+
+    unpcklpd tmp1, m0, m2
+    unpcklpd tmp2, m1, m3
+    unpcklpd tw_o, tx1_e0, tx1_o0
+    unpcklpd tw_e, tx2_e0, tx2_o0
+    unpckhpd m0, m0, m2
+    unpckhpd m1, m1, m3
+    unpckhpd tx1_e0, tx1_e0, tx1_o0
+    unpckhpd tx2_e0, tx2_e0, tx2_o0
+
+    vextractf128 [outq +  0*mmsize +  0], tmp1,   0
+    vextractf128 [outq +  0*mmsize + 16], m0,     0
+    vextractf128 [outq +  4*mmsize +  0], tmp2,   0
+    vextractf128 [outq +  4*mmsize + 16], m1,     0
+
+    vextractf128 [outq +  8*mmsize +  0], tw_o,   0
+    vextractf128 [outq +  8*mmsize + 16], tx1_e0, 0
+    vextractf128 [outq +  9*mmsize +  0], tw_o,   1
+    vextractf128 [outq +  9*mmsize + 16], tx1_e0, 1
+
+    vperm2f128 tmp1, tmp1, m0, 0x31
+    vperm2f128 tmp2, tmp2, m1, 0x31
+
+    vextractf128 [outq + 12*mmsize +  0], tw_e,   0
+    vextractf128 [outq + 12*mmsize + 16], tx2_e0, 0
+    vextractf128 [outq + 13*mmsize +  0], tw_e,   1
+    vextractf128 [outq + 13*mmsize + 16], tx2_e0, 1
+
+    movaps tw_e,           [tab_64_float + mmsize]
+    vperm2f128 tw_o, tw_o, [tab_64_float + 64 - 4*7 - mmsize], 0x23
+
+    movaps m0, [outq +  1*mmsize]
+    movaps m1, [outq +  3*mmsize]
+    movaps m2, [outq +  5*mmsize]
+    movaps m3, [outq +  7*mmsize]
+
+    movaps [outq +  1*mmsize], tmp1
+    movaps [outq +  5*mmsize], tmp2
+
+    SPLIT_RADIX_COMBINE 0, m0, m2, m1, m3, tx1_e1, tx2_e1, tx1_o1, tx2_o1, tw_e, tw_o, \
+                           tmp1, tmp2, tx2_o0, tx1_o0, tx2_e0, tx1_e0 ; temporary registers
+
+    unpcklpd tmp1, m0, m1
+    unpcklpd tmp2, m2, m3
+    unpcklpd tw_e, tx1_e1, tx1_o1
+    unpcklpd tw_o, tx2_e1, tx2_o1
+    unpckhpd m0, m0, m1
+    unpckhpd m2, m2, m3
+    unpckhpd tx1_e1, tx1_e1, tx1_o1
+    unpckhpd tx2_e1, tx2_e1, tx2_o1
+
+    vextractf128 [outq +  2*mmsize +  0], tmp1,   0
+    vextractf128 [outq +  2*mmsize + 16], m0,     0
+    vextractf128 [outq +  3*mmsize +  0], tmp1,   1
+    vextractf128 [outq +  3*mmsize + 16], m0,     1
+
+    vextractf128 [outq +  6*mmsize +  0], tmp2,   0
+    vextractf128 [outq +  6*mmsize + 16], m2,     0
+    vextractf128 [outq +  7*mmsize +  0], tmp2,   1
+    vextractf128 [outq +  7*mmsize + 16], m2,     1
+
+    vextractf128 [outq + 10*mmsize +  0], tw_e,   0
+    vextractf128 [outq + 10*mmsize + 16], tx1_e1, 0
+    vextractf128 [outq + 11*mmsize +  0], tw_e,   1
+    vextractf128 [outq + 11*mmsize + 16], tx1_e1, 1
+
+    vextractf128 [outq + 14*mmsize +  0], tw_o,   0
+    vextractf128 [outq + 14*mmsize + 16], tx2_e1, 0
+    vextractf128 [outq + 15*mmsize +  0], tw_o,   1
+    vextractf128 [outq + 15*mmsize + 16], tx2_e1, 1
+
+%if %2
+    sub inq, 16*mmsize
+    ret
+%else
+    RET
+%endif
+
+%if %2
+cglobal fft_sr_ns_float, 4, 10, 16, 272, ctx, out, in, tmp, len, lut, itab, rtab, tgt, off
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov lutq, [ctxq + AVTXContext.map]
+
+    call mangle(ff_tx_fft_sr_asm_float_ %+ %1)
+    RET
+%endif
+%endmacro
+
+%if ARCH_X86_64
+FFT_SPLIT_RADIX_FN avx, 0
+FFT_SPLIT_RADIX_FN avx, 1
+FFT_SPLIT_RADIX_FN fma3, 0
+FFT_SPLIT_RADIX_FN fma3, 1
+FFT_SPLIT_RADIX_FN avx2, 0
+FFT_SPLIT_RADIX_FN avx2, 1
+%endif
+
+%macro FFT15_FN 2
+INIT_YMM avx2
+cglobal fft15_ %+ %2, 4, 10, 16, ctx, out, in, stride, len, lut, tmp, tgt5, stride3, stride5
+    mov lutq, [ctxq + AVTXContext.map]
+
+    imul stride3q, strideq, 3
+    imul stride5q, strideq, 5
+
+    movaps m11, [mask_mmppmmmm]      ; mmppmmmm
+    movaps m10, [tab_53_float]       ; tab5
+    movaps xm9, [tab_53_float + 32]  ; tab3
+    vpermpd m9, m9, q1110            ; tab[23232323]
+    movaps m8, [s15_perm]
+
+%if %1
+    movups  xm0, [inq]
+    movddup xm5, [inq + 16]
+    movups  m2, [inq + mmsize*0 + 24]
+    movups  m3, [inq + mmsize*1 + 24]
+    movups  m4, [inq + mmsize*2 + 24]
+%else
+    LOAD64_LUT xm0, inq, lutq, 0, tmpq, m14, xm15
+    LOAD64_LUT  m2, inq, lutq, (mmsize/2)*0 + 12, tmpq, m6, m7
+    LOAD64_LUT  m3, inq, lutq, (mmsize/2)*1 + 12, tmpq, m14, m15
+    LOAD64_LUT  m4, inq, lutq, (mmsize/2)*2 + 12, tmpq, m6, m7
+    mov tmpd, [lutq + 8]
+    movddup xm5, [inq + tmpq*8]
+%endif
+
+    FFT15
+
+    lea tgt5q, [outq + stride5q]
+    lea tmpq,  [outq + stride5q*2]
+
+    movhps [outq], xm14              ; out[0]
+    movhps [outq + stride5q*1], xm15 ; out[5]
+    movlps [outq + stride5q*2], xm15 ; out[10]
+
+    vextractf128 xm3, m0, 1
+    vextractf128 xm4, m1, 1
+    vextractf128 xm5, m2, 1
+
+    movlps [outq  + strideq*1],  xm1
+    movhps [outq  + strideq*2],  xm2
+    movlps [outq  + stride3q*1], xm3
+    movhps [outq  + strideq*4],  xm4
+    movlps [outq  + stride3q*2], xm0
+    movlps [outq  + strideq*8],  xm5
+    movhps [outq  + stride3q*4], xm0
+    movhps [tgt5q + strideq*2],  xm1
+    movhps [tgt5q + strideq*4],  xm3
+    movlps [tmpq  + strideq*1],  xm2
+    movlps [tmpq  + stride3q*1], xm4
+    movhps [tmpq  + strideq*4],  xm5
+
+    RET
+%endmacro
+
+%if ARCH_X86_64
+FFT15_FN 0, float
+FFT15_FN 1, ns_float
+%endif
+
+%macro IMDCT_FN 1
+INIT_YMM %1
+cglobal mdct_inv_float, 4, 14, 16, 320, ctx, out, in, stride, len, lut, exp, t1, t2, t3, \
+                                        t4, t5, btmp
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov expq, [ctxq + AVTXContext.exp]
+
+    lea t1d, [lend - 1]
+    imul t1d, strided
+
+    mov btmpq, ctxq                    ; backup original context
+    mov lutq, [ctxq + AVTXContext.map] ; load map
+
+    cmp strideq, 4
+    je .stride4
+
+    shl strideq, 1
+    movd xm4, strided
+    vpbroadcastd m4, xm4             ; stride splatted
+    movd xm5, t1d
+    vpbroadcastd m5, xm5             ; offset splatted
+
+    mov t2q, outq                    ; don't modify the original output
+    pcmpeqd m15, m15                 ; set all bits to 1
+
+.stridex_pre:
+    pmulld m2, m4, [lutq]            ; multiply by stride
+    movaps m0, m15
+    psubd m3, m5, m2                 ; subtract from offset
+    movaps m1, m15
+    vgatherdps m6, [inq + m2], m0    ; im
+    vgatherdps m7, [inq + m3], m1    ; re
+
+    movaps m8, [expq + 0*mmsize]     ; tab 1
+    movaps m9, [expq + 1*mmsize]     ; tab 2
+
+    unpcklps m0, m7, m6              ; re, im, re, im
+    unpckhps m1, m7, m6              ; re, im, re, im
+
+    vperm2f128 m2, m1, m0, 0x02      ; output order
+    vperm2f128 m3, m1, m0, 0x13      ; output order
+
+    movshdup m10, m8                 ; tab 1 imim
+    movshdup m11, m9                 ; tab 2 imim
+    movsldup m12, m8                 ; tab 1 rere
+    movsldup m13, m9                 ; tab 2 rere
+
+    mulps m10, m2                    ; 1 reim * imim
+    mulps m11, m3                    ; 2 reim * imim
+
+    shufps m10, m10, q2301
+    shufps m11, m11, q2301
+
+    fmaddsubps m10, m12, m2, m10
+    fmaddsubps m11, m13, m3, m11
+
+    movups [t2q + 0*mmsize], m10
+    movups [t2q + 1*mmsize], m11
+
+    add expq, mmsize*2
+    add lutq, mmsize
+    add t2q, mmsize*2
+    sub lenq, mmsize/2
+    jg .stridex_pre
+    jmp .transform
+
+.stride4:
+    lea expq, [expq + lenq*4]
+    lea lutq, [lutq + lenq*2]
+    lea t1q, [inq + t1q]
+    lea t1q, [t1q + strideq - mmsize]
+    lea t2q, [lenq*2 - mmsize/2]
+
+.stride4_pre:
+    movups       m4, [inq]
+    movups       m3, [t1q]
+
+    movsldup     m1, m4              ; im im, im im
+    movshdup     m0, m3              ; re re, re re
+    movshdup     m4, m4              ; re re, re re (2)
+    movsldup     m3, m3              ; im im, im im (2)
+
+    movups       m2, [expq]          ; tab
+    movups       m5, [expq + 2*t2q]  ; tab (2)
+
+    vpermpd      m0, m0, q0123       ; flip
+    shufps       m7, m2, m2, q2301
+    vpermpd      m4, m4, q0123       ; flip (2)
+    shufps       m8, m5, m5, q2301
+
+    mulps        m1, m7              ; im im * tab.reim
+    mulps        m3, m8              ; im im * tab.reim (2)
+
+    fmaddsubps   m0, m0, m2, m1
+    fmaddsubps   m4, m4, m5, m3
+
+    vextractf128 xm3, m0, 1
+    vextractf128 xm6, m4, 1
+
+    ; scatter
+    movsxd strideq, dword [lutq + 0*4]
+    movsxd lenq,    dword [lutq + 1*4]
+    movsxd t3q,     dword [lutq + 2*4]
+    movsxd t4q,     dword [lutq + 3*4]
+
+    movlps [outq + strideq*8], xm0
+    movhps [outq + lenq*8],    xm0
+    movlps [outq + t3q*8],     xm3
+    movhps [outq + t4q*8],     xm3
+
+    movsxd strideq, dword [lutq + 0*4 + t2q]
+    movsxd lenq,    dword [lutq + 1*4 + t2q]
+    movsxd t3q,     dword [lutq + 2*4 + t2q]
+    movsxd t4q,     dword [lutq + 3*4 + t2q]
+
+    movlps [outq + strideq*8], xm4
+    movhps [outq + lenq*8],    xm4
+    movlps [outq + t3q*8],     xm6
+    movhps [outq + t4q*8],     xm6
+
+    add lutq, mmsize/2
+    add expq, mmsize
+    add inq, mmsize
+    sub t1q, mmsize
+    sub t2q, mmsize
+    jge .stride4_pre
+
+.transform:
+    mov strideq, 2*4
+    mov t4q, ctxq                      ; backup original context
+    mov t5q, [ctxq + AVTXContext.fn]   ; subtransform's jump point
+    mov ctxq, [ctxq + AVTXContext.sub]
+    mov lutq, [ctxq + AVTXContext.map]
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+
+    mov inq, outq                    ; in-place transform
+    call t5q                         ; call the FFT
+
+    mov ctxq, t4q                    ; restore original context
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov expq, [ctxq + AVTXContext.exp]
+    lea expq, [expq + lenq*4]
+
+    xor t1q, t1q                     ; low
+    lea t2q, [lenq*4 - mmsize]       ; high
+
+.post:
+    movaps m2, [expq + t2q]          ; tab h
+    movaps m3, [expq + t1q]          ; tab l
+    movups m0, [outq + t2q]          ; in h
+    movups m1, [outq + t1q]          ; in l
+
+    movshdup m4, m2                  ; tab h imim
+    movshdup m5, m3                  ; tab l imim
+    movsldup m6, m2                  ; tab h rere
+    movsldup m7, m3                  ; tab l rere
+
+    shufps m2, m0, m0, q2301         ; in h imre
+    shufps m3, m1, m1, q2301         ; in l imre
+
+    mulps m6, m0
+    mulps m7, m1
+
+    fmaddsubps m4, m4, m2, m6
+    fmaddsubps m5, m5, m3, m7
+
+    vpermpd m3, m5, q0123            ; flip
+    vpermpd m2, m4, q0123            ; flip
+
+    blendps m1, m2, m5, 01010101b
+    blendps m0, m3, m4, 01010101b
+
+    movups [outq + t2q], m0
+    movups [outq + t1q], m1
+
+    add t1q, mmsize
+    sub t2q, mmsize
+    sub lenq, mmsize/2
+    jg .post
+
+    RET
+%endmacro
+
+%if ARCH_X86_64
+IMDCT_FN avx2
+%endif
+
+%macro PFA_15_FN 2
+INIT_YMM %1
+%if %2
+cglobal fft_pfa_15xM_asm_float, 0, 0, 0, ctx, out, in, stride, len, lut, buf, map, tgt, tmp, \
+                                         tgt5, stride3, stride5, btmp
+%else
+cglobal fft_pfa_15xM_float, 4, 14, 16, 320, ctx, out, in, stride, len, lut, buf, map, tgt, tmp, \
+                                            tgt5, stride3, stride5, btmp
+%endif
+
+%if %2
+    PUSH inq
+    PUSH tgt5q
+    PUSH stride3q
+    PUSH stride5q
+    PUSH btmpq
+%endif
+
+    PUSH strideq
+
+    mov btmpq, outq
+
+    mov outq, [ctxq + AVTXContext.tmp]
+%if !%2
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov lutq, [ctxq + AVTXContext.map]
+%endif
+
+    ; Load stride (second transform's length) and second transform's LUT
+    mov tmpq, [ctxq + AVTXContext.sub]
+    movsxd strideq, dword [tmpq + AVTXContext.len]
+    mov mapq, [tmpq + AVTXContext.map]
+
+    shl strideq, 3
+    imul stride3q, strideq, 3
+    imul stride5q, strideq, 5
+
+    movaps m11, [mask_mmppmmmm]      ; mmppmmmm
+    movaps m10, [tab_53_float]       ; tab5
+    movaps xm9, [tab_53_float + 32]  ; tab3
+    vpermpd m9, m9, q1110            ; tab[23232323]
+    movaps m8, [s15_perm]
+
+.dim1:
+    mov tmpd, [mapq]
+    lea tgtq, [outq + tmpq*8]
+
+%if %2
+    movups  xm0, [inq]                                            ; in[0,1].reim
+    movddup xm5, [inq + 16]                                       ; in[2].reimreim
+    movups  m2, [inq + mmsize*0 + 24]                             ; in[3-6].reim
+    movups  m3, [inq + mmsize*1 + 24]                             ; in[7-11].reim
+    movups  m4, [inq + mmsize*2 + 24]                             ; in[12-15].reim
+%else
+    LOAD64_LUT xm0, inq, lutq, 0, tmpq, m14, xm15                 ; in[0,1].reim
+    LOAD64_LUT  m2, inq, lutq, (mmsize/2)*0 + 12, tmpq, m6, m7
+    LOAD64_LUT  m3, inq, lutq, (mmsize/2)*1 + 12, tmpq, m14, m15
+    LOAD64_LUT  m4, inq, lutq, (mmsize/2)*2 + 12, tmpq, m6, m7
+    mov tmpd, [lutq + 8]
+    movddup xm5, [inq + tmpq*8]     ; in[2].reimreim
+%endif
+
+    FFT15
+
+    lea tgt5q, [tgtq + stride5q]
+    lea tmpq,  [tgtq + stride5q*2]
+
+    movhps [tgtq], xm14              ; out[0]
+    movhps [tgtq + stride5q*1], xm15 ; out[5]
+    movlps [tgtq + stride5q*2], xm15 ; out[10]
+
+    vextractf128 xm3, m0, 1
+    vextractf128 xm4, m1, 1
+    vextractf128 xm5, m2, 1
+
+    movlps [tgtq  + strideq*1],  xm1
+    movhps [tgtq  + strideq*2],  xm2
+    movlps [tgtq  + stride3q*1], xm3
+    movhps [tgtq  + strideq*4],  xm4
+    movlps [tgtq  + stride3q*2], xm0
+    movlps [tgtq  + strideq*8],  xm5
+    movhps [tgtq  + stride3q*4], xm0
+    movhps [tgt5q + strideq*2],  xm1
+    movhps [tgt5q + strideq*4],  xm3
+    movlps [tmpq  + strideq*1],  xm2
+    movlps [tmpq  + stride3q*1], xm4
+    movhps [tmpq  + strideq*4],  xm5
+
+%if %2
+    add inq, mmsize*3 + 24
+%else
+    add lutq, (mmsize/2)*3 + 12
+%endif
+    add mapq, 4
+    sub lenq, 15
+    jg .dim1
+
+    ; Second transform setup
+    mov stride5q, ctxq                              ; backup original context
+    movsxd stride3q, dword [ctxq + AVTXContext.len] ; full length
+    mov tgt5q, [ctxq + AVTXContext.fn]              ; subtransform's jump point
+
+    mov inq, outq                                   ; in-place transform
+    mov ctxq, [ctxq + AVTXContext.sub]              ; load subtransform's context
+    mov lutq, [ctxq + AVTXContext.map]              ; load subtransform's map
+    movsxd lenq, dword [ctxq + AVTXContext.len]     ; load subtransform's length
+
+.dim2:
+    call tgt5q                                      ; call the FFT
+    lea inq,  [inq  + lenq*8]
+    lea outq, [outq + lenq*8]
+    sub stride3q, lenq
+    jg .dim2
+
+    mov ctxq, stride5q                              ; restore original context
+    mov lutq, [ctxq + AVTXContext.map]
+    mov inq,  [ctxq + AVTXContext.tmp]
+    movsxd lenq, dword [ctxq + AVTXContext.len]     ; full length
+
+    lea stride3q, [lutq + lenq*4]                   ; second part of the LUT
+    mov stride5q, lenq
+    mov tgt5q, btmpq
+    POP strideq
+    lea tmpq, [strideq + 2*strideq]
+
+.post:
+    LOAD64_LUT m0, inq, stride3q, 0, tmpq, m8, m9
+    vextractf128 xm1, m0, 1
+    movlps [tgt5q], xm0
+    movhps [tgt5q + strideq], xm0
+    movlps [tgt5q + strideq*2], xm1
+    movhps [tgt5q + tmpq], xm1
+
+    lea tgt5q, [tgt5q + 4*strideq]
+    add stride3q, mmsize/2
+    sub stride5q, mmsize/8
+    jg .post
+
+%if %2
+    mov outq, btmpq
+    POP btmpq
+    POP stride5q
+    POP stride3q
+    POP tgt5q
+    POP inq
+    ret
+%else
+    RET
+%endif
+
+%if %2
+cglobal fft_pfa_15xM_ns_float, 4, 14, 16, 320, ctx, out, in, stride, len, lut, buf, map, tgt, tmp, \
+                                               tgt5, stride3, stride5, btmp
+    movsxd lenq, dword [ctxq + AVTXContext.len]
+    mov lutq, [ctxq + AVTXContext.map]
+
+    call mangle(ff_tx_fft_pfa_15xM_asm_float)
+    RET
+%endif
+%endmacro
+
+%if ARCH_X86_64
+PFA_15_FN avx2, 0
+PFA_15_FN avx2, 1
+%endif
diff --git a/libs/ffmpeg/libavutil/x86/tx_float_init.c b/libs/ffmpeg/libavutil/x86/tx_float_init.c
new file mode 100644
index 000000000000..05f8d7dc1bc0
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/tx_float_init.c
@@ -0,0 +1,313 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#define TX_FLOAT
+#include "libavutil/tx_priv.h"
+#include "libavutil/attributes.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/cpu.h"
+
+#include "config.h"
+
+TX_DECL_FN(fft2,      sse3)
+TX_DECL_FN(fft4_fwd,  sse2)
+TX_DECL_FN(fft4_inv,  sse2)
+TX_DECL_FN(fft8,      sse3)
+TX_DECL_FN(fft8_ns,   sse3)
+TX_DECL_FN(fft8,      avx)
+TX_DECL_FN(fft8_ns,   avx)
+TX_DECL_FN(fft15,     avx2)
+TX_DECL_FN(fft15_ns,  avx2)
+TX_DECL_FN(fft16,     avx)
+TX_DECL_FN(fft16_ns,  avx)
+TX_DECL_FN(fft16,     fma3)
+TX_DECL_FN(fft16_ns,  fma3)
+TX_DECL_FN(fft32,     avx)
+TX_DECL_FN(fft32_ns,  avx)
+TX_DECL_FN(fft32,     fma3)
+TX_DECL_FN(fft32_ns,  fma3)
+TX_DECL_FN(fft_sr,    avx)
+TX_DECL_FN(fft_sr_ns, avx)
+TX_DECL_FN(fft_sr,    fma3)
+TX_DECL_FN(fft_sr_ns, fma3)
+TX_DECL_FN(fft_sr,    avx2)
+TX_DECL_FN(fft_sr_ns, avx2)
+
+TX_DECL_FN(fft_pfa_15xM, avx2)
+TX_DECL_FN(fft_pfa_15xM_ns, avx2)
+
+TX_DECL_FN(mdct_inv, avx2)
+
+TX_DECL_FN(fft2_asm, sse3)
+TX_DECL_FN(fft4_fwd_asm, sse2)
+TX_DECL_FN(fft4_inv_asm, sse2)
+TX_DECL_FN(fft8_asm, sse3)
+TX_DECL_FN(fft8_asm, avx)
+TX_DECL_FN(fft16_asm, avx)
+TX_DECL_FN(fft16_asm, fma3)
+TX_DECL_FN(fft32_asm, avx)
+TX_DECL_FN(fft32_asm, fma3)
+TX_DECL_FN(fft_sr_asm, avx)
+TX_DECL_FN(fft_sr_asm, fma3)
+TX_DECL_FN(fft_sr_asm, avx2)
+
+TX_DECL_FN(fft_pfa_15xM_asm, avx2)
+
+#define DECL_INIT_FN(basis, interleave)                                        \
+static av_cold int b ##basis## _i ##interleave(AVTXContext *s,                 \
+                                               const FFTXCodelet *cd,          \
+                                               uint64_t flags,                 \
+                                               FFTXCodeletOptions *opts,       \
+                                               int len, int inv,               \
+                                               const void *scale)              \
+{                                                                              \
+    ff_tx_init_tabs_float(len);                                                \
+    if (cd->max_len == 2)                                                      \
+        return ff_tx_gen_ptwo_revtab(s, opts);                                 \
+    else                                                                       \
+        return ff_tx_gen_split_radix_parity_revtab(s, len, inv, opts,          \
+                                                   basis, interleave);         \
+}
+
+DECL_INIT_FN(8, 0)
+DECL_INIT_FN(8, 2)
+
+static av_cold int factor_init(AVTXContext *s, const FFTXCodelet *cd,
+                               uint64_t flags, FFTXCodeletOptions *opts,
+                               int len, int inv, const void *scale)
+{
+    int ret;
+
+    /* The transformations below are performed in the gather domain,
+     * so override the option and let the infrastructure convert the map
+     * to SCATTER if needed. */
+    FFTXCodeletOptions sub_opts = { .map_dir = FF_TX_MAP_GATHER };
+
+    TX_TAB(ff_tx_init_tabs)(len);
+
+    if (len == 15)
+        ret = ff_tx_gen_pfa_input_map(s, &sub_opts, 3, 5);
+    else
+        ret = ff_tx_gen_default_map(s, &sub_opts);
+
+    if (ret < 0)
+        return ret;
+
+    if (len == 15) {
+        int cnt = 0, tmp[15];
+
+        /* Special permutation to simplify loads in the pre-permuted version */
+        memcpy(tmp, s->map, 15*sizeof(*tmp));
+        for (int i = 1; i < 15; i += 3) {
+            s->map[cnt] = tmp[i];
+            cnt++;
+        }
+        for (int i = 2; i < 15; i += 3) {
+            s->map[cnt] = tmp[i];
+            cnt++;
+        }
+        for (int i = 0; i < 15; i += 3) {
+            s->map[cnt] = tmp[i];
+            cnt++;
+        }
+        memmove(&s->map[7], &s->map[6], 4*sizeof(int));
+        memmove(&s->map[3], &s->map[1], 4*sizeof(int));
+        s->map[1] = tmp[2];
+        s->map[2] = tmp[0];
+    }
+
+    return 0;
+}
+
+static av_cold int m_inv_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 = 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;   /* This function handles the permute step */
+    flags |=  FF_TX_ASM_CALL;     /* We want an assembly function, not C */
+
+    if ((ret = ff_tx_init_subtx(s, TX_TYPE(FFT), flags, &sub_opts, len >> 1,
+                                inv, scale)))
+        return ret;
+
+    s->map = av_malloc(len*sizeof(*s->map));
+    if (!s->map)
+        return AVERROR(ENOMEM);
+
+    memcpy(s->map, s->sub->map, (len >> 1)*sizeof(*s->map));
+    /* Invert lookup table for unstrided path */
+    for (int i = 0; i < (len >> 1); i++)
+       s->map[(len >> 1) + s->map[i]] = i;
+
+    if ((ret = ff_tx_mdct_gen_exp_float(s, s->map)))
+        return ret;
+
+    return 0;
+}
+
+static av_cold int fft_pfa_init(AVTXContext *s,
+                                const FFTXCodelet *cd,
+                                uint64_t flags,
+                                FFTXCodeletOptions *opts,
+                                int len, int inv,
+                                const void *scale)
+{
+    int ret;
+    int sub_len = len / cd->factors[0];
+    FFTXCodeletOptions sub_opts = { .map_dir = FF_TX_MAP_SCATTER };
+
+    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 */
+    flags |=  FF_TX_ASM_CALL;     /* We want an assembly function, not C */
+
+    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;
+
+    if (cd->factors[0] == 15) {
+        int tmp[15];
+
+        /* Our 15-point transform is also a compound one, so embed its input map */
+        TX_EMBED_INPUT_PFA_MAP(s->map, len, 3, 5);
+
+        /* Special permutation to simplify loads in the pre-permuted version */
+        for (int k = 0; k < s->sub[0].len; k++) {
+            int cnt = 0;
+            memcpy(tmp, &s->map[k*15], 15*sizeof(*tmp));
+            for (int i = 1; i < 15; i += 3) {
+                s->map[k*15 + cnt] = tmp[i];
+                cnt++;
+            }
+            for (int i = 2; i < 15; i += 3) {
+                s->map[k*15 + cnt] = tmp[i];
+                cnt++;
+            }
+            for (int i = 0; i < 15; i += 3) {
+                s->map[k*15 + cnt] = tmp[i];
+                cnt++;
+            }
+            memmove(&s->map[k*15 + 7], &s->map[k*15 + 6], 4*sizeof(int));
+            memmove(&s->map[k*15 + 3], &s->map[k*15 + 1], 4*sizeof(int));
+            s->map[k*15 + 1] = tmp[2];
+            s->map[k*15 + 2] = tmp[0];
+        }
+    }
+
+    if (!(s->tmp = av_malloc(len*sizeof(*s->tmp))))
+        return AVERROR(ENOMEM);
+
+    TX_TAB(ff_tx_init_tabs)(len / sub_len);
+
+    return 0;
+}
+
+const FFTXCodelet * const ff_tx_codelet_list_float_x86[] = {
+    TX_DEF(fft2,     FFT,  2,  2, 2, 0, 128, NULL,  sse3, SSE3, AV_TX_INPLACE, 0),
+    TX_DEF(fft2_asm, FFT,  2,  2, 2, 0, 192, b8_i0, sse3, SSE3,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, 0),
+    TX_DEF(fft2,     FFT,  2,  2, 2, 0, 192, b8_i0, sse3, SSE3, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft4_fwd, FFT,  4,  4, 2, 0, 128, NULL,  sse2, SSE2, AV_TX_INPLACE | FF_TX_FORWARD_ONLY, 0),
+    TX_DEF(fft4_fwd_asm, FFT,  4,  4, 2, 0, 192, b8_i0, sse2, SSE2,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, 0),
+    TX_DEF(fft4_inv_asm, FFT,  4,  4, 2, 0, 128, NULL,  sse2, SSE2,
+           AV_TX_INPLACE | FF_TX_INVERSE_ONLY | FF_TX_ASM_CALL, 0),
+    TX_DEF(fft4_fwd, FFT,  4,  4, 2, 0, 192, b8_i0, sse2, SSE2, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft4_inv, FFT,  4,  4, 2, 0, 128, NULL,  sse2, SSE2, AV_TX_INPLACE | FF_TX_INVERSE_ONLY, 0),
+    TX_DEF(fft8,     FFT,  8,  8, 2, 0, 128, b8_i0, sse3, SSE3, AV_TX_INPLACE, 0),
+    TX_DEF(fft8_asm, FFT,  8,  8, 2, 0, 192, b8_i0, sse3, SSE3,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, 0),
+    TX_DEF(fft8_ns,  FFT,  8,  8, 2, 0, 192, b8_i0, sse3, SSE3, AV_TX_INPLACE | FF_TX_PRESHUFFLE, 0),
+    TX_DEF(fft8,     FFT,  8,  8, 2, 0, 256, b8_i0, avx,  AVX,  AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft8_asm, FFT,  8,  8, 2, 0, 320, b8_i0, avx,  AVX,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft8_ns,  FFT,  8,  8, 2, 0, 320, b8_i0, avx,  AVX,  AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16,    FFT, 16, 16, 2, 0, 256, b8_i2, avx,  AVX,  AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16_asm, FFT, 16, 16, 2, 0, 320, b8_i2, avx,  AVX,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16_ns, FFT, 16, 16, 2, 0, 320, b8_i2, avx,  AVX,  AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16,    FFT, 16, 16, 2, 0, 288, b8_i2, fma3, FMA3, AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16_asm, FFT, 16, 16, 2, 0, 352, b8_i2, fma3, FMA3,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft16_ns, FFT, 16, 16, 2, 0, 352, b8_i2, fma3, FMA3, AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+
+#if ARCH_X86_64
+    TX_DEF(fft32,    FFT, 32, 32, 2, 0, 256, b8_i2, avx,  AVX,  AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft32_asm, FFT, 32, 32, 2, 0, 320, b8_i2, avx,  AVX,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft32_ns, FFT, 32, 32, 2, 0, 320, b8_i2, avx,  AVX,  AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft32,    FFT, 32, 32, 2, 0, 288, b8_i2, fma3, FMA3, AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft32_asm, FFT, 32, 32, 2, 0, 352, b8_i2, fma3, FMA3,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft32_ns, FFT, 32, 32, 2, 0, 352, b8_i2, fma3, FMA3, AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr,    FFT, 64, 131072, 2, 0, 256, b8_i2, avx, AVX,  0, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr_asm, FFT, 64, 131072, 2, 0, 320, b8_i2, avx, AVX,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr_ns, FFT, 64, 131072, 2, 0, 320, b8_i2, avx, AVX,  AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr,    FFT, 64, 131072, 2, 0, 288, b8_i2, fma3,  FMA3,  0, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr_asm, FFT, 64, 131072, 2, 0, 352, b8_i2, fma3,  FMA3,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft_sr_ns, FFT, 64, 131072, 2, 0, 352, b8_i2, fma3,  FMA3,  AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW),
+
+    TX_DEF(fft15, FFT, 15, 15, 15, 0, 320, factor_init, avx2, AVX2,
+           AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW),
+    TX_DEF(fft15_ns, FFT, 15, 15, 15, 0, 384, factor_init, avx2, AVX2,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE, AV_CPU_FLAG_AVXSLOW),
+
+    TX_DEF(fft_sr,    FFT, 64, 131072, 2, 0, 320, b8_i2, avx2, AVX2, 0,
+           AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+    TX_DEF(fft_sr_asm, FFT, 64, 131072, 2, 0, 384, b8_i2, avx2, AVX2,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+    TX_DEF(fft_sr_ns, FFT, 64, 131072, 2, 0, 384, b8_i2, avx2, AVX2, AV_TX_INPLACE | FF_TX_PRESHUFFLE,
+           AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+
+    TX_DEF(fft_pfa_15xM, FFT, 60, TX_LEN_UNLIMITED, 15, 2, 320, fft_pfa_init, avx2, AVX2,
+           AV_TX_INPLACE, AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+    TX_DEF(fft_pfa_15xM_asm, FFT, 60, TX_LEN_UNLIMITED, 15, 2, 384, fft_pfa_init, avx2, AVX2,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE | FF_TX_ASM_CALL, AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+    TX_DEF(fft_pfa_15xM_ns, FFT, 60, TX_LEN_UNLIMITED, 15, 2, 384, fft_pfa_init, avx2, AVX2,
+           AV_TX_INPLACE | FF_TX_PRESHUFFLE, AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+
+    TX_DEF(mdct_inv, MDCT, 16, TX_LEN_UNLIMITED, 2, TX_FACTOR_ANY, 384, m_inv_init, avx2, AVX2,
+           FF_TX_INVERSE_ONLY, AV_CPU_FLAG_AVXSLOW | AV_CPU_FLAG_SLOW_GATHER),
+#endif
+
+    NULL,
+};
+
+#endif
diff --git a/libs/ffmpeg/libavutil/x86/x86inc.asm b/libs/ffmpeg/libavutil/x86/x86inc.asm
new file mode 100644
index 000000000000..731669801355
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/x86inc.asm
@@ -0,0 +1,2004 @@
+;*****************************************************************************
+;* x86inc.asm: x86 abstraction layer
+;*****************************************************************************
+;* Copyright (C) 2005-2024 x264 project
+;*
+;* Authors: Loren Merritt <lorenm@u.washington.edu>
+;*          Henrik Gramner <henrik@gramner.com>
+;*          Anton Mitrofanov <BugMaster@narod.ru>
+;*          Fiona Glaser <fiona@x264.com>
+;*
+;* Permission to use, copy, modify, and/or distribute this software for any
+;* purpose with or without fee is hereby granted, provided that the above
+;* copyright notice and this permission notice appear in all copies.
+;*
+;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+;*****************************************************************************
+
+; This is a header file for the x86inc.asm assembly language, which uses
+; NASM/YASM syntax combined with a large number of macros to provide easy
+; abstraction between different calling conventions (x86_32, win64, linux64).
+; It also has various other useful features to simplify writing the kind of
+; DSP functions that are most often used.
+
+;; config tweaks for Wine build
+%pragma makedep header
+
+%define HAVE_AVX_EXTERNAL 1
+%define HAVE_AVX2_EXTERNAL 1
+%define HAVE_AVX512ICL_EXTERNAL 1
+%define HAVE_FMA3_EXTERNAL 1
+%define HAVE_FMA4_EXTERNAL 1
+%define HAVE_MMXEXT_EXTERNAL 1
+%define HAVE_SSE_EXTERNAL 1
+%define HAVE_SSE2_EXTERNAL 1
+%define HAVE_SSE3_EXTERNAL 1
+%define HAVE_XOP_EXTERNAL 1
+
+%ifidn __OUTPUT_FORMAT__,win32
+%define ARCH_X86_32 1
+%define ARCH_X86_64 0
+%define PREFIX _
+%define HAVE_ALIGNED_STACK 0
+%else
+%define ARCH_X86_32 0
+%define ARCH_X86_64 1
+%define HAVE_ALIGNED_STACK 1
+%endif
+;; end of config tweaks for Wine build
+
+%ifndef private_prefix
+    %error private_prefix not defined
+%endif
+
+%ifndef public_prefix
+    %define public_prefix private_prefix
+%endif
+
+%if HAVE_ALIGNED_STACK
+    %define STACK_ALIGNMENT 16
+%endif
+%ifndef STACK_ALIGNMENT
+    %if ARCH_X86_64
+        %define STACK_ALIGNMENT 16
+    %else
+        %define STACK_ALIGNMENT 4
+    %endif
+%endif
+
+%define WIN64  0
+%define UNIX64 0
+%if ARCH_X86_64
+    %ifidn __OUTPUT_FORMAT__,win32
+        %define WIN64  1
+    %elifidn __OUTPUT_FORMAT__,win64
+        %define WIN64  1
+    %elifidn __OUTPUT_FORMAT__,x64
+        %define WIN64  1
+    %else
+        %define UNIX64 1
+    %endif
+%endif
+
+%define FORMAT_ELF 0
+%define FORMAT_MACHO 0
+%ifidn __OUTPUT_FORMAT__,elf
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,elf32
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,elf64
+    %define FORMAT_ELF 1
+%elifidn __OUTPUT_FORMAT__,macho
+    %define FORMAT_MACHO 1
+%elifidn __OUTPUT_FORMAT__,macho32
+    %define FORMAT_MACHO 1
+%elifidn __OUTPUT_FORMAT__,macho64
+    %define FORMAT_MACHO 1
+%endif
+
+%ifdef PREFIX
+    %define mangle(x) _ %+ x
+%else
+    %define mangle(x) x
+%endif
+
+; Use VEX-encoding even in non-AVX functions
+%ifndef FORCE_VEX_ENCODING
+    %define FORCE_VEX_ENCODING 0
+%endif
+
+; aout does not support align=
+; NOTE: This section is out of sync with x264, in order to
+; keep supporting OS/2.
+%macro SECTION_RODATA 0-1 16
+    %ifidn __OUTPUT_FORMAT__,aout
+        SECTION .text
+    %elifidn __OUTPUT_FORMAT__,coff
+        SECTION .text
+    %elifidn __OUTPUT_FORMAT__,win32
+        SECTION .rdata align=%1
+    %elif WIN64
+        SECTION .rdata align=%1
+    %else
+        SECTION .rodata align=%1
+    %endif
+%endmacro
+
+%if ARCH_X86_64
+    %define PIC 1 ; always use PIC on x86-64
+    default rel
+%elifidn __OUTPUT_FORMAT__,win32
+    %define PIC 0 ; PIC isn't used on 32-bit Windows
+%elifndef PIC
+    %define PIC 0
+%endif
+
+%define HAVE_PRIVATE_EXTERN 1
+%ifdef __NASM_VERSION_ID__
+    %use smartalign
+    %if __NASM_VERSION_ID__ < 0x020e0000 ; 2.14
+        %define HAVE_PRIVATE_EXTERN 0
+    %endif
+%endif
+
+; Macros to eliminate most code duplication between x86_32 and x86_64:
+; Currently this works only for leaf functions which load all their arguments
+; into registers at the start, and make no other use of the stack. Luckily that
+; covers most use cases.
+
+; PROLOGUE:
+; %1 = number of arguments. loads them from stack if needed.
+; %2 = number of registers used. pushes callee-saved regs if needed.
+; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed.
+; %4 = (optional) stack size to be allocated. The stack will be aligned before
+;      allocating the specified stack size. If the required stack alignment is
+;      larger than the known stack alignment the stack will be manually aligned
+;      and an extra register will be allocated to hold the original stack
+;      pointer (to not invalidate r0m etc.). To prevent the use of an extra
+;      register as stack pointer, request a negative stack size.
+; %4+/%5+ = list of names to define to registers
+; PROLOGUE can also be invoked by adding the same options to cglobal
+
+; e.g.
+; cglobal foo, 2,3,7,0x40, dst, src, tmp
+; declares a function (foo) that automatically loads two arguments (dst and
+; src) into registers, uses one additional register (tmp) plus 7 vector
+; registers (m0-m6) and allocates 0x40 bytes of stack space.
+
+; TODO Some functions can use some args directly from the stack. If they're the
+; last args then you can just not declare them, but if they're in the middle
+; we need more flexible macro.
+
+; RET:
+; Pops anything that was pushed by PROLOGUE, and returns.
+
+; REP_RET:
+; Use this instead of RET if it's a branch target.
+
+; registers:
+; rN and rNq are the native-size register holding function argument N
+; rNd, rNw, rNb are dword, word, and byte size
+; rNh is the high 8 bits of the word size
+; rNm is the original location of arg N (a register or on the stack), dword
+; rNmp is native size
+
+%macro DECLARE_REG 2-3
+    %define r%1q %2
+    %define r%1d %2d
+    %define r%1w %2w
+    %define r%1b %2b
+    %define r%1h %2h
+    %define %2q %2
+    %if %0 == 2
+        %define r%1m  %2d
+        %define r%1mp %2
+    %elif ARCH_X86_64 ; memory
+        %define r%1m [rstk + stack_offset + %3]
+        %define r%1mp qword r %+ %1 %+ m
+    %else
+        %define r%1m [rstk + stack_offset + %3]
+        %define r%1mp dword r %+ %1 %+ m
+    %endif
+    %define r%1  %2
+%endmacro
+
+%macro DECLARE_REG_SIZE 3
+    %define r%1q r%1
+    %define e%1q r%1
+    %define r%1d e%1
+    %define e%1d e%1
+    %define r%1w %1
+    %define e%1w %1
+    %define r%1h %3
+    %define e%1h %3
+    %define r%1b %2
+    %define e%1b %2
+    %if ARCH_X86_64 == 0
+        %define r%1 e%1
+    %endif
+%endmacro
+
+DECLARE_REG_SIZE ax, al, ah
+DECLARE_REG_SIZE bx, bl, bh
+DECLARE_REG_SIZE cx, cl, ch
+DECLARE_REG_SIZE dx, dl, dh
+DECLARE_REG_SIZE si, sil, null
+DECLARE_REG_SIZE di, dil, null
+DECLARE_REG_SIZE bp, bpl, null
+
+; t# defines for when per-arch register allocation is more complex than just function arguments
+
+%macro DECLARE_REG_TMP 1-*
+    %assign %%i 0
+    %rep %0
+        CAT_XDEFINE t, %%i, r%1
+        %assign %%i %%i+1
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro DECLARE_REG_TMP_SIZE 0-*
+    %rep %0
+        %define t%1q t%1 %+ q
+        %define t%1d t%1 %+ d
+        %define t%1w t%1 %+ w
+        %define t%1h t%1 %+ h
+        %define t%1b t%1 %+ b
+        %rotate 1
+    %endrep
+%endmacro
+
+DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14
+
+%if ARCH_X86_64
+    %define gprsize 8
+%else
+    %define gprsize 4
+%endif
+
+%macro LEA 2
+%if ARCH_X86_64
+    lea %1, [%2]
+%elif PIC
+    call $+5 ; special-cased to not affect the RSB on most CPU:s
+    pop %1
+    add %1, (%2)-$+1
+%else
+    mov %1, %2
+%endif
+%endmacro
+
+; Repeats an instruction/operation for multiple arguments.
+; Example usage: "REPX {psrlw x, 8}, m0, m1, m2, m3"
+%macro REPX 2-* ; operation, args
+    %xdefine %%f(x) %1
+    %rep %0 - 1
+        %rotate 1
+        %%f(%1)
+    %endrep
+%endmacro
+
+%macro PUSH 1
+    push %1
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset+gprsize
+    %endif
+%endmacro
+
+%macro POP 1
+    pop %1
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset-gprsize
+    %endif
+%endmacro
+
+%macro PUSH_IF_USED 1-*
+    %rep %0
+        %if %1 < regs_used
+            PUSH r%1
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro POP_IF_USED 1-*
+    %rep %0
+        %if %1 < regs_used
+            pop r%1
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro LOAD_IF_USED 1-*
+    %rep %0
+        %if %1 < num_args
+            mov r%1, r %+ %1 %+ mp
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SUB 2
+    sub %1, %2
+    %ifidn %1, rstk
+        %assign stack_offset stack_offset+(%2)
+    %endif
+%endmacro
+
+%macro ADD 2
+    add %1, %2
+    %ifidn %1, rstk
+        %assign stack_offset stack_offset-(%2)
+    %endif
+%endmacro
+
+%macro movifnidn 2
+    %ifnidn %1, %2
+        mov %1, %2
+    %endif
+%endmacro
+
+%if ARCH_X86_64 == 0
+    %define movsxd movifnidn
+%endif
+
+%macro movsxdifnidn 2
+    %ifnidn %1, %2
+        movsxd %1, %2
+    %endif
+%endmacro
+
+%macro ASSERT 1
+    %if (%1) == 0
+        %error assertion ``%1'' failed
+    %endif
+%endmacro
+
+%macro DEFINE_ARGS 0-*
+    %ifdef n_arg_names
+        %assign %%i 0
+        %rep n_arg_names
+            CAT_UNDEF arg_name %+ %%i, q
+            CAT_UNDEF arg_name %+ %%i, d
+            CAT_UNDEF arg_name %+ %%i, w
+            CAT_UNDEF arg_name %+ %%i, h
+            CAT_UNDEF arg_name %+ %%i, b
+            CAT_UNDEF arg_name %+ %%i, m
+            CAT_UNDEF arg_name %+ %%i, mp
+            CAT_UNDEF arg_name, %%i
+            %assign %%i %%i+1
+        %endrep
+    %endif
+
+    %xdefine %%stack_offset stack_offset
+    %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine
+    %assign %%i 0
+    %rep %0
+        %xdefine %1q r %+ %%i %+ q
+        %xdefine %1d r %+ %%i %+ d
+        %xdefine %1w r %+ %%i %+ w
+        %xdefine %1h r %+ %%i %+ h
+        %xdefine %1b r %+ %%i %+ b
+        %xdefine %1m r %+ %%i %+ m
+        %xdefine %1mp r %+ %%i %+ mp
+        CAT_XDEFINE arg_name, %%i, %1
+        %assign %%i %%i+1
+        %rotate 1
+    %endrep
+    %xdefine stack_offset %%stack_offset
+    %assign n_arg_names %0
+%endmacro
+
+%define required_stack_alignment ((mmsize + 15) & ~15)
+%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512)))
+%define high_mm_regs (16*cpuflag(avx512))
+
+; Large stack allocations on Windows need to use stack probing in order
+; to guarantee that all stack memory is committed before accessing it.
+; This is done by ensuring that the guard page(s) at the end of the
+; currently committed pages are touched prior to any pages beyond that.
+%if WIN64
+    %assign STACK_PROBE_SIZE 8192
+%elifidn __OUTPUT_FORMAT__, win32
+    %assign STACK_PROBE_SIZE 4096
+%else
+    %assign STACK_PROBE_SIZE 0
+%endif
+
+%macro PROBE_STACK 1 ; stack_size
+    %if STACK_PROBE_SIZE
+        %assign %%i STACK_PROBE_SIZE
+        %rep %1 / STACK_PROBE_SIZE
+            mov eax, [rsp-%%i]
+            %assign %%i %%i+STACK_PROBE_SIZE
+        %endrep
+    %endif
+%endmacro
+
+%macro RESET_STACK_STATE 0
+    %ifidn rstk, rsp
+        %assign stack_offset stack_offset - stack_size_padded
+    %else
+        %xdefine rstk rsp
+    %endif
+    %assign stack_size 0
+    %assign stack_size_padded 0
+    %assign xmm_regs_used 0
+%endmacro
+
+%macro ALLOC_STACK 0-2 0, 0 ; stack_size, n_xmm_regs
+    RESET_STACK_STATE
+    %ifnum %2
+        %if mmsize != 8
+            %assign xmm_regs_used %2
+        %endif
+    %endif
+    %ifnum %1
+        %if %1 != 0
+            %assign %%pad 0
+            %assign stack_size %1
+            %if stack_size < 0
+                %assign stack_size -stack_size
+            %endif
+            %if WIN64
+                %assign %%pad %%pad + 32 ; shadow space
+                %if xmm_regs_used > 8
+                    %assign %%pad %%pad + (xmm_regs_used-8)*16 ; callee-saved xmm registers
+                %endif
+            %endif
+            %if required_stack_alignment <= STACK_ALIGNMENT
+                ; maintain the current stack alignment
+                %assign stack_size_padded stack_size + %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1))
+                PROBE_STACK stack_size_padded
+                SUB rsp, stack_size_padded
+            %else
+                %assign %%reg_num (regs_used - 1)
+                %xdefine rstk r %+ %%reg_num
+                ; align stack, and save original stack location directly above
+                ; it, i.e. in [rsp+stack_size_padded], so we can restore the
+                ; stack in a single instruction (i.e. mov rsp, rstk or mov
+                ; rsp, [rsp+stack_size_padded])
+                %if %1 < 0 ; need to store rsp on stack
+                    %xdefine rstkm [rsp + stack_size + %%pad]
+                    %assign %%pad %%pad + gprsize
+                %else ; can keep rsp in rstk during whole function
+                    %xdefine rstkm rstk
+                %endif
+                %assign stack_size_padded stack_size + ((%%pad + required_stack_alignment-1) & ~(required_stack_alignment-1))
+                PROBE_STACK stack_size_padded
+                mov rstk, rsp
+                and rsp, ~(required_stack_alignment-1)
+                sub rsp, stack_size_padded
+                movifnidn rstkm, rstk
+            %endif
+            WIN64_PUSH_XMM
+        %endif
+    %endif
+%endmacro
+
+%macro SETUP_STACK_POINTER 0-1 0
+    %ifnum %1
+        %if %1 != 0 && required_stack_alignment > STACK_ALIGNMENT
+            %if %1 > 0
+                ; Reserve an additional register for storing the original stack pointer, but avoid using
+                ; eax/rax for this purpose since it can potentially get overwritten as a return value.
+                %assign regs_used (regs_used + 1)
+                %if ARCH_X86_64 && regs_used == 7
+                    %assign regs_used 8
+                %elif ARCH_X86_64 == 0 && regs_used == 1
+                    %assign regs_used 2
+                %endif
+            %endif
+            %if ARCH_X86_64 && regs_used < 5 + UNIX64 * 3
+                ; Ensure that we don't clobber any registers containing arguments. For UNIX64 we also preserve r6 (rax)
+                ; since it's used as a hidden argument in vararg functions to specify the number of vector registers used.
+                %assign regs_used 5 + UNIX64 * 3
+            %endif
+        %endif
+    %endif
+%endmacro
+
+%if WIN64 ; Windows x64 ;=================================================
+
+DECLARE_REG 0,  rcx
+DECLARE_REG 1,  rdx
+DECLARE_REG 2,  R8
+DECLARE_REG 3,  R9
+DECLARE_REG 4,  R10, 40
+DECLARE_REG 5,  R11, 48
+DECLARE_REG 6,  rax, 56
+DECLARE_REG 7,  rdi, 64
+DECLARE_REG 8,  rsi, 72
+DECLARE_REG 9,  rbx, 80
+DECLARE_REG 10, rbp, 88
+DECLARE_REG 11, R14, 96
+DECLARE_REG 12, R15, 104
+DECLARE_REG 13, R12, 112
+DECLARE_REG 14, R13, 120
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 15
+    PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14
+    ALLOC_STACK %4, %3
+    %if mmsize != 8 && stack_size == 0
+        WIN64_SPILL_XMM %3
+    %endif
+    LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+; Push XMM registers to the stack. If no argument is specified all used register
+; will be pushed, otherwise only push previously unpushed registers.
+%macro WIN64_PUSH_XMM 0-2 ; new_xmm_regs_used, xmm_regs_pushed
+    %if mmsize != 8
+        %if %0 == 2
+            %assign %%pushed %2
+            %assign xmm_regs_used %1
+        %elif %0 == 1
+            %assign %%pushed xmm_regs_used
+            %assign xmm_regs_used %1
+        %else
+            %assign %%pushed 0
+        %endif
+        ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated.
+        %if %%pushed <= 6 + high_mm_regs && xmm_regs_used > 6 + high_mm_regs
+            movaps [rstk + stack_offset +  8], xmm6
+        %endif
+        %if %%pushed <= 7 + high_mm_regs && xmm_regs_used > 7 + high_mm_regs
+            movaps [rstk + stack_offset + 24], xmm7
+        %endif
+        %assign %%pushed %%pushed - high_mm_regs - 8
+        %if %%pushed < 0
+            %assign %%pushed 0
+        %endif
+        %assign %%regs_to_push xmm_regs_used - %%pushed - high_mm_regs - 8
+        %if %%regs_to_push > 0
+            ASSERT (%%regs_to_push + %%pushed) * 16 <= stack_size_padded - stack_size - 32
+            %assign %%i %%pushed + 8
+            %rep %%regs_to_push
+                movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i
+                %assign %%i %%i+1
+            %endrep
+        %endif
+    %endif
+%endmacro
+
+; Allocated stack space for XMM registers and push all, or a subset, of those
+%macro WIN64_SPILL_XMM 1-2 ; xmm_regs_used, xmm_regs_reserved
+    RESET_STACK_STATE
+    %if mmsize != 8
+        %assign xmm_regs_used %1
+        ASSERT xmm_regs_used <= 16 + high_mm_regs
+        %if %0 == 2
+            ASSERT %2 >= %1
+            %assign %%xmm_regs_on_stack %2 - high_mm_regs - 8
+        %else
+            %assign %%xmm_regs_on_stack %1 - high_mm_regs - 8
+        %endif
+        %if %%xmm_regs_on_stack > 0
+            ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack.
+            %assign %%pad %%xmm_regs_on_stack*16 + 32
+            %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1))
+            SUB rsp, stack_size_padded
+        %endif
+        WIN64_PUSH_XMM
+    %endif
+%endmacro
+
+%macro WIN64_RESTORE_XMM_INTERNAL 0
+    %assign %%pad_size 0
+    %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8
+    %if %%xmm_regs_on_stack > 0
+        %assign %%i xmm_regs_used - high_mm_regs
+        %rep %%xmm_regs_on_stack
+            %assign %%i %%i-1
+            movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32]
+        %endrep
+    %endif
+    %if stack_size_padded > 0
+        %if stack_size > 0 && required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+            %assign %%pad_size stack_size_padded
+        %endif
+    %endif
+    %if xmm_regs_used > 7 + high_mm_regs
+        movaps xmm7, [rsp + stack_offset - %%pad_size + 24]
+    %endif
+    %if xmm_regs_used > 6 + high_mm_regs
+        movaps xmm6, [rsp + stack_offset - %%pad_size +  8]
+    %endif
+%endmacro
+
+%macro WIN64_RESTORE_XMM 0
+    WIN64_RESTORE_XMM_INTERNAL
+    RESET_STACK_STATE
+%endmacro
+
+%define has_epilogue (regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs)
+
+%macro RET 0
+    WIN64_RESTORE_XMM_INTERNAL
+    POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%elif ARCH_X86_64 ; *nix x64 ;=============================================
+
+DECLARE_REG 0,  rdi
+DECLARE_REG 1,  rsi
+DECLARE_REG 2,  rdx
+DECLARE_REG 3,  rcx
+DECLARE_REG 4,  R8
+DECLARE_REG 5,  R9
+DECLARE_REG 6,  rax, 8
+DECLARE_REG 7,  R10, 16
+DECLARE_REG 8,  R11, 24
+DECLARE_REG 9,  rbx, 32
+DECLARE_REG 10, rbp, 40
+DECLARE_REG 11, R14, 48
+DECLARE_REG 12, R15, 56
+DECLARE_REG 13, R12, 64
+DECLARE_REG 14, R13, 72
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 15
+    PUSH_IF_USED 9, 10, 11, 12, 13, 14
+    ALLOC_STACK %4, %3
+    LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+%define has_epilogue (regs_used > 9 || stack_size > 0 || vzeroupper_required)
+
+%macro RET 0
+    %if stack_size_padded > 0
+        %if required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+        %endif
+    %endif
+    POP_IF_USED 14, 13, 12, 11, 10, 9
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%else ; X86_32 ;==============================================================
+
+DECLARE_REG 0, eax, 4
+DECLARE_REG 1, ecx, 8
+DECLARE_REG 2, edx, 12
+DECLARE_REG 3, ebx, 16
+DECLARE_REG 4, esi, 20
+DECLARE_REG 5, edi, 24
+DECLARE_REG 6, ebp, 28
+%define rsp esp
+
+%macro DECLARE_ARG 1-*
+    %rep %0
+        %define r%1m [rstk + stack_offset + 4*%1 + 4]
+        %define r%1mp dword r%1m
+        %rotate 1
+    %endrep
+%endmacro
+
+DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14
+
+%macro PROLOGUE 2-5+ 0, 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names...
+    %assign num_args %1
+    %assign regs_used %2
+    ASSERT regs_used >= num_args
+    %if num_args > 7
+        %assign num_args 7
+    %endif
+    %if regs_used > 7
+        %assign regs_used 7
+    %endif
+    SETUP_STACK_POINTER %4
+    ASSERT regs_used <= 7
+    PUSH_IF_USED 3, 4, 5, 6
+    ALLOC_STACK %4, %3
+    LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6
+    %if %0 > 4
+        %ifnum %4
+            DEFINE_ARGS %5
+        %else
+            DEFINE_ARGS %4, %5
+        %endif
+    %elifnnum %4
+        DEFINE_ARGS %4
+    %endif
+%endmacro
+
+%define has_epilogue (regs_used > 3 || stack_size > 0 || vzeroupper_required)
+
+%macro RET 0
+    %if stack_size_padded > 0
+        %if required_stack_alignment > STACK_ALIGNMENT
+            mov rsp, rstkm
+        %else
+            add rsp, stack_size_padded
+        %endif
+    %endif
+    POP_IF_USED 6, 5, 4, 3
+    %if vzeroupper_required
+        vzeroupper
+    %endif
+    AUTO_REP_RET
+%endmacro
+
+%endif ;======================================================================
+
+%if WIN64 == 0
+    %macro WIN64_SPILL_XMM 1-2
+        RESET_STACK_STATE
+        %if mmsize != 8
+            %assign xmm_regs_used %1
+        %endif
+    %endmacro
+    %macro WIN64_RESTORE_XMM 0
+        RESET_STACK_STATE
+    %endmacro
+    %macro WIN64_PUSH_XMM 0-2
+        %if mmsize != 8 && %0 >= 1
+            %assign xmm_regs_used %1
+        %endif
+    %endmacro
+%endif
+
+; On AMD cpus <=K10, an ordinary ret is slow if it immediately follows either
+; a branch or a branch target. So switch to a 2-byte form of ret in that case.
+; We can automatically detect "follows a branch", but not a branch target.
+; (SSSE3 is a sufficient condition to know that your cpu doesn't have this problem.)
+%macro REP_RET 0
+    %if has_epilogue || cpuflag(ssse3)
+        RET
+    %else
+        rep ret
+    %endif
+    annotate_function_size
+%endmacro
+
+%define last_branch_adr $$
+%macro AUTO_REP_RET 0
+    %if notcpuflag(ssse3)
+        times ((last_branch_adr-$)>>31)+1 rep ; times 1 iff $ == last_branch_adr.
+    %endif
+    ret
+    annotate_function_size
+%endmacro
+
+%macro BRANCH_INSTR 0-*
+    %rep %0
+        %macro %1 1-2 %1
+            %2 %1
+            %if notcpuflag(ssse3)
+                %%branch_instr equ $
+                %xdefine last_branch_adr %%branch_instr
+            %endif
+        %endmacro
+        %rotate 1
+    %endrep
+%endmacro
+
+BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, jna, jnae, jb, jbe, jnb, jnbe, jc, jnc, js, jns, jo, jno, jp, jnp
+
+%macro TAIL_CALL 1-2 1 ; callee, is_nonadjacent
+    %if has_epilogue
+        call %1
+        RET
+    %elif %2
+        jmp %1
+    %endif
+    annotate_function_size
+%endmacro
+
+;=============================================================================
+; arch-independent part
+;=============================================================================
+
+%assign function_align 16
+
+; Begin a function.
+; Applies any symbol mangling needed for C linkage, and sets up a define such that
+; subsequent uses of the function name automatically refer to the mangled version.
+; Appends cpuflags to the function name if cpuflags has been specified.
+; The "" empty default parameter is a workaround for nasm, which fails if SUFFIX
+; is empty and we call cglobal_internal with just %1 %+ SUFFIX (without %2).
+%macro cglobal 1-2+ "" ; name, [PROLOGUE args]
+    cglobal_internal 1, %1 %+ SUFFIX, %2
+%endmacro
+%macro cvisible 1-2+ "" ; name, [PROLOGUE args]
+    cglobal_internal 0, %1 %+ SUFFIX, %2
+%endmacro
+%macro cglobal_internal 2-3+
+    annotate_function_size
+    %ifndef cglobaled_%2
+        %if %1
+            %xdefine %2 mangle(private_prefix %+ _ %+ %2)
+        %else
+            %xdefine %2 mangle(public_prefix %+ _ %+ %2)
+        %endif
+        %xdefine %2.skip_prologue %2 %+ .skip_prologue
+        CAT_XDEFINE cglobaled_, %2, 1
+    %endif
+    %xdefine current_function %2
+    %xdefine current_function_section __SECT__
+    %if FORMAT_ELF
+        %if %1
+            global %2:function hidden
+        %else
+            global %2:function
+        %endif
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN && %1
+        global %2:private_extern
+    %else
+        global %2
+    %endif
+    align function_align
+    %2:
+    RESET_MM_PERMUTATION        ; needed for x86-64, also makes disassembly somewhat nicer
+    %xdefine rstk rsp           ; copy of the original stack pointer, used when greater alignment than the known stack alignment is required
+    %assign stack_offset 0      ; stack pointer offset relative to the return address
+    %assign stack_size 0        ; amount of stack space that can be freely used inside a function
+    %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding
+    %assign xmm_regs_used 0     ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper
+    %ifnidn %3, ""
+        PROLOGUE %3
+    %endif
+%endmacro
+
+; Create a global symbol from a local label with the correct name mangling and type
+%macro cglobal_label 1
+    %if FORMAT_ELF
+        global current_function %+ %1:function hidden
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN
+        global current_function %+ %1:private_extern
+    %else
+        global current_function %+ %1
+    %endif
+    %1:
+%endmacro
+
+%macro cextern 1
+    %xdefine %1 mangle(private_prefix %+ _ %+ %1)
+    CAT_XDEFINE cglobaled_, %1, 1
+    extern %1
+%endmacro
+
+; like cextern, but without the prefix
+%macro cextern_naked 1
+    %ifdef PREFIX
+        %xdefine %1 mangle(%1)
+    %endif
+    CAT_XDEFINE cglobaled_, %1, 1
+    extern %1
+%endmacro
+
+%macro const 1-2+
+    %xdefine %1 mangle(private_prefix %+ _ %+ %1)
+    %if FORMAT_ELF
+        global %1:data hidden
+    %elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN
+        global %1:private_extern
+    %else
+        global %1
+    %endif
+    %1: %2
+%endmacro
+
+%if FORMAT_ELF
+    ; The GNU linker assumes the stack is executable by default.
+    [SECTION .note.GNU-stack noalloc noexec nowrite progbits]
+
+    %ifdef __NASM_VERSION_ID__
+        %if __NASM_VERSION_ID__ >= 0x020e0300 ; 2.14.03
+            %if ARCH_X86_64
+                ; Control-flow Enforcement Technology (CET) properties.
+                [SECTION .note.gnu.property alloc noexec nowrite note align=gprsize]
+                dd 0x00000004  ; n_namesz
+                dd gprsize + 8 ; n_descsz
+                dd 0x00000005  ; n_type = NT_GNU_PROPERTY_TYPE_0
+                db "GNU",0     ; n_name
+                dd 0xc0000002  ; pr_type = GNU_PROPERTY_X86_FEATURE_1_AND
+                dd 0x00000004  ; pr_datasz
+                dd 0x00000002  ; pr_data = GNU_PROPERTY_X86_FEATURE_1_SHSTK
+                dd 0x00000000  ; pr_padding
+            %endif
+        %endif
+    %endif
+%endif
+
+; Tell debuggers how large the function was.
+; This may be invoked multiple times per function; we rely on later instances overriding earlier ones.
+; This is invoked by RET and similar macros, and also cglobal does it for the previous function,
+; but if the last function in a source file doesn't use any of the standard macros for its epilogue,
+; then its size might be unspecified.
+%macro annotate_function_size 0
+    %ifdef __YASM_VER__
+        %ifdef current_function
+            %if FORMAT_ELF
+                current_function_section
+                %%ecf equ $
+                size current_function %%ecf - current_function
+                __SECT__
+            %endif
+        %endif
+    %endif
+%endmacro
+
+; cpuflags
+
+%assign cpuflags_mmx       (1<<0)
+%assign cpuflags_mmx2      (1<<1)  | cpuflags_mmx
+%assign cpuflags_3dnow     (1<<2)  | cpuflags_mmx
+%assign cpuflags_3dnowext  (1<<3)  | cpuflags_3dnow
+%assign cpuflags_sse       (1<<4)  | cpuflags_mmx2
+%assign cpuflags_sse2      (1<<5)  | cpuflags_sse
+%assign cpuflags_sse2slow  (1<<6)  | cpuflags_sse2
+%assign cpuflags_lzcnt     (1<<7)  | cpuflags_sse2
+%assign cpuflags_sse3      (1<<8)  | cpuflags_sse2
+%assign cpuflags_ssse3     (1<<9)  | cpuflags_sse3
+%assign cpuflags_sse4      (1<<10) | cpuflags_ssse3
+%assign cpuflags_sse42     (1<<11) | cpuflags_sse4
+%assign cpuflags_aesni     (1<<12) | cpuflags_sse42
+%assign cpuflags_clmul     (1<<13) | cpuflags_sse42
+%assign cpuflags_gfni      (1<<14) | cpuflags_aesni|cpuflags_clmul
+%assign cpuflags_avx       (1<<15) | cpuflags_sse42
+%assign cpuflags_xop       (1<<16) | cpuflags_avx
+%assign cpuflags_fma4      (1<<17) | cpuflags_avx
+%assign cpuflags_fma3      (1<<18) | cpuflags_avx
+%assign cpuflags_bmi1      (1<<19) | cpuflags_avx|cpuflags_lzcnt
+%assign cpuflags_bmi2      (1<<20) | cpuflags_bmi1
+%assign cpuflags_avx2      (1<<21) | cpuflags_fma3|cpuflags_bmi2
+%assign cpuflags_avx512    (1<<22) | cpuflags_avx2 ; F, CD, BW, DQ, VL
+%assign cpuflags_avx512icl (1<<23) | cpuflags_avx512|cpuflags_gfni ; VNNI, IFMA, VBMI, VBMI2, VPOPCNTDQ, BITALG, VAES, VPCLMULQDQ
+
+%assign cpuflags_cache32   (1<<24)
+%assign cpuflags_cache64   (1<<25)
+%assign cpuflags_aligned   (1<<26) ; not a cpu feature, but a function variant
+%assign cpuflags_atom      (1<<27)
+
+; Returns a boolean value expressing whether or not the specified cpuflag is enabled.
+%define    cpuflag(x) (((((cpuflags & (cpuflags_ %+ x)) ^ (cpuflags_ %+ x)) - 1) >> 31) & 1)
+%define notcpuflag(x) (cpuflag(x) ^ 1)
+
+; Takes an arbitrary number of cpuflags from the above list.
+; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu.
+; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co.
+%macro INIT_CPUFLAGS 0-*
+    %xdefine SUFFIX
+    %undef cpuname
+    %assign cpuflags 0
+
+    %if %0 >= 1
+        %rep %0
+            %ifdef cpuname
+                %xdefine cpuname cpuname %+ _%1
+            %else
+                %xdefine cpuname %1
+            %endif
+            %assign cpuflags cpuflags | cpuflags_%1
+            %rotate 1
+        %endrep
+        %xdefine SUFFIX _ %+ cpuname
+
+        %if cpuflag(avx)
+            %assign avx_enabled 1
+        %endif
+        %if (mmsize == 16 && notcpuflag(sse2)) || (mmsize == 32 && notcpuflag(avx2))
+            %define mova movaps
+            %define movu movups
+            %define movnta movntps
+        %endif
+        %if cpuflag(aligned)
+            %define movu mova
+        %elif cpuflag(sse3) && notcpuflag(ssse3)
+            %define movu lddqu
+        %endif
+    %endif
+
+    %if ARCH_X86_64 || cpuflag(sse2)
+        %ifdef __NASM_VERSION_ID__
+            ALIGNMODE p6
+        %else
+            CPU amdnop
+        %endif
+    %else
+        %ifdef __NASM_VERSION_ID__
+            ALIGNMODE nop
+        %else
+            CPU basicnop
+        %endif
+    %endif
+%endmacro
+
+; Merge mmx, sse*, and avx*
+; m# is a simd register of the currently selected size
+; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m#
+; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m#
+; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m#
+; (All 4 remain in sync through SWAP.)
+
+%macro CAT_XDEFINE 3
+    %xdefine %1%2 %3
+%endmacro
+
+%macro CAT_UNDEF 2
+    %undef %1%2
+%endmacro
+
+%macro DEFINE_MMREGS 1 ; mmtype
+    %assign %%prev_mmregs 0
+    %ifdef num_mmregs
+        %assign %%prev_mmregs num_mmregs
+    %endif
+
+    %assign num_mmregs 8
+    %if ARCH_X86_64 && mmsize >= 16
+        %assign num_mmregs 16
+        %if cpuflag(avx512) || mmsize == 64
+            %assign num_mmregs 32
+        %endif
+    %endif
+
+    %assign %%i 0
+    %rep num_mmregs
+        CAT_XDEFINE m, %%i, %1 %+ %%i
+        CAT_XDEFINE nn%1, %%i, %%i
+        %assign %%i %%i+1
+    %endrep
+    %if %%prev_mmregs > num_mmregs
+        %rep %%prev_mmregs - num_mmregs
+            CAT_UNDEF m, %%i
+            CAT_UNDEF nn %+ mmtype, %%i
+            %assign %%i %%i+1
+        %endrep
+    %endif
+    %xdefine mmtype %1
+%endmacro
+
+; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper
+%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg
+    %if ARCH_X86_64 && cpuflag(avx512)
+        %assign %%i %1
+        %rep 16-%1
+            %assign %%i_high %%i+16
+            SWAP %%i, %%i_high
+            %assign %%i %%i+1
+        %endrep
+    %endif
+%endmacro
+
+%macro INIT_MMX 0-1+
+    %assign avx_enabled 0
+    %define RESET_MM_PERMUTATION INIT_MMX %1
+    %define mmsize 8
+    %define mova movq
+    %define movu movq
+    %define movh movd
+    %define movnta movntq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS mm
+%endmacro
+
+%macro INIT_XMM 0-1+
+    %assign avx_enabled FORCE_VEX_ENCODING
+    %define RESET_MM_PERMUTATION INIT_XMM %1
+    %define mmsize 16
+    %define mova movdqa
+    %define movu movdqu
+    %define movh movq
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS xmm
+    %if WIN64
+        AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers
+    %endif
+    %xdefine bcstw 1to8
+    %xdefine bcstd 1to4
+    %xdefine bcstq 1to2
+%endmacro
+
+%macro INIT_YMM 0-1+
+    %assign avx_enabled 1
+    %define RESET_MM_PERMUTATION INIT_YMM %1
+    %define mmsize 32
+    %define mova movdqa
+    %define movu movdqu
+    %undef movh
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS ymm
+    AVX512_MM_PERMUTATION
+    %xdefine bcstw 1to16
+    %xdefine bcstd 1to8
+    %xdefine bcstq 1to4
+%endmacro
+
+%macro INIT_ZMM 0-1+
+    %assign avx_enabled 1
+    %define RESET_MM_PERMUTATION INIT_ZMM %1
+    %define mmsize 64
+    %define mova movdqa
+    %define movu movdqu
+    %undef movh
+    %define movnta movntdq
+    INIT_CPUFLAGS %1
+    DEFINE_MMREGS zmm
+    AVX512_MM_PERMUTATION
+    %xdefine bcstw 1to32
+    %xdefine bcstd 1to16
+    %xdefine bcstq 1to8
+%endmacro
+
+INIT_XMM
+
+%macro DECLARE_MMCAST 1
+    %define  mmmm%1   mm%1
+    %define  mmxmm%1  mm%1
+    %define  mmymm%1  mm%1
+    %define  mmzmm%1  mm%1
+    %define xmmmm%1   mm%1
+    %define xmmxmm%1 xmm%1
+    %define xmmymm%1 xmm%1
+    %define xmmzmm%1 xmm%1
+    %define ymmmm%1   mm%1
+    %define ymmxmm%1 xmm%1
+    %define ymmymm%1 ymm%1
+    %define ymmzmm%1 ymm%1
+    %define zmmmm%1   mm%1
+    %define zmmxmm%1 xmm%1
+    %define zmmymm%1 ymm%1
+    %define zmmzmm%1 zmm%1
+    %define xm%1 xmm %+ m%1
+    %define ym%1 ymm %+ m%1
+    %define zm%1 zmm %+ m%1
+%endmacro
+
+%assign i 0
+%rep 32
+    DECLARE_MMCAST i
+    %assign i i+1
+%endrep
+
+; I often want to use macros that permute their arguments. e.g. there's no
+; efficient way to implement butterfly or transpose or dct without swapping some
+; arguments.
+;
+; I would like to not have to manually keep track of the permutations:
+; If I insert a permutation in the middle of a function, it should automatically
+; change everything that follows. For more complex macros I may also have multiple
+; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations.
+;
+; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that
+; permutes its arguments. It's equivalent to exchanging the contents of the
+; registers, except that this way you exchange the register names instead, so it
+; doesn't cost any cycles.
+
+%macro PERMUTE 2-* ; takes a list of pairs to swap
+    %rep %0/2
+        %xdefine %%tmp%2 m%2
+        %rotate 2
+    %endrep
+    %rep %0/2
+        %xdefine m%1 %%tmp%2
+        CAT_XDEFINE nn, m%1, %1
+        %rotate 2
+    %endrep
+%endmacro
+
+%macro SWAP 2+ ; swaps a single chain (sometimes more concise than pairs)
+    %ifnum %1 ; SWAP 0, 1, ...
+        SWAP_INTERNAL_NUM %1, %2
+    %else ; SWAP m0, m1, ...
+        SWAP_INTERNAL_NAME %1, %2
+    %endif
+%endmacro
+
+%macro SWAP_INTERNAL_NUM 2-*
+    %rep %0-1
+        %xdefine %%tmp m%1
+        %xdefine m%1 m%2
+        %xdefine m%2 %%tmp
+        CAT_XDEFINE nn, m%1, %1
+        CAT_XDEFINE nn, m%2, %2
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro SWAP_INTERNAL_NAME 2-*
+    %xdefine %%args nn %+ %1
+    %rep %0-1
+        %xdefine %%args %%args, nn %+ %2
+        %rotate 1
+    %endrep
+    SWAP_INTERNAL_NUM %%args
+%endmacro
+
+; If SAVE_MM_PERMUTATION is placed at the end of a function, then any later
+; calls to that function will automatically load the permutation, so values can
+; be returned in mmregs.
+%macro SAVE_MM_PERMUTATION 0-1
+    %if %0
+        %xdefine %%f %1_m
+    %else
+        %xdefine %%f current_function %+ _m
+    %endif
+    %assign %%i 0
+    %rep num_mmregs
+        %xdefine %%tmp m %+ %%i
+        CAT_XDEFINE %%f, %%i, regnumof %+ %%tmp
+        %assign %%i %%i+1
+    %endrep
+%endmacro
+
+%macro LOAD_MM_PERMUTATION 0-1 ; name to load from
+    %if %0
+        %xdefine %%f %1_m
+    %else
+        %xdefine %%f current_function %+ _m
+    %endif
+    %xdefine %%tmp %%f %+ 0
+    %ifnum %%tmp
+        DEFINE_MMREGS mmtype
+        %assign %%i 0
+        %rep num_mmregs
+            %xdefine %%tmp %%f %+ %%i
+            CAT_XDEFINE %%m, %%i, m %+ %%tmp
+            %assign %%i %%i+1
+        %endrep
+        %rep num_mmregs
+            %assign %%i %%i-1
+            CAT_XDEFINE m, %%i, %%m %+ %%i
+            CAT_XDEFINE nn, m %+ %%i, %%i
+        %endrep
+    %endif
+%endmacro
+
+; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't
+%macro call 1
+    %ifid %1
+        call_internal %1 %+ SUFFIX, %1
+    %else
+        call %1
+    %endif
+%endmacro
+%macro call_internal 2
+    %xdefine %%i %2
+    %ifndef cglobaled_%2
+        %ifdef cglobaled_%1
+            %xdefine %%i %1
+        %endif
+    %endif
+    call %%i
+    LOAD_MM_PERMUTATION %%i
+%endmacro
+
+; Substitutions that reduce instruction size but are functionally equivalent
+%macro add 2
+    %ifnum %2
+        %if %2==128
+            sub %1, -128
+        %else
+            add %1, %2
+        %endif
+    %else
+        add %1, %2
+    %endif
+%endmacro
+
+%macro sub 2
+    %ifnum %2
+        %if %2==128
+            add %1, -128
+        %else
+            sub %1, %2
+        %endif
+    %else
+        sub %1, %2
+    %endif
+%endmacro
+
+;=============================================================================
+; AVX abstraction layer
+;=============================================================================
+
+%assign i 0
+%rep 32
+    %if i < 8
+        CAT_XDEFINE sizeofmm, i, 8
+        CAT_XDEFINE regnumofmm, i, i
+    %endif
+    CAT_XDEFINE sizeofxmm, i, 16
+    CAT_XDEFINE sizeofymm, i, 32
+    CAT_XDEFINE sizeofzmm, i, 64
+    CAT_XDEFINE regnumofxmm, i, i
+    CAT_XDEFINE regnumofymm, i, i
+    CAT_XDEFINE regnumofzmm, i, i
+    %assign i i+1
+%endrep
+%undef i
+
+%macro CHECK_AVX_INSTR_EMU 3-*
+    %xdefine %%opcode %1
+    %xdefine %%dst %2
+    %rep %0-2
+        %ifidn %%dst, %3
+            %error non-avx emulation of ``%%opcode'' is not supported
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+;%1 == instruction
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation)
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+;%6+: operands
+%macro RUN_AVX_INSTR 6-9+
+    %ifnum sizeof%7
+        %assign __sizeofreg sizeof%7
+    %elifnum sizeof%6
+        %assign __sizeofreg sizeof%6
+    %else
+        %assign __sizeofreg mmsize
+    %endif
+    %assign __emulate_avx 0
+    %if avx_enabled && __sizeofreg >= 16
+        %xdefine __instr v%1
+    %else
+        %xdefine __instr %1
+        %if %0 >= 8+%4
+            %assign __emulate_avx 1
+        %endif
+    %endif
+    %ifnidn %2, fnord
+        %ifdef cpuname
+            %if notcpuflag(%2)
+                %error use of ``%1'' %2 instruction in cpuname function: current_function
+            %elif %3 == 0 && __sizeofreg == 16 && notcpuflag(sse2)
+                %error use of ``%1'' sse2 instruction in cpuname function: current_function
+            %elif %3 == 0 && __sizeofreg == 32 && notcpuflag(avx2)
+                %error use of ``%1'' avx2 instruction in cpuname function: current_function
+            %elif __sizeofreg == 16 && notcpuflag(sse)
+                %error use of ``%1'' sse instruction in cpuname function: current_function
+            %elif __sizeofreg == 32 && notcpuflag(avx)
+                %error use of ``%1'' avx instruction in cpuname function: current_function
+            %elif __sizeofreg == 64 && notcpuflag(avx512)
+                %error use of ``%1'' avx512 instruction in cpuname function: current_function
+            %elifidn %1, pextrw ; special case because the base instruction is mmx2,
+                %ifnid %6       ; but sse4 is required for memory operands
+                    %if notcpuflag(sse4)
+                        %error use of ``%1'' sse4 instruction in cpuname function: current_function
+                    %endif
+                %endif
+            %endif
+        %endif
+    %endif
+
+    %if __emulate_avx
+        %xdefine __src1 %7
+        %xdefine __src2 %8
+        %if %5 && %4 == 0
+            %ifnidn %6, %7
+                %ifidn %6, %8
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %elifnnum sizeof%8
+                    ; 3-operand AVX instructions with a memory arg can only have it in src2,
+                    ; whereas SSE emulation prefers to have it in src1 (i.e. the mov).
+                    ; So, if the instruction is commutative with a memory arg, swap them.
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %endif
+            %endif
+        %endif
+        %ifnidn %6, __src1
+            %if %0 >= 9
+                CHECK_AVX_INSTR_EMU {%1 %6, %7, %8, %9}, %6, __src2, %9
+            %else
+                CHECK_AVX_INSTR_EMU {%1 %6, %7, %8}, %6, __src2
+            %endif
+            %if __sizeofreg == 8
+                MOVQ %6, __src1
+            %elif %3
+                MOVAPS %6, __src1
+            %else
+                MOVDQA %6, __src1
+            %endif
+        %endif
+        %if %0 >= 9
+            %1 %6, __src2, %9
+        %else
+            %1 %6, __src2
+        %endif
+    %elif %0 >= 9
+        %if avx_enabled && __sizeofreg >= 16 && %4 == 1
+            %ifnnum regnumof%7
+                %if %3
+                    vmovaps %6, %7
+                %else
+                    vmovdqa %6, %7
+                %endif
+                __instr %6, %6, %8, %9
+            %else
+                __instr %6, %7, %8, %9
+            %endif
+        %else
+            __instr %6, %7, %8, %9
+        %endif
+    %elif %0 == 8
+        %if avx_enabled && __sizeofreg >= 16 && %4 == 0
+            %xdefine __src1 %7
+            %xdefine __src2 %8
+            %if %5
+                %ifnum regnumof%7
+                    %ifnum regnumof%8
+                        %if regnumof%7 < 8 && regnumof%8 >= 8 && regnumof%8 < 16 && sizeof%8 <= 32
+                            ; Most VEX-encoded instructions require an additional byte to encode when
+                            ; src2 is a high register (e.g. m8..15). If the instruction is commutative
+                            ; we can swap src1 and src2 when doing so reduces the instruction length.
+                            %xdefine __src1 %8
+                            %xdefine __src2 %7
+                        %endif
+                    %endif
+                %elifnum regnumof%8 ; put memory operands in src2 when possible
+                    %xdefine __src1 %8
+                    %xdefine __src2 %7
+                %else
+                    %assign __emulate_avx 1
+                %endif
+            %elifnnum regnumof%7
+                ; EVEX allows imm8 shift instructions to be used with memory operands,
+                ; but VEX does not. This handles those special cases.
+                %ifnnum %8
+                    %assign __emulate_avx 1
+                %elif notcpuflag(avx512)
+                    %assign __emulate_avx 1
+                %endif
+            %endif
+            %if __emulate_avx ; a separate load is required
+                %if %3
+                    vmovaps %6, %7
+                %else
+                    vmovdqa %6, %7
+                %endif
+                __instr %6, %6, %8
+            %else
+                __instr %6, __src1, __src2
+            %endif
+        %else
+            __instr %6, %7, %8
+        %endif
+    %elif %0 == 7
+        %if avx_enabled && __sizeofreg >= 16 && %5
+            %xdefine __src1 %6
+            %xdefine __src2 %7
+            %ifnum regnumof%6
+                %ifnum regnumof%7
+                    %if regnumof%6 < 8 && regnumof%7 >= 8 && regnumof%7 < 16 && sizeof%7 <= 32
+                        %xdefine __src1 %7
+                        %xdefine __src2 %6
+                    %endif
+                %endif
+            %endif
+            __instr %6, __src1, __src2
+        %else
+            __instr %6, %7
+        %endif
+    %else
+        __instr %6
+    %endif
+%endmacro
+
+;%1 == instruction
+;%2 == minimal instruction set
+;%3 == 1 if float, 0 if int
+;%4 == 1 if 4-operand emulation, 0 if 3-operand emulation, 255 otherwise (no emulation)
+;%5 == 1 if commutative (i.e. doesn't matter which src arg is which), 0 if not
+%macro AVX_INSTR 1-5 fnord, 0, 255, 0
+    %macro %1 1-10 fnord, fnord, fnord, fnord, %1, %2, %3, %4, %5
+        %ifidn %2, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1
+        %elifidn %3, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2
+        %elifidn %4, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3
+        %elifidn %5, fnord
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4
+        %else
+            RUN_AVX_INSTR %6, %7, %8, %9, %10, %1, %2, %3, %4, %5
+        %endif
+    %endmacro
+%endmacro
+
+; Instructions with both VEX/EVEX and legacy encodings
+; Non-destructive instructions are written without parameters
+AVX_INSTR addpd, sse2, 1, 0, 1
+AVX_INSTR addps, sse, 1, 0, 1
+AVX_INSTR addsd, sse2, 1, 0, 0
+AVX_INSTR addss, sse, 1, 0, 0
+AVX_INSTR addsubpd, sse3, 1, 0, 0
+AVX_INSTR addsubps, sse3, 1, 0, 0
+AVX_INSTR aesdec, aesni, 0, 0, 0
+AVX_INSTR aesdeclast, aesni, 0, 0, 0
+AVX_INSTR aesenc, aesni, 0, 0, 0
+AVX_INSTR aesenclast, aesni, 0, 0, 0
+AVX_INSTR aesimc, aesni
+AVX_INSTR aeskeygenassist, aesni
+AVX_INSTR andnpd, sse2, 1, 0, 0
+AVX_INSTR andnps, sse, 1, 0, 0
+AVX_INSTR andpd, sse2, 1, 0, 1
+AVX_INSTR andps, sse, 1, 0, 1
+AVX_INSTR blendpd, sse4, 1, 1, 0
+AVX_INSTR blendps, sse4, 1, 1, 0
+AVX_INSTR blendvpd, sse4, 1, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR blendvps, sse4, 1, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR cmpeqpd, sse2, 1, 0, 1
+AVX_INSTR cmpeqps, sse, 1, 0, 1
+AVX_INSTR cmpeqsd, sse2, 1, 0, 0
+AVX_INSTR cmpeqss, sse, 1, 0, 0
+AVX_INSTR cmplepd, sse2, 1, 0, 0
+AVX_INSTR cmpleps, sse, 1, 0, 0
+AVX_INSTR cmplesd, sse2, 1, 0, 0
+AVX_INSTR cmpless, sse, 1, 0, 0
+AVX_INSTR cmpltpd, sse2, 1, 0, 0
+AVX_INSTR cmpltps, sse, 1, 0, 0
+AVX_INSTR cmpltsd, sse2, 1, 0, 0
+AVX_INSTR cmpltss, sse, 1, 0, 0
+AVX_INSTR cmpneqpd, sse2, 1, 0, 1
+AVX_INSTR cmpneqps, sse, 1, 0, 1
+AVX_INSTR cmpneqsd, sse2, 1, 0, 0
+AVX_INSTR cmpneqss, sse, 1, 0, 0
+AVX_INSTR cmpnlepd, sse2, 1, 0, 0
+AVX_INSTR cmpnleps, sse, 1, 0, 0
+AVX_INSTR cmpnlesd, sse2, 1, 0, 0
+AVX_INSTR cmpnless, sse, 1, 0, 0
+AVX_INSTR cmpnltpd, sse2, 1, 0, 0
+AVX_INSTR cmpnltps, sse, 1, 0, 0
+AVX_INSTR cmpnltsd, sse2, 1, 0, 0
+AVX_INSTR cmpnltss, sse, 1, 0, 0
+AVX_INSTR cmpordpd, sse2 1, 0, 1
+AVX_INSTR cmpordps, sse 1, 0, 1
+AVX_INSTR cmpordsd, sse2 1, 0, 0
+AVX_INSTR cmpordss, sse 1, 0, 0
+AVX_INSTR cmppd, sse2, 1, 1, 0
+AVX_INSTR cmpps, sse, 1, 1, 0
+AVX_INSTR cmpsd, sse2, 1, 1, 0
+AVX_INSTR cmpss, sse, 1, 1, 0
+AVX_INSTR cmpunordpd, sse2, 1, 0, 1
+AVX_INSTR cmpunordps, sse, 1, 0, 1
+AVX_INSTR cmpunordsd, sse2, 1, 0, 0
+AVX_INSTR cmpunordss, sse, 1, 0, 0
+AVX_INSTR comisd, sse2, 1
+AVX_INSTR comiss, sse, 1
+AVX_INSTR cvtdq2pd, sse2, 1
+AVX_INSTR cvtdq2ps, sse2, 1
+AVX_INSTR cvtpd2dq, sse2, 1
+AVX_INSTR cvtpd2ps, sse2, 1
+AVX_INSTR cvtps2dq, sse2, 1
+AVX_INSTR cvtps2pd, sse2, 1
+AVX_INSTR cvtsd2si, sse2, 1
+AVX_INSTR cvtsd2ss, sse2, 1, 0, 0
+AVX_INSTR cvtsi2sd, sse2, 1, 0, 0
+AVX_INSTR cvtsi2ss, sse, 1, 0, 0
+AVX_INSTR cvtss2sd, sse2, 1, 0, 0
+AVX_INSTR cvtss2si, sse, 1
+AVX_INSTR cvttpd2dq, sse2, 1
+AVX_INSTR cvttps2dq, sse2, 1
+AVX_INSTR cvttsd2si, sse2, 1
+AVX_INSTR cvttss2si, sse, 1
+AVX_INSTR divpd, sse2, 1, 0, 0
+AVX_INSTR divps, sse, 1, 0, 0
+AVX_INSTR divsd, sse2, 1, 0, 0
+AVX_INSTR divss, sse, 1, 0, 0
+AVX_INSTR dppd, sse4, 1, 1, 0
+AVX_INSTR dpps, sse4, 1, 1, 0
+AVX_INSTR extractps, sse4, 1
+AVX_INSTR gf2p8affineinvqb, gfni, 0, 1, 0
+AVX_INSTR gf2p8affineqb, gfni, 0, 1, 0
+AVX_INSTR gf2p8mulb, gfni, 0, 0, 0
+AVX_INSTR haddpd, sse3, 1, 0, 0
+AVX_INSTR haddps, sse3, 1, 0, 0
+AVX_INSTR hsubpd, sse3, 1, 0, 0
+AVX_INSTR hsubps, sse3, 1, 0, 0
+AVX_INSTR insertps, sse4, 1, 1, 0
+AVX_INSTR lddqu, sse3
+AVX_INSTR ldmxcsr, sse, 1
+AVX_INSTR maskmovdqu, sse2
+AVX_INSTR maxpd, sse2, 1, 0, 1
+AVX_INSTR maxps, sse, 1, 0, 1
+AVX_INSTR maxsd, sse2, 1, 0, 0
+AVX_INSTR maxss, sse, 1, 0, 0
+AVX_INSTR minpd, sse2, 1, 0, 1
+AVX_INSTR minps, sse, 1, 0, 1
+AVX_INSTR minsd, sse2, 1, 0, 0
+AVX_INSTR minss, sse, 1, 0, 0
+AVX_INSTR movapd, sse2, 1
+AVX_INSTR movaps, sse, 1
+AVX_INSTR movd, mmx
+AVX_INSTR movddup, sse3, 1
+AVX_INSTR movdqa, sse2
+AVX_INSTR movdqu, sse2
+AVX_INSTR movhlps, sse, 1, 0, 0
+AVX_INSTR movhpd, sse2, 1, 0, 0
+AVX_INSTR movhps, sse, 1, 0, 0
+AVX_INSTR movlhps, sse, 1, 0, 0
+AVX_INSTR movlpd, sse2, 1, 0, 0
+AVX_INSTR movlps, sse, 1, 0, 0
+AVX_INSTR movmskpd, sse2, 1
+AVX_INSTR movmskps, sse, 1
+AVX_INSTR movntdq, sse2
+AVX_INSTR movntdqa, sse4
+AVX_INSTR movntpd, sse2, 1
+AVX_INSTR movntps, sse, 1
+AVX_INSTR movq, mmx
+AVX_INSTR movsd, sse2, 1, 0, 0
+AVX_INSTR movshdup, sse3, 1
+AVX_INSTR movsldup, sse3, 1
+AVX_INSTR movss, sse, 1, 0, 0
+AVX_INSTR movupd, sse2, 1
+AVX_INSTR movups, sse, 1
+AVX_INSTR mpsadbw, sse4, 0, 1, 0
+AVX_INSTR mulpd, sse2, 1, 0, 1
+AVX_INSTR mulps, sse, 1, 0, 1
+AVX_INSTR mulsd, sse2, 1, 0, 0
+AVX_INSTR mulss, sse, 1, 0, 0
+AVX_INSTR orpd, sse2, 1, 0, 1
+AVX_INSTR orps, sse, 1, 0, 1
+AVX_INSTR pabsb, ssse3
+AVX_INSTR pabsd, ssse3
+AVX_INSTR pabsw, ssse3
+AVX_INSTR packssdw, mmx, 0, 0, 0
+AVX_INSTR packsswb, mmx, 0, 0, 0
+AVX_INSTR packusdw, sse4, 0, 0, 0
+AVX_INSTR packuswb, mmx, 0, 0, 0
+AVX_INSTR paddb, mmx, 0, 0, 1
+AVX_INSTR paddd, mmx, 0, 0, 1
+AVX_INSTR paddq, sse2, 0, 0, 1
+AVX_INSTR paddsb, mmx, 0, 0, 1
+AVX_INSTR paddsw, mmx, 0, 0, 1
+AVX_INSTR paddusb, mmx, 0, 0, 1
+AVX_INSTR paddusw, mmx, 0, 0, 1
+AVX_INSTR paddw, mmx, 0, 0, 1
+AVX_INSTR palignr, ssse3, 0, 1, 0
+AVX_INSTR pand, mmx, 0, 0, 1
+AVX_INSTR pandn, mmx, 0, 0, 0
+AVX_INSTR pavgb, mmx2, 0, 0, 1
+AVX_INSTR pavgw, mmx2, 0, 0, 1
+AVX_INSTR pblendvb, sse4, 0, 1, 0 ; last operand must be xmm0 with legacy encoding
+AVX_INSTR pblendw, sse4, 0, 1, 0
+AVX_INSTR pclmulhqhqdq, clmul, 0, 0, 0
+AVX_INSTR pclmulhqlqdq, clmul, 0, 0, 0
+AVX_INSTR pclmullqhqdq, clmul, 0, 0, 0
+AVX_INSTR pclmullqlqdq, clmul, 0, 0, 0
+AVX_INSTR pclmulqdq, clmul, 0, 1, 0
+AVX_INSTR pcmpeqb, mmx, 0, 0, 1
+AVX_INSTR pcmpeqd, mmx, 0, 0, 1
+AVX_INSTR pcmpeqq, sse4, 0, 0, 1
+AVX_INSTR pcmpeqw, mmx, 0, 0, 1
+AVX_INSTR pcmpestri, sse42
+AVX_INSTR pcmpestrm, sse42
+AVX_INSTR pcmpgtb, mmx, 0, 0, 0
+AVX_INSTR pcmpgtd, mmx, 0, 0, 0
+AVX_INSTR pcmpgtq, sse42, 0, 0, 0
+AVX_INSTR pcmpgtw, mmx, 0, 0, 0
+AVX_INSTR pcmpistri, sse42
+AVX_INSTR pcmpistrm, sse42
+AVX_INSTR pextrb, sse4
+AVX_INSTR pextrd, sse4
+AVX_INSTR pextrq, sse4
+AVX_INSTR pextrw, mmx2
+AVX_INSTR phaddd, ssse3, 0, 0, 0
+AVX_INSTR phaddsw, ssse3, 0, 0, 0
+AVX_INSTR phaddw, ssse3, 0, 0, 0
+AVX_INSTR phminposuw, sse4
+AVX_INSTR phsubd, ssse3, 0, 0, 0
+AVX_INSTR phsubsw, ssse3, 0, 0, 0
+AVX_INSTR phsubw, ssse3, 0, 0, 0
+AVX_INSTR pinsrb, sse4, 0, 1, 0
+AVX_INSTR pinsrd, sse4, 0, 1, 0
+AVX_INSTR pinsrq, sse4, 0, 1, 0
+AVX_INSTR pinsrw, mmx2, 0, 1, 0
+AVX_INSTR pmaddubsw, ssse3, 0, 0, 0
+AVX_INSTR pmaddwd, mmx, 0, 0, 1
+AVX_INSTR pmaxsb, sse4, 0, 0, 1
+AVX_INSTR pmaxsd, sse4, 0, 0, 1
+AVX_INSTR pmaxsw, mmx2, 0, 0, 1
+AVX_INSTR pmaxub, mmx2, 0, 0, 1
+AVX_INSTR pmaxud, sse4, 0, 0, 1
+AVX_INSTR pmaxuw, sse4, 0, 0, 1
+AVX_INSTR pminsb, sse4, 0, 0, 1
+AVX_INSTR pminsd, sse4, 0, 0, 1
+AVX_INSTR pminsw, mmx2, 0, 0, 1
+AVX_INSTR pminub, mmx2, 0, 0, 1
+AVX_INSTR pminud, sse4, 0, 0, 1
+AVX_INSTR pminuw, sse4, 0, 0, 1
+AVX_INSTR pmovmskb, mmx2
+AVX_INSTR pmovsxbd, sse4
+AVX_INSTR pmovsxbq, sse4
+AVX_INSTR pmovsxbw, sse4
+AVX_INSTR pmovsxdq, sse4
+AVX_INSTR pmovsxwd, sse4
+AVX_INSTR pmovsxwq, sse4
+AVX_INSTR pmovzxbd, sse4
+AVX_INSTR pmovzxbq, sse4
+AVX_INSTR pmovzxbw, sse4
+AVX_INSTR pmovzxdq, sse4
+AVX_INSTR pmovzxwd, sse4
+AVX_INSTR pmovzxwq, sse4
+AVX_INSTR pmuldq, sse4, 0, 0, 1
+AVX_INSTR pmulhrsw, ssse3, 0, 0, 1
+AVX_INSTR pmulhuw, mmx2, 0, 0, 1
+AVX_INSTR pmulhw, mmx, 0, 0, 1
+AVX_INSTR pmulld, sse4, 0, 0, 1
+AVX_INSTR pmullw, mmx, 0, 0, 1
+AVX_INSTR pmuludq, sse2, 0, 0, 1
+AVX_INSTR por, mmx, 0, 0, 1
+AVX_INSTR psadbw, mmx2, 0, 0, 1
+AVX_INSTR pshufb, ssse3, 0, 0, 0
+AVX_INSTR pshufd, sse2
+AVX_INSTR pshufhw, sse2
+AVX_INSTR pshuflw, sse2
+AVX_INSTR psignb, ssse3, 0, 0, 0
+AVX_INSTR psignd, ssse3, 0, 0, 0
+AVX_INSTR psignw, ssse3, 0, 0, 0
+AVX_INSTR pslld, mmx, 0, 0, 0
+AVX_INSTR pslldq, sse2, 0, 0, 0
+AVX_INSTR psllq, mmx, 0, 0, 0
+AVX_INSTR psllw, mmx, 0, 0, 0
+AVX_INSTR psrad, mmx, 0, 0, 0
+AVX_INSTR psraw, mmx, 0, 0, 0
+AVX_INSTR psrld, mmx, 0, 0, 0
+AVX_INSTR psrldq, sse2, 0, 0, 0
+AVX_INSTR psrlq, mmx, 0, 0, 0
+AVX_INSTR psrlw, mmx, 0, 0, 0
+AVX_INSTR psubb, mmx, 0, 0, 0
+AVX_INSTR psubd, mmx, 0, 0, 0
+AVX_INSTR psubq, sse2, 0, 0, 0
+AVX_INSTR psubsb, mmx, 0, 0, 0
+AVX_INSTR psubsw, mmx, 0, 0, 0
+AVX_INSTR psubusb, mmx, 0, 0, 0
+AVX_INSTR psubusw, mmx, 0, 0, 0
+AVX_INSTR psubw, mmx, 0, 0, 0
+AVX_INSTR ptest, sse4
+AVX_INSTR punpckhbw, mmx, 0, 0, 0
+AVX_INSTR punpckhdq, mmx, 0, 0, 0
+AVX_INSTR punpckhqdq, sse2, 0, 0, 0
+AVX_INSTR punpckhwd, mmx, 0, 0, 0
+AVX_INSTR punpcklbw, mmx, 0, 0, 0
+AVX_INSTR punpckldq, mmx, 0, 0, 0
+AVX_INSTR punpcklqdq, sse2, 0, 0, 0
+AVX_INSTR punpcklwd, mmx, 0, 0, 0
+AVX_INSTR pxor, mmx, 0, 0, 1
+AVX_INSTR rcpps, sse, 1
+AVX_INSTR rcpss, sse, 1, 0, 0
+AVX_INSTR roundpd, sse4, 1
+AVX_INSTR roundps, sse4, 1
+AVX_INSTR roundsd, sse4, 1, 1, 0
+AVX_INSTR roundss, sse4, 1, 1, 0
+AVX_INSTR rsqrtps, sse, 1
+AVX_INSTR rsqrtss, sse, 1, 0, 0
+AVX_INSTR shufpd, sse2, 1, 1, 0
+AVX_INSTR shufps, sse, 1, 1, 0
+AVX_INSTR sqrtpd, sse2, 1
+AVX_INSTR sqrtps, sse, 1
+AVX_INSTR sqrtsd, sse2, 1, 0, 0
+AVX_INSTR sqrtss, sse, 1, 0, 0
+AVX_INSTR stmxcsr, sse, 1
+AVX_INSTR subpd, sse2, 1, 0, 0
+AVX_INSTR subps, sse, 1, 0, 0
+AVX_INSTR subsd, sse2, 1, 0, 0
+AVX_INSTR subss, sse, 1, 0, 0
+AVX_INSTR ucomisd, sse2, 1
+AVX_INSTR ucomiss, sse, 1
+AVX_INSTR unpckhpd, sse2, 1, 0, 0
+AVX_INSTR unpckhps, sse, 1, 0, 0
+AVX_INSTR unpcklpd, sse2, 1, 0, 0
+AVX_INSTR unpcklps, sse, 1, 0, 0
+AVX_INSTR xorpd, sse2, 1, 0, 1
+AVX_INSTR xorps, sse, 1, 0, 1
+
+; 3DNow instructions, for sharing code between AVX, SSE and 3DN
+AVX_INSTR pfadd, 3dnow, 1, 0, 1
+AVX_INSTR pfmul, 3dnow, 1, 0, 1
+AVX_INSTR pfsub, 3dnow, 1, 0, 0
+
+;%1 == instruction
+;%2 == minimal instruction set
+%macro GPR_INSTR 2
+    %macro %1 2-5 fnord, %1, %2
+        %ifdef cpuname
+            %if notcpuflag(%5)
+                %error use of ``%4'' %5 instruction in cpuname function: current_function
+            %endif
+        %endif
+        %ifidn %3, fnord
+            %4 %1, %2
+        %else
+            %4 %1, %2, %3
+        %endif
+    %endmacro
+%endmacro
+
+GPR_INSTR andn, bmi1
+GPR_INSTR bextr, bmi1
+GPR_INSTR blsi, bmi1
+GPR_INSTR blsmsk, bmi1
+GPR_INSTR blsr, bmi1
+GPR_INSTR bzhi, bmi2
+GPR_INSTR crc32, sse42
+GPR_INSTR mulx, bmi2
+GPR_INSTR pdep, bmi2
+GPR_INSTR pext, bmi2
+GPR_INSTR popcnt, sse42
+GPR_INSTR rorx, bmi2
+GPR_INSTR sarx, bmi2
+GPR_INSTR shlx, bmi2
+GPR_INSTR shrx, bmi2
+
+; base-4 constants for shuffles
+%assign i 0
+%rep 256
+    %assign j ((i>>6)&3)*1000 + ((i>>4)&3)*100 + ((i>>2)&3)*10 + (i&3)
+    %if j < 10
+        CAT_XDEFINE q000, j, i
+    %elif j < 100
+        CAT_XDEFINE q00, j, i
+    %elif j < 1000
+        CAT_XDEFINE q0, j, i
+    %else
+        CAT_XDEFINE q, j, i
+    %endif
+    %assign i i+1
+%endrep
+%undef i
+%undef j
+
+%macro FMA_INSTR 3
+    %macro %1 4-7 %1, %2, %3
+        %if cpuflag(xop)
+            v%5 %1, %2, %3, %4
+        %elifnidn %1, %4
+            %6 %1, %2, %3
+            %7 %1, %4
+        %else
+            %error non-xop emulation of ``%5 %1, %2, %3, %4'' is not supported
+        %endif
+    %endmacro
+%endmacro
+
+FMA_INSTR pmacsdd,  pmulld,  paddd ; sse4 emulation
+FMA_INSTR pmacsdql, pmuldq,  paddq ; sse4 emulation
+FMA_INSTR pmacsww,  pmullw,  paddw
+FMA_INSTR pmadcswd, pmaddwd, paddd
+
+; Macros for consolidating FMA3 and FMA4 using 4-operand (dst, src1, src2, src3) syntax.
+; FMA3 is only possible if dst is the same as one of the src registers.
+; Either src2 or src3 can be a memory operand.
+%macro FMA4_INSTR 2-*
+    %push fma4_instr
+    %xdefine %$prefix %1
+    %rep %0 - 1
+        %macro %$prefix%2 4-6 %$prefix, %2
+            %if notcpuflag(fma3) && notcpuflag(fma4)
+                %error use of ``%5%6'' fma instruction in cpuname function: current_function
+            %elif cpuflag(fma4)
+                v%5%6 %1, %2, %3, %4
+            %elifidn %1, %2
+                ; If %3 or %4 is a memory operand it needs to be encoded as the last operand.
+                %ifnum sizeof%3
+                    v%{5}213%6 %2, %3, %4
+                %else
+                    v%{5}132%6 %2, %4, %3
+                %endif
+            %elifidn %1, %3
+                v%{5}213%6 %3, %2, %4
+            %elifidn %1, %4
+                v%{5}231%6 %4, %2, %3
+            %else
+                %error fma3 emulation of ``%5%6 %1, %2, %3, %4'' is not supported
+            %endif
+        %endmacro
+        %rotate 1
+    %endrep
+    %pop
+%endmacro
+
+FMA4_INSTR fmadd,    pd, ps, sd, ss
+FMA4_INSTR fmaddsub, pd, ps
+FMA4_INSTR fmsub,    pd, ps, sd, ss
+FMA4_INSTR fmsubadd, pd, ps
+FMA4_INSTR fnmadd,   pd, ps, sd, ss
+FMA4_INSTR fnmsub,   pd, ps, sd, ss
+
+; Macros for converting VEX instructions to equivalent EVEX ones.
+%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex
+    %macro %1 2-7 fnord, fnord, %1, %2, %3
+        %ifidn %3, fnord
+            %define %%args %1, %2
+        %elifidn %4, fnord
+            %define %%args %1, %2, %3
+        %else
+            %define %%args %1, %2, %3, %4
+        %endif
+        %assign %%evex_required cpuflag(avx512) & %7
+        %ifnum regnumof%1
+            %if regnumof%1 >= 16 || sizeof%1 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %ifnum regnumof%2
+            %if regnumof%2 >= 16 || sizeof%2 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %ifnum regnumof%3
+            %if regnumof%3 >= 16 || sizeof%3 > 32
+                %assign %%evex_required 1
+            %endif
+        %endif
+        %if %%evex_required
+            %6 %%args
+        %else
+            %5 %%args ; Prefer VEX over EVEX due to shorter instruction length
+        %endif
+    %endmacro
+%endmacro
+
+EVEX_INSTR vbroadcastf128, vbroadcastf32x4
+EVEX_INSTR vbroadcasti128, vbroadcasti32x4
+EVEX_INSTR vextractf128,   vextractf32x4
+EVEX_INSTR vextracti128,   vextracti32x4
+EVEX_INSTR vinsertf128,    vinsertf32x4
+EVEX_INSTR vinserti128,    vinserti32x4
+EVEX_INSTR vmovdqa,        vmovdqa32
+EVEX_INSTR vmovdqu,        vmovdqu32
+EVEX_INSTR vpand,          vpandd
+EVEX_INSTR vpandn,         vpandnd
+EVEX_INSTR vpor,           vpord
+EVEX_INSTR vpxor,          vpxord
+EVEX_INSTR vrcpps,         vrcp14ps,   1 ; EVEX versions have higher precision
+EVEX_INSTR vrcpss,         vrcp14ss,   1
+EVEX_INSTR vrsqrtps,       vrsqrt14ps, 1
+EVEX_INSTR vrsqrtss,       vrsqrt14ss, 1
diff --git a/libs/ffmpeg/libavutil/x86/x86util.asm b/libs/ffmpeg/libavutil/x86/x86util.asm
new file mode 100644
index 000000000000..b5aaecb05d9a
--- /dev/null
+++ b/libs/ffmpeg/libavutil/x86/x86util.asm
@@ -0,0 +1,1026 @@
+;*****************************************************************************
+;* x86util.asm
+;*****************************************************************************
+;* Copyright (C) 2008-2010 x264 project
+;*
+;* Authors: Loren Merritt <lorenm@u.washington.edu>
+;*          Holger Lubitz <holger@lubitz.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
+;******************************************************************************
+
+%pragma makedep header
+
+%define private_prefix ff
+%define public_prefix  avpriv
+%define cpuflags_mmxext cpuflags_mmx2
+
+%include "libavutil/x86/x86inc.asm"
+
+; expands to [base],...,[base+7*stride]
+%define PASS8ROWS(base, base3, stride, stride3) \
+    [base],           [base  + stride],   [base  + 2*stride], [base3], \
+    [base3 + stride], [base3 + 2*stride], [base3 + stride3],  [base3 + stride*4]
+
+; Interleave low src0 with low src1 and store in src0,
+; interleave high src0 with high src1 and store in src1.
+; %1 - types
+; %2 - index of the register with src0
+; %3 - index of the register with src1
+; %4 - index of the register for intermediate results
+; example for %1 - wd: input: src0: x0 x1 x2 x3 z0 z1 z2 z3
+;                             src1: y0 y1 y2 y3 q0 q1 q2 q3
+;                     output: src0: x0 y0 x1 y1 x2 y2 x3 y3
+;                             src1: z0 q0 z1 q1 z2 q2 z3 q3
+%macro SBUTTERFLY 4
+%ifidn %1, dqqq
+    vperm2i128  m%4, m%2, m%3, q0301
+    vinserti128 m%2, m%2, xm%3, 1
+%elif avx_enabled == 0
+    mova      m%4, m%2
+    punpckl%1 m%2, m%3
+    punpckh%1 m%4, m%3
+%else
+    punpckh%1 m%4, m%2, m%3
+    punpckl%1 m%2, m%3
+%endif
+    SWAP %3, %4
+%endmacro
+
+%macro SBUTTERFLY2 4
+    punpckl%1 m%4, m%2, m%3
+    punpckh%1 m%2, m%2, m%3
+    SWAP %2, %4, %3
+%endmacro
+
+%macro SBUTTERFLYPS 3
+    unpcklps m%3, m%1, m%2
+    unpckhps m%1, m%1, m%2
+    SWAP %1, %3, %2
+%endmacro
+
+%macro SBUTTERFLYPD 3
+    movlhps m%3, m%1, m%2
+    movhlps m%2, m%2, m%1
+    SWAP %1, %3
+%endmacro
+
+%macro TRANSPOSE4x4B 5
+    SBUTTERFLY bw, %1, %2, %5
+    SBUTTERFLY bw, %3, %4, %5
+    SBUTTERFLY wd, %1, %3, %5
+    SBUTTERFLY wd, %2, %4, %5
+    SWAP %2, %3
+%endmacro
+
+%macro TRANSPOSE4x4W 5
+    SBUTTERFLY wd, %1, %2, %5
+    SBUTTERFLY wd, %3, %4, %5
+    SBUTTERFLY dq, %1, %3, %5
+    SBUTTERFLY dq, %2, %4, %5
+    SWAP %2, %3
+%endmacro
+
+%macro TRANSPOSE2x4x4B 5
+    SBUTTERFLY bw,  %1, %2, %5
+    SBUTTERFLY bw,  %3, %4, %5
+    SBUTTERFLY wd,  %1, %3, %5
+    SBUTTERFLY wd,  %2, %4, %5
+    SBUTTERFLY dq,  %1, %2, %5
+    SBUTTERFLY dq,  %3, %4, %5
+%endmacro
+
+%macro TRANSPOSE2x4x4W 5
+    SBUTTERFLY wd,  %1, %2, %5
+    SBUTTERFLY wd,  %3, %4, %5
+    SBUTTERFLY dq,  %1, %3, %5
+    SBUTTERFLY dq,  %2, %4, %5
+    SBUTTERFLY qdq, %1, %2, %5
+    SBUTTERFLY qdq, %3, %4, %5
+%endmacro
+
+%macro TRANSPOSE4x4D 5
+    SBUTTERFLY dq,  %1, %2, %5
+    SBUTTERFLY dq,  %3, %4, %5
+    SBUTTERFLY qdq, %1, %3, %5
+    SBUTTERFLY qdq, %2, %4, %5
+    SWAP %2, %3
+%endmacro
+
+; identical behavior to TRANSPOSE4x4D, but using SSE1 float ops
+%macro TRANSPOSE4x4PS 5
+    SBUTTERFLYPS %1, %2, %5
+    SBUTTERFLYPS %3, %4, %5
+    SBUTTERFLYPD %1, %3, %5
+    SBUTTERFLYPD %2, %4, %5
+    SWAP %2, %3
+%endmacro
+
+%macro TRANSPOSE8x4D 9-11
+%if ARCH_X86_64
+    SBUTTERFLY dq,  %1, %2, %9
+    SBUTTERFLY dq,  %3, %4, %9
+    SBUTTERFLY dq,  %5, %6, %9
+    SBUTTERFLY dq,  %7, %8, %9
+    SBUTTERFLY qdq, %1, %3, %9
+    SBUTTERFLY qdq, %2, %4, %9
+    SBUTTERFLY qdq, %5, %7, %9
+    SBUTTERFLY qdq, %6, %8, %9
+    SWAP %2, %5
+    SWAP %4, %7
+%else
+; in:  m0..m7
+; out: m0..m7, unless %11 in which case m2 is in %9
+; spills into %9 and %10
+    movdqa %9, m%7
+    SBUTTERFLY dq,  %1, %2, %7
+    movdqa %10, m%2
+    movdqa m%7, %9
+    SBUTTERFLY dq,  %3, %4, %2
+    SBUTTERFLY dq,  %5, %6, %2
+    SBUTTERFLY dq,  %7, %8, %2
+    SBUTTERFLY qdq, %1, %3, %2
+    movdqa %9, m%3
+    movdqa m%2, %10
+    SBUTTERFLY qdq, %2, %4, %3
+    SBUTTERFLY qdq, %5, %7, %3
+    SBUTTERFLY qdq, %6, %8, %3
+    SWAP %2, %5
+    SWAP %4, %7
+%if %0<11
+    movdqa m%3, %9
+%endif
+%endif
+%endmacro
+
+%macro TRANSPOSE8x8W 9-11
+%if ARCH_X86_64
+    SBUTTERFLY wd,  %1, %2, %9
+    SBUTTERFLY wd,  %3, %4, %9
+    SBUTTERFLY wd,  %5, %6, %9
+    SBUTTERFLY wd,  %7, %8, %9
+    SBUTTERFLY dq,  %1, %3, %9
+    SBUTTERFLY dq,  %2, %4, %9
+    SBUTTERFLY dq,  %5, %7, %9
+    SBUTTERFLY dq,  %6, %8, %9
+    SBUTTERFLY qdq, %1, %5, %9
+    SBUTTERFLY qdq, %2, %6, %9
+    SBUTTERFLY qdq, %3, %7, %9
+    SBUTTERFLY qdq, %4, %8, %9
+    SWAP %2, %5
+    SWAP %4, %7
+%else
+; in:  m0..m7, unless %11 in which case m6 is in %9
+; out: m0..m7, unless %11 in which case m4 is in %10
+; spills into %9 and %10
+%if %0<11
+    movdqa %9, m%7
+%endif
+    SBUTTERFLY wd,  %1, %2, %7
+    movdqa %10, m%2
+    movdqa m%7, %9
+    SBUTTERFLY wd,  %3, %4, %2
+    SBUTTERFLY wd,  %5, %6, %2
+    SBUTTERFLY wd,  %7, %8, %2
+    SBUTTERFLY dq,  %1, %3, %2
+    movdqa %9, m%3
+    movdqa m%2, %10
+    SBUTTERFLY dq,  %2, %4, %3
+    SBUTTERFLY dq,  %5, %7, %3
+    SBUTTERFLY dq,  %6, %8, %3
+    SBUTTERFLY qdq, %1, %5, %3
+    SBUTTERFLY qdq, %2, %6, %3
+    movdqa %10, m%2
+    movdqa m%3, %9
+    SBUTTERFLY qdq, %3, %7, %2
+    SBUTTERFLY qdq, %4, %8, %2
+    SWAP %2, %5
+    SWAP %4, %7
+%if %0<11
+    movdqa m%5, %10
+%endif
+%endif
+%endmacro
+
+%macro TRANSPOSE16x16W 18-19
+; in:  m0..m15, unless %19 in which case m6 is in %17
+; out: m0..m15, unless %19 in which case m4 is in %18
+; spills into %17 and %18
+%if %0 < 19
+    mova       %17, m%7
+%endif
+
+    SBUTTERFLY dqqq, %1,  %9, %7
+    SBUTTERFLY dqqq, %2, %10, %7
+    SBUTTERFLY dqqq, %3, %11, %7
+    SBUTTERFLY dqqq, %4, %12, %7
+    SBUTTERFLY dqqq, %5, %13, %7
+    SBUTTERFLY dqqq, %6, %14, %7
+    mova       %18, m%14
+    mova       m%7, %17
+    SBUTTERFLY dqqq, %7, %15, %14
+    SBUTTERFLY dqqq, %8, %16, %14
+
+    SBUTTERFLY  wd,  %1,  %2, %14
+    SBUTTERFLY  wd,  %3,  %4, %14
+    SBUTTERFLY  wd,  %5,  %6, %14
+    SBUTTERFLY  wd,  %7,  %8, %14
+    SBUTTERFLY  wd,  %9, %10, %14
+    SBUTTERFLY  wd, %11, %12, %14
+    mova       %17, m%12
+    mova      m%14, %18
+    SBUTTERFLY  wd, %13, %14, %12
+    SBUTTERFLY  wd, %15, %16, %12
+
+    SBUTTERFLY  dq,  %1,  %3, %12
+    SBUTTERFLY  dq,  %2,  %4, %12
+    SBUTTERFLY  dq,  %5,  %7, %12
+    SBUTTERFLY  dq,  %6,  %8, %12
+    SBUTTERFLY  dq,  %9, %11, %12
+    mova       %18, m%11
+    mova      m%12, %17
+    SBUTTERFLY  dq, %10, %12, %11
+    SBUTTERFLY  dq, %13, %15, %11
+    SBUTTERFLY  dq, %14, %16, %11
+
+    SBUTTERFLY qdq,  %1,  %5, %11
+    SBUTTERFLY qdq,  %2,  %6, %11
+    SBUTTERFLY qdq,  %3,  %7, %11
+    SBUTTERFLY qdq,  %4,  %8, %11
+
+    SWAP        %2, %5
+    SWAP        %4, %7
+
+    SBUTTERFLY qdq,  %9, %13, %11
+    SBUTTERFLY qdq, %10, %14, %11
+    mova      m%11, %18
+    mova       %18, m%5
+    SBUTTERFLY qdq, %11, %15, %5
+    SBUTTERFLY qdq, %12, %16, %5
+
+%if %0 < 19
+    mova       m%5, %18
+%endif
+
+    SWAP       %10, %13
+    SWAP       %12, %15
+%endmacro
+
+%macro TRANSPOSE_8X8B 8
+    %if mmsize == 8
+        %error "This macro does not support mmsize == 8"
+    %endif
+    punpcklbw m%1, m%2
+    punpcklbw m%3, m%4
+    punpcklbw m%5, m%6
+    punpcklbw m%7, m%8
+    TRANSPOSE4x4W %1, %3, %5, %7, %2
+    MOVHL m%2, m%1
+    MOVHL m%4, m%3
+    MOVHL m%6, m%5
+    MOVHL m%8, m%7
+%endmacro
+
+; PABSW macro assumes %1 != %2, while ABS1/2 macros work in-place
+%macro PABSW 2
+%if cpuflag(ssse3)
+    pabsw      %1, %2
+%elif cpuflag(mmxext)
+    pxor    %1, %1
+    psubw   %1, %2
+    pmaxsw  %1, %2
+%else
+    pxor       %1, %1
+    pcmpgtw    %1, %2
+    pxor       %2, %1
+    psubw      %2, %1
+    SWAP       %1, %2
+%endif
+%endmacro
+
+%macro PSIGNW 2
+%if cpuflag(ssse3)
+    psignw     %1, %2
+%else
+    pxor       %1, %2
+    psubw      %1, %2
+%endif
+%endmacro
+
+%macro ABS1 2
+%if cpuflag(ssse3)
+    pabsw   %1, %1
+%elif cpuflag(mmxext) ; a, tmp
+    pxor    %2, %2
+    psubw   %2, %1
+    pmaxsw  %1, %2
+%else ; a, tmp
+    pxor       %2, %2
+    pcmpgtw    %2, %1
+    pxor       %1, %2
+    psubw      %1, %2
+%endif
+%endmacro
+
+%macro ABS2 4
+%if cpuflag(ssse3)
+    pabsw   %1, %1
+    pabsw   %2, %2
+%elif cpuflag(mmxext) ; a, b, tmp0, tmp1
+    pxor    %3, %3
+    pxor    %4, %4
+    psubw   %3, %1
+    psubw   %4, %2
+    pmaxsw  %1, %3
+    pmaxsw  %2, %4
+%else ; a, b, tmp0, tmp1
+    pxor       %3, %3
+    pxor       %4, %4
+    pcmpgtw    %3, %1
+    pcmpgtw    %4, %2
+    pxor       %1, %3
+    pxor       %2, %4
+    psubw      %1, %3
+    psubw      %2, %4
+%endif
+%endmacro
+
+%macro ABSB 2 ; source mmreg, temp mmreg (unused for SSSE3)
+%if cpuflag(ssse3)
+    pabsb   %1, %1
+%else
+    pxor    %2, %2
+    psubb   %2, %1
+    pminub  %1, %2
+%endif
+%endmacro
+
+%macro ABSB2 4 ; src1, src2, tmp1, tmp2 (tmp1/2 unused for SSSE3)
+%if cpuflag(ssse3)
+    pabsb   %1, %1
+    pabsb   %2, %2
+%else
+    pxor    %3, %3
+    pxor    %4, %4
+    psubb   %3, %1
+    psubb   %4, %2
+    pminub  %1, %3
+    pminub  %2, %4
+%endif
+%endmacro
+
+%macro ABSD2 4
+    pxor    %3, %3
+    pxor    %4, %4
+    pcmpgtd %3, %1
+    pcmpgtd %4, %2
+    pxor    %1, %3
+    pxor    %2, %4
+    psubd   %1, %3
+    psubd   %2, %4
+%endmacro
+
+%macro ABS4 6
+    ABS2 %1, %2, %5, %6
+    ABS2 %3, %4, %5, %6
+%endmacro
+
+%macro SPLATB_LOAD 3
+%if cpuflag(ssse3)
+    movd      %1, [%2-3]
+    pshufb    %1, %3
+%else
+    movd      %1, [%2-3] ;to avoid crossing a cacheline
+    punpcklbw %1, %1
+    SPLATW    %1, %1, 3
+%endif
+%endmacro
+
+%macro SPLATB_REG 3
+%if cpuflag(ssse3)
+    movd      %1, %2d
+    pshufb    %1, %3
+%else
+    movd      %1, %2d
+    punpcklbw %1, %1
+    SPLATW    %1, %1, 0
+%endif
+%endmacro
+
+%macro HADDD 2 ; sum junk
+%if sizeof%1 == 32
+%define %2 xmm%2
+    vextracti128 %2, %1, 1
+%define %1 xmm%1
+    paddd   %1, %2
+%endif
+%if mmsize >= 16
+%if cpuflag(xop) && sizeof%1 == 16
+    vphadddq %1, %1
+%endif
+    movhlps %2, %1
+    paddd   %1, %2
+%endif
+%if notcpuflag(xop) || sizeof%1 != 16
+%if cpuflag(mmxext)
+    PSHUFLW %2, %1, q0032
+%else ; mmx
+    mova    %2, %1
+    psrlq   %2, 32
+%endif
+    paddd   %1, %2
+%endif
+%undef %1
+%undef %2
+%endmacro
+
+%macro HADDW 2 ; reg, tmp
+%if cpuflag(xop) && sizeof%1 == 16
+    vphaddwq  %1, %1
+    movhlps   %2, %1
+    paddd     %1, %2
+%else
+    pmaddwd %1, [pw_1]
+    HADDD   %1, %2
+%endif
+%endmacro
+
+%macro HADDPS 3 ; dst, src, tmp
+%if cpuflag(sse3)
+    haddps  %1, %1, %2
+%else
+    movaps  %3, %1
+    shufps  %1, %2, q2020
+    shufps  %3, %2, q3131
+    addps   %1, %3
+%endif
+%endmacro
+
+%macro PALIGNR 4-5
+%if cpuflag(ssse3)
+%if %0==5
+    palignr %1, %2, %3, %4
+%else
+    palignr %1, %2, %3
+%endif
+%else ; [dst,] src1, src2, imm, tmp
+    %define %%dst %1
+%if %0==5
+%ifnidn %1, %2
+    mova    %%dst, %2
+%endif
+    %rotate 1
+%endif
+%ifnidn %4, %2
+    mova    %4, %2
+%endif
+%if mmsize==8
+    psllq   %%dst, (8-%3)*8
+    psrlq   %4, %3*8
+%else
+    pslldq  %%dst, 16-%3
+    psrldq  %4, %3
+%endif
+    por     %%dst, %4
+%endif
+%endmacro
+
+%macro PAVGB 2-4
+%if cpuflag(mmxext)
+    pavgb   %1, %2
+%elif cpuflag(3dnow)
+    pavgusb %1, %2
+%elif cpuflag(mmx)
+    movu   %3, %2
+    por    %3, %1
+    pxor   %1, %2
+    pand   %1, %4
+    psrlq  %1, 1
+    psubb  %3, %1
+    SWAP   %1, %3
+%endif
+%endmacro
+
+%macro PSHUFLW 1+
+    %if mmsize == 8
+        pshufw %1
+    %else
+        pshuflw %1
+    %endif
+%endmacro
+
+%macro PSWAPD 2
+%if cpuflag(mmxext)
+    pshufw    %1, %2, q1032
+%elif cpuflag(3dnowext)
+    pswapd    %1, %2
+%elif cpuflag(3dnow)
+    movq      %1, %2
+    psrlq     %1, 32
+    punpckldq %1, %2
+%endif
+%endmacro
+
+%macro DEINTB 5 ; mask, reg1, mask, reg2, optional src to fill masks from
+%ifnum %5
+    pand   m%3, m%5, m%4 ; src .. y6 .. y4
+    pand   m%1, m%5, m%2 ; dst .. y6 .. y4
+%else
+    mova   m%1, %5
+    pand   m%3, m%1, m%4 ; src .. y6 .. y4
+    pand   m%1, m%1, m%2 ; dst .. y6 .. y4
+%endif
+    psrlw  m%2, 8        ; dst .. y7 .. y5
+    psrlw  m%4, 8        ; src .. y7 .. y5
+%endmacro
+
+%macro SUMSUB_BA 3-4
+%if %0==3
+    padd%1  m%2, m%3
+    padd%1  m%3, m%3
+    psub%1  m%3, m%2
+%else
+%if avx_enabled == 0
+    mova    m%4, m%2
+    padd%1  m%2, m%3
+    psub%1  m%3, m%4
+%else
+    padd%1  m%4, m%2, m%3
+    psub%1  m%3, m%2
+    SWAP    %2, %4
+%endif
+%endif
+%endmacro
+
+%macro SUMSUB_BADC 5-6
+%if %0==6
+    SUMSUB_BA %1, %2, %3, %6
+    SUMSUB_BA %1, %4, %5, %6
+%else
+    padd%1  m%2, m%3
+    padd%1  m%4, m%5
+    padd%1  m%3, m%3
+    padd%1  m%5, m%5
+    psub%1  m%3, m%2
+    psub%1  m%5, m%4
+%endif
+%endmacro
+
+%macro SUMSUB2_AB 4
+%ifnum %3
+    psub%1  m%4, m%2, m%3
+    psub%1  m%4, m%3
+    padd%1  m%2, m%2
+    padd%1  m%2, m%3
+%else
+    mova    m%4, m%2
+    padd%1  m%2, m%2
+    padd%1  m%2, %3
+    psub%1  m%4, %3
+    psub%1  m%4, %3
+%endif
+%endmacro
+
+%macro SUMSUB2_BA 4
+%if avx_enabled == 0
+    mova    m%4, m%2
+    padd%1  m%2, m%3
+    padd%1  m%2, m%3
+    psub%1  m%3, m%4
+    psub%1  m%3, m%4
+%else
+    padd%1  m%4, m%2, m%3
+    padd%1  m%4, m%3
+    psub%1  m%3, m%2
+    psub%1  m%3, m%2
+    SWAP     %2,  %4
+%endif
+%endmacro
+
+%macro SUMSUBD2_AB 5
+%ifnum %4
+    psra%1  m%5, m%2, 1  ; %3: %3>>1
+    psra%1  m%4, m%3, 1  ; %2: %2>>1
+    padd%1  m%4, m%2     ; %3: %3>>1+%2
+    psub%1  m%5, m%3     ; %2: %2>>1-%3
+    SWAP     %2, %5
+    SWAP     %3, %4
+%else
+    mova    %5, m%2
+    mova    %4, m%3
+    psra%1  m%3, 1  ; %3: %3>>1
+    psra%1  m%2, 1  ; %2: %2>>1
+    padd%1  m%3, %5 ; %3: %3>>1+%2
+    psub%1  m%2, %4 ; %2: %2>>1-%3
+%endif
+%endmacro
+
+%macro DCT4_1D 5
+%ifnum %5
+    SUMSUB_BADC w, %4, %1, %3, %2, %5
+    SUMSUB_BA   w, %3, %4, %5
+    SUMSUB2_AB  w, %1, %2, %5
+    SWAP %1, %3, %4, %5, %2
+%else
+    SUMSUB_BADC w, %4, %1, %3, %2
+    SUMSUB_BA   w, %3, %4
+    mova     [%5], m%2
+    SUMSUB2_AB  w, %1, [%5], %2
+    SWAP %1, %3, %4, %2
+%endif
+%endmacro
+
+%macro IDCT4_1D 6-7
+%ifnum %6
+    SUMSUBD2_AB %1, %3, %5, %7, %6
+    ; %3: %3>>1-%5 %5: %3+%5>>1
+    SUMSUB_BA   %1, %4, %2, %7
+    ; %4: %2+%4 %2: %2-%4
+    SUMSUB_BADC %1, %5, %4, %3, %2, %7
+    ; %5: %2+%4 + (%3+%5>>1)
+    ; %4: %2+%4 - (%3+%5>>1)
+    ; %3: %2-%4 + (%3>>1-%5)
+    ; %2: %2-%4 - (%3>>1-%5)
+%else
+%ifidn %1, w
+    SUMSUBD2_AB %1, %3, %5, [%6], [%6+16]
+%else
+    SUMSUBD2_AB %1, %3, %5, [%6], [%6+32]
+%endif
+    SUMSUB_BA   %1, %4, %2
+    SUMSUB_BADC %1, %5, %4, %3, %2
+%endif
+    SWAP %2, %5, %4
+    ; %2: %2+%4 + (%3+%5>>1) row0
+    ; %3: %2-%4 + (%3>>1-%5) row1
+    ; %4: %2-%4 - (%3>>1-%5) row2
+    ; %5: %2+%4 - (%3+%5>>1) row3
+%endmacro
+
+
+%macro LOAD_DIFF 5
+%ifidn %3, none
+    movh       %1, %4
+    movh       %2, %5
+    punpcklbw  %1, %2
+    punpcklbw  %2, %2
+    psubw      %1, %2
+%else
+    movh       %1, %4
+    punpcklbw  %1, %3
+    movh       %2, %5
+    punpcklbw  %2, %3
+    psubw      %1, %2
+%endif
+%endmacro
+
+%macro STORE_DCT 6
+    movq   [%5+%6+ 0], m%1
+    movq   [%5+%6+ 8], m%2
+    movq   [%5+%6+16], m%3
+    movq   [%5+%6+24], m%4
+    movhps [%5+%6+32], m%1
+    movhps [%5+%6+40], m%2
+    movhps [%5+%6+48], m%3
+    movhps [%5+%6+56], m%4
+%endmacro
+
+%macro LOAD_DIFF_8x4P 7-10 r0,r2,0 ; 4x dest, 2x temp, 2x pointer, increment?
+    LOAD_DIFF m%1, m%5, m%7, [%8],      [%9]
+    LOAD_DIFF m%2, m%6, m%7, [%8+r1],   [%9+r3]
+    LOAD_DIFF m%3, m%5, m%7, [%8+2*r1], [%9+2*r3]
+    LOAD_DIFF m%4, m%6, m%7, [%8+r4],   [%9+r5]
+%if %10
+    lea %8, [%8+4*r1]
+    lea %9, [%9+4*r3]
+%endif
+%endmacro
+
+%macro DIFFx2 6-7
+    movh       %3, %5
+    punpcklbw  %3, %4
+    psraw      %1, 6
+    paddsw     %1, %3
+    movh       %3, %6
+    punpcklbw  %3, %4
+    psraw      %2, 6
+    paddsw     %2, %3
+    packuswb   %2, %1
+%endmacro
+
+%macro STORE_DIFF 4
+    movh       %2, %4
+    punpcklbw  %2, %3
+    psraw      %1, 6
+    paddsw     %1, %2
+    packuswb   %1, %1
+    movh       %4, %1
+%endmacro
+
+%macro STORE_DIFFx2 8 ; add1, add2, reg1, reg2, zero, shift, source, stride
+    movh       %3, [%7]
+    movh       %4, [%7+%8]
+    psraw      %1, %6
+    psraw      %2, %6
+    punpcklbw  %3, %5
+    punpcklbw  %4, %5
+    paddw      %3, %1
+    paddw      %4, %2
+    packuswb   %3, %5
+    packuswb   %4, %5
+    movh     [%7], %3
+    movh  [%7+%8], %4
+%endmacro
+
+%macro PMINUB 3 ; dst, src, ignored
+%if cpuflag(mmxext)
+    pminub   %1, %2
+%else ; dst, src, tmp
+    mova     %3, %1
+    psubusb  %3, %2
+    psubb    %1, %3
+%endif
+%endmacro
+
+%macro SPLATW 2-3 0
+%if cpuflag(avx2) && %3 == 0
+    vpbroadcastw %1, %2
+%elif mmsize == 16
+    pshuflw    %1, %2, (%3)*0x55
+    punpcklqdq %1, %1
+%elif cpuflag(mmxext)
+    pshufw     %1, %2, (%3)*0x55
+%else
+    %ifnidn %1, %2
+        mova       %1, %2
+    %endif
+    %if %3 & 2
+        punpckhwd  %1, %1
+    %else
+        punpcklwd  %1, %1
+    %endif
+    %if %3 & 1
+        punpckhwd  %1, %1
+    %else
+        punpcklwd  %1, %1
+    %endif
+%endif
+%endmacro
+
+%macro SPLATD 1
+%if mmsize == 8
+    punpckldq  %1, %1
+%elif cpuflag(sse2)
+    pshufd  %1, %1, 0
+%elif cpuflag(sse)
+    shufps  %1, %1, 0
+%endif
+%endmacro
+
+%macro CLIPUB 3 ;(dst, min, max)
+    pmaxub %1, %2
+    pminub %1, %3
+%endmacro
+
+%macro CLIPW 3 ;(dst, min, max)
+    pmaxsw %1, %2
+    pminsw %1, %3
+%endmacro
+
+%macro PMINSD 3 ; dst, src, tmp/unused
+%if cpuflag(sse4)
+    pminsd    %1, %2
+%else
+    mova      %3, %2
+    pcmpgtd   %3, %1
+    pxor      %1, %2
+    pand      %1, %3
+    pxor      %1, %2
+%endif
+%endmacro
+
+%macro PMAXSD 3 ; dst, src, tmp/unused
+%if cpuflag(sse4)
+    pmaxsd    %1, %2
+%else
+    mova      %3, %1
+    pcmpgtd   %3, %2
+    pand      %1, %3
+    pandn     %3, %2
+    por       %1, %3
+%endif
+%endmacro
+
+%macro CLIPD 3-4
+%if cpuflag(sse4);  src/dst, min, max, unused
+    pminsd  %1, %3
+    pmaxsd  %1, %2
+%elif cpuflag(sse2) ; src/dst, min (float), max (float), unused
+    cvtdq2ps  %1, %1
+    minps     %1, %3
+    maxps     %1, %2
+    cvtps2dq  %1, %1
+%else               ; src/dst, min, max, tmp
+    PMINSD    %1, %3, %4
+    PMAXSD    %1, %2, %4
+%endif
+%endmacro
+
+%macro VBROADCASTSS 2 ; dst xmm/ymm, src m32/xmm
+%if cpuflag(avx2)
+    vbroadcastss  %1, %2
+%elif cpuflag(avx)
+    %ifnum sizeof%2         ; avx1 register
+        shufps  xmm%1, xmm%2, xmm%2, q0000
+        %if sizeof%1 >= 32  ; mmsize>=32
+            vinsertf128  %1, %1, xmm%1, 1
+        %endif
+    %else                   ; avx1 memory
+        vbroadcastss  %1, %2
+    %endif
+%else
+    %ifnum sizeof%2         ; sse register
+        shufps  %1, %2, %2, q0000
+    %else                   ; sse memory
+        movss   %1, %2
+        shufps  %1, %1, 0
+    %endif
+%endif
+%endmacro
+
+%macro VBROADCASTSD 2 ; dst xmm/ymm, src m64
+%if cpuflag(avx) && mmsize == 32
+    vbroadcastsd %1, %2
+%elif cpuflag(sse3)
+    movddup      %1, %2
+%else ; sse2
+    movsd        %1, %2
+    movlhps      %1, %1
+%endif
+%endmacro
+
+%macro VPBROADCASTD 2 ; dst xmm/ymm, src m32/xmm
+%if cpuflag(avx2)
+    vpbroadcastd  %1, %2
+%elif cpuflag(avx) && sizeof%1 >= 32
+    %error vpbroadcastd not possible with ymm on avx1. try vbroadcastss
+%else
+    %ifnum sizeof%2         ; sse2 register
+        pshufd  %1, %2, q0000
+    %else                   ; sse memory
+        movd    %1, %2
+        pshufd  %1, %1, 0
+    %endif
+%endif
+%endmacro
+
+%macro VBROADCASTI128 2 ; dst xmm/ymm, src : 128bits val
+%if mmsize > 16
+    vbroadcasti128 %1, %2
+%else
+    mova           %1, %2
+%endif
+%endmacro
+
+%macro SHUFFLE_MASK_W 8
+    %rep 8
+        %if %1>=0x80
+            db %1, %1
+        %else
+            db %1*2
+            db %1*2+1
+        %endif
+        %rotate 1
+    %endrep
+%endmacro
+
+%macro PMOVSXWD 2; dst, src
+%if cpuflag(sse4)
+    pmovsxwd     %1, %2
+%else
+    %ifnidn %1, %2
+    mova         %1, %2
+    %endif
+    punpcklwd    %1, %1
+    psrad        %1, 16
+%endif
+%endmacro
+
+; Wrapper for non-FMA version of fmaddps
+%macro FMULADD_PS 5
+    %if cpuflag(fma3) || cpuflag(fma4)
+        fmaddps %1, %2, %3, %4
+    %elifidn %1, %4
+        mulps   %5, %2, %3
+        addps   %1, %4, %5
+    %else
+        mulps   %1, %2, %3
+        addps   %1, %4
+    %endif
+%endmacro
+
+%macro LSHIFT 2
+%if mmsize > 8
+    pslldq  %1, %2
+%else
+    psllq   %1, 8*(%2)
+%endif
+%endmacro
+
+%macro RSHIFT 2
+%if mmsize > 8
+    psrldq  %1, %2
+%else
+    psrlq   %1, 8*(%2)
+%endif
+%endmacro
+
+%macro MOVHL 2 ; dst, src
+%ifidn %1, %2
+    punpckhqdq %1, %2
+%elif cpuflag(avx)
+    punpckhqdq %1, %2, %2
+%elif cpuflag(sse4)
+    pshufd     %1, %2, q3232 ; pshufd is slow on some older CPUs, so only use it on more modern ones
+%else
+    movhlps    %1, %2        ; may cause an int/float domain transition and has a dependency on dst
+%endif
+%endmacro
+
+; Horizontal Sum of Packed Single precision floats
+; The resulting sum is in all elements.
+%macro HSUMPS 2 ; dst/src, tmp
+%if cpuflag(avx)
+    %if sizeof%1>=32  ; avx
+        vperm2f128  %2, %1, %1, (0)*16+(1)
+        addps       %1, %2
+    %endif
+    shufps      %2, %1, %1, q1032
+    addps       %1, %2
+    shufps      %2, %1, %1, q0321
+    addps       %1, %2
+%else  ; this form is a bit faster than the short avx-like emulation.
+    movaps      %2, %1
+    shufps      %1, %1, q1032
+    addps       %1, %2
+    movaps      %2, %1
+    shufps      %1, %1, q0321
+    addps       %1, %2
+    ; all %1 members should be equal for as long as float a+b==b+a
+%endif
+%endmacro
+
+; Emulate blendvps if not available
+;
+; src_b is destroyed when using emulation with logical operands
+; SSE41 blendv instruction is hard coded to use xmm0 as mask
+%macro BLENDVPS 3 ; dst/src_a, src_b, mask
+%if cpuflag(avx)
+    blendvps  %1, %1, %2, %3
+%elif cpuflag(sse4)
+    %ifnidn %3,xmm0
+        %error sse41 blendvps uses xmm0 as default 3d operand, you used %3
+    %endif
+    blendvps  %1, %2, %3
+%else
+    xorps  %2, %1
+    andps  %2, %3
+    xorps  %1, %2
+%endif
+%endmacro
+
+; Emulate pblendvb if not available
+;
+; src_b is destroyed when using emulation with logical operands
+; SSE41 blendv instruction is hard coded to use xmm0 as mask
+%macro PBLENDVB 3 ; dst/src_a, src_b, mask
+%if cpuflag(avx)
+    %if cpuflag(avx) && notcpuflag(avx2) && sizeof%1 >= 32
+        %error pblendb not possible with ymm on avx1, try blendvps.
+    %endif
+    pblendvb  %1, %1, %2, %3
+%elif cpuflag(sse4)
+    %ifnidn %3,xmm0
+        %error sse41 pblendvd uses xmm0 as default 3d operand, you used %3
+    %endif
+    pblendvb  %1, %2, %3
+%else
+    pxor  %2, %1
+    pand  %2, %3
+    pxor  %1, %2
+%endif
+%endmacro
diff --git a/libs/ffmpeg/libavutil/xga_font_data.c b/libs/ffmpeg/libavutil/xga_font_data.c
new file mode 100644
index 000000000000..e4b21760f8b4
--- /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 000000000000..90d3cec4cefe
--- /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 000000000000..6f376c365c39
--- /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 000000000000..735427c109a1
--- /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/aarch64/audio_convert_init.c b/libs/ffmpeg/libswresample/aarch64/audio_convert_init.c
new file mode 100644
index 000000000000..60e24adb1c66
--- /dev/null
+++ b/libs/ffmpeg/libswresample/aarch64/audio_convert_init.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/aarch64/cpu.h"
+#include "libavutil/samplefmt.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
+void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels);
+void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels);
+
+static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){
+    swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len);
+}
+
+static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){
+    swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2);
+}
+
+static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){
+    int channels;
+    for(channels=3; channels<SWR_CH_MAX && src[channels]; channels++)
+        ;
+    swri_oldapi_conv_fltp_to_s16_nch_neon((int16_t*)*dst, (float *const*)src, len, channels);
+}
+
+av_cold void swri_audio_convert_init_aarch64(struct AudioConvert *ac,
+                                       enum AVSampleFormat out_fmt,
+                                       enum AVSampleFormat in_fmt,
+                                       int channels)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    ac->simd_f= NULL;
+
+    if (have_neon(cpu_flags)) {
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+            ac->simd_f = conv_flt_to_s16_neon;
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2)
+            ac->simd_f = conv_fltp_to_s16_2ch_neon;
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels >  2)
+            ac->simd_f = conv_fltp_to_s16_nch_neon;
+        if(ac->simd_f)
+            ac->in_simd_align_mask = ac->out_simd_align_mask = 15;
+    }
+}
diff --git a/libs/ffmpeg/libswresample/aarch64/audio_convert_neon.S b/libs/ffmpeg/libswresample/aarch64/audio_convert_neon.S
new file mode 100644
index 000000000000..6d789b16d26a
--- /dev/null
+++ b/libs/ffmpeg/libswresample/aarch64/audio_convert_neon.S
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ * Copyright (c) 2014 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
+ */
+
+#include "config.h"
+#include "libavutil/aarch64/asm.S"
+
+function swri_oldapi_conv_flt_to_s16_neon, export=1
+oldapi_conv_flt_to_s16_neon:
+        subs            x2,  x2,  #8
+        ld1             {v0.4s}, [x1],  #16
+        fcvtzs          v4.4s,  v0.4s,  #31
+        ld1             {v1.4s}, [x1],  #16
+        fcvtzs          v5.4s,  v1.4s,  #31
+        b.eq            3f
+        ands            x12, x2,  #~15
+        b.eq            2f
+1:      subs            x12, x12, #16
+        sqrshrn         v4.4h,  v4.4s,  #16
+        ld1             {v2.4s}, [x1],  #16
+        fcvtzs          v6.4s,  v2.4s,  #31
+        sqrshrn2        v4.8h,  v5.4s,  #16
+        ld1             {v3.4s}, [x1],  #16
+        fcvtzs          v7.4s,  v3.4s,  #31
+        sqrshrn         v6.4h,  v6.4s,  #16
+        st1             {v4.8h}, [x0],  #16
+        sqrshrn2        v6.8h,  v7.4s,  #16
+        ld1             {v0.4s}, [x1],  #16
+        fcvtzs          v4.4s,  v0.4s,  #31
+        ld1             {v1.4s}, [x1],  #16
+        fcvtzs          v5.4s,  v1.4s,  #31
+        st1             {v6.8h}, [x0],  #16
+        b.ne            1b
+        ands            x2,  x2,  #15
+        b.eq            3f
+2:      ld1             {v2.4s}, [x1],  #16
+        sqrshrn         v4.4h,  v4.4s,  #16
+        fcvtzs          v6.4s,  v2.4s,  #31
+        ld1             {v3.4s}, [x1],  #16
+        sqrshrn2        v4.8h,  v5.4s,  #16
+        fcvtzs          v7.4s,  v3.4s,  #31
+        sqrshrn         v6.4h,  v6.4s,  #16
+        st1             {v4.8h}, [x0],  #16
+        sqrshrn2        v6.8h,  v7.4s,  #16
+        st1             {v6.8h}, [x0]
+        ret
+3:      sqrshrn         v4.4h,  v4.4s,  #16
+        sqrshrn2        v4.8h,  v5.4s,  #16
+        st1             {v4.8h}, [x0]
+        ret
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_2ch_neon, export=1
+oldapi_conv_fltp_to_s16_2ch_neon:
+        ldp             x4,  x5,  [x1]
+        subs            x2,  x2,  #8
+        ld1             {v0.4s},  [x4], #16
+        fcvtzs          v4.4s,  v0.4s,  #31
+        ld1             {v1.4s},  [x4], #16
+        fcvtzs          v5.4s,  v1.4s,  #31
+        ld1             {v2.4s},  [x5], #16
+        fcvtzs          v6.4s,  v2.4s,  #31
+        ld1             {v3.4s},  [x5], #16
+        fcvtzs          v7.4s,  v3.4s,  #31
+        b.eq            3f
+        ands            x12, x2,  #~15
+        b.eq            2f
+1:      subs            x12, x12, #16
+        ld1             {v16.4s}, [x4], #16
+        fcvtzs          v20.4s, v16.4s, #31
+        sri             v6.4s,  v4.4s,  #16
+        ld1             {v17.4s}, [x4], #16
+        fcvtzs          v21.4s, v17.4s, #31
+        ld1             {v18.4s}, [x5], #16
+        fcvtzs          v22.4s, v18.4s, #31
+        ld1             {v19.4s}, [x5], #16
+        sri             v7.4s,  v5.4s,  #16
+        st1             {v6.4s},  [x0], #16
+        fcvtzs          v23.4s, v19.4s, #31
+        st1             {v7.4s},  [x0], #16
+        sri             v22.4s, v20.4s, #16
+        ld1             {v0.4s},  [x4], #16
+        sri             v23.4s, v21.4s, #16
+        st1             {v22.4s}, [x0], #16
+        fcvtzs          v4.4s,  v0.4s,  #31
+        ld1             {v1.4s},  [x4], #16
+        fcvtzs          v5.4s,  v1.4s,  #31
+        ld1             {v2.4s},  [x5], #16
+        fcvtzs          v6.4s,  v2.4s,  #31
+        ld1             {v3.4s},  [x5], #16
+        fcvtzs          v7.4s,  v3.4s,  #31
+        st1             {v23.4s}, [x0], #16
+        b.ne            1b
+        ands            x2,  x2,  #15
+        b.eq            3f
+2:      sri             v6.4s,  v4.4s,  #16
+        ld1             {v0.4s},  [x4], #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        ld1             {v1.4s},  [x4], #16
+        fcvtzs          v1.4s,  v1.4s,  #31
+        ld1             {v2.4s},  [x5], #16
+        fcvtzs          v2.4s,  v2.4s,  #31
+        sri             v7.4s,  v5.4s,  #16
+        ld1             {v3.4s},  [x5], #16
+        fcvtzs          v3.4s,  v3.4s,  #31
+        sri             v2.4s,  v0.4s,  #16
+        st1             {v6.4s,v7.4s},  [x0], #32
+        sri             v3.4s,  v1.4s,  #16
+        st1             {v2.4s,v3.4s},  [x0], #32
+        ret
+3:      sri             v6.4s,  v4.4s,  #16
+        sri             v7.4s,  v5.4s,  #16
+        st1             {v6.4s,v7.4s},  [x0]
+        ret
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1
+        cmp             w3,  #2
+        b.eq            oldapi_conv_fltp_to_s16_2ch_neon
+        b.gt            1f
+        ldr             x1,  [x1]
+        b               oldapi_conv_flt_to_s16_neon
+1:
+        cmp             w3,  #4
+        lsl             x12, x3,  #1
+        b.lt            4f
+
+5:      // 4 channels
+        ldp             x4, x5, [x1], #16
+        ldp             x6, x7, [x1], #16
+        mov             w9,  w2
+        mov             x8,  x0
+        ld1             {v4.4s},        [x4], #16
+        fcvtzs          v4.4s,  v4.4s,  #31
+        ld1             {v5.4s},        [x5], #16
+        fcvtzs          v5.4s,  v5.4s,  #31
+        ld1             {v6.4s},        [x6], #16
+        fcvtzs          v6.4s, v6.4s, #31
+        ld1             {v7.4s},        [x7], #16
+        fcvtzs          v7.4s, v7.4s, #31
+6:
+        subs            w9,  w9,  #8
+        ld1             {v0.4s},        [x4], #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        sri             v5.4s,  v4.4s,  #16
+        ld1             {v1.4s},        [x5], #16
+        fcvtzs          v1.4s,  v1.4s,  #31
+        sri             v7.4s,  v6.4s,  #16
+        ld1             {v2.4s},        [x6], #16
+        fcvtzs          v2.4s,  v2.4s,  #31
+        zip1            v16.4s, v5.4s,  v7.4s
+        ld1             {v3.4s},        [x7], #16
+        fcvtzs          v3.4s,  v3.4s,  #31
+        zip2            v17.4s, v5.4s,  v7.4s
+        st1             {v16.d}[0],     [x8], x12
+        sri             v1.4s,  v0.4s,  #16
+        st1             {v16.d}[1],     [x8], x12
+        sri             v3.4s,  v2.4s,  #16
+        st1             {v17.d}[0],     [x8], x12
+        zip1            v18.4s, v1.4s,  v3.4s
+        st1             {v17.d}[1],     [x8], x12
+        zip2            v19.4s, v1.4s,  v3.4s
+        b.eq            7f
+        ld1             {v4.4s},        [x4], #16
+        fcvtzs          v4.4s,  v4.4s,  #31
+        st1             {v18.d}[0],     [x8], x12
+        ld1             {v5.4s},        [x5], #16
+        fcvtzs          v5.4s,  v5.4s,  #31
+        st1             {v18.d}[1],     [x8], x12
+        ld1             {v6.4s},    [x6], #16
+        fcvtzs          v6.4s, v6.4s, #31
+        st1             {v19.d}[0],     [x8], x12
+        ld1             {v7.4s},    [x7], #16
+        fcvtzs          v7.4s, v7.4s, #31
+        st1             {v19.d}[1],     [x8], x12
+        b               6b
+7:
+        st1             {v18.d}[0],     [x8], x12
+        st1             {v18.d}[1],     [x8], x12
+        st1             {v19.d}[0],     [x8], x12
+        st1             {v19.d}[1],     [x8], x12
+        subs            w3,  w3,  #4
+        b.eq            end
+        cmp             w3,  #4
+        add             x0,  x0,  #8
+        b.ge            5b
+
+4:      // 2 channels
+        cmp             w3,  #2
+        b.lt            4f
+        ldp             x4,  x5,  [x1], #16
+        mov             w9,  w2
+        mov             x8,  x0
+        tst             w9,  #8
+        ld1             {v4.4s},        [x4], #16
+        fcvtzs          v4.4s,  v4.4s,  #31
+        ld1             {v5.4s},        [x5], #16
+        fcvtzs          v5.4s,  v5.4s,  #31
+        ld1             {v6.4s},        [x4], #16
+        fcvtzs          v6.4s,  v6.4s,  #31
+        ld1             {v7.4s},        [x5], #16
+        fcvtzs          v7.4s,  v7.4s,  #31
+        b.eq            6f
+        subs            w9,  w9,  #8
+        b.eq            7f
+        sri             v5.4s,  v4.4s,  #16
+        ld1             {v4.4s},        [x4], #16
+        fcvtzs          v4.4s,  v4.4s,  #31
+        st1             {v5.s}[0],      [x8], x12
+        sri             v7.4s,  v6.4s,  #16
+        st1             {v5.s}[1],      [x8], x12
+        ld1             {v6.4s},        [x4], #16
+        fcvtzs          v6.4s,  v6.4s, #31
+        st1             {v5.s}[2],      [x8], x12
+        st1             {v5.s}[3],      [x8], x12
+        st1             {v7.s}[0],      [x8], x12
+        st1             {v7.s}[1],      [x8], x12
+        ld1             {v5.4s},        [x5], #16
+        fcvtzs          v5.4s,  v5.4s,  #31
+        st1             {v7.s}[2],      [x8], x12
+        st1             {v7.s}[3],      [x8], x12
+        ld1             {v7.4s},        [x5], #16
+        fcvtzs          v7.4s,  v7.4s,  #31
+6:
+        subs            w9,  w9,  #16
+        ld1             {v0.4s},        [x4], #16
+        sri             v5.4s,  v4.4s,  #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        ld1             {v1.4s},        [x5], #16
+        sri             v7.4s,  v6.4s,  #16
+        st1             {v5.s}[0],      [x8], x12
+        st1             {v5.s}[1],      [x8], x12
+        fcvtzs          v1.4s,  v1.4s,  #31
+        st1             {v5.s}[2],      [x8], x12
+        st1             {v5.s}[3],      [x8], x12
+        ld1             {v2.4s},        [x4], #16
+        st1             {v7.s}[0],      [x8], x12
+        fcvtzs          v2.4s,  v2.4s,  #31
+        st1             {v7.s}[1],      [x8], x12
+        ld1             {v3.4s},        [x5], #16
+        st1             {v7.s}[2],      [x8], x12
+        fcvtzs          v3.4s,  v3.4s,  #31
+        st1             {v7.s}[3],      [x8], x12
+        sri             v1.4s,  v0.4s,  #16
+        sri             v3.4s,  v2.4s,  #16
+        b.eq            6f
+        ld1             {v4.4s},        [x4], #16
+        st1             {v1.s}[0],      [x8], x12
+        fcvtzs          v4.4s,  v4.4s,  #31
+        st1             {v1.s}[1],      [x8], x12
+        ld1             {v5.4s},        [x5], #16
+        st1             {v1.s}[2],      [x8], x12
+        fcvtzs          v5.4s,  v5.4s,  #31
+        st1             {v1.s}[3],      [x8], x12
+        ld1             {v6.4s},        [x4], #16
+        st1             {v3.s}[0],      [x8], x12
+        fcvtzs          v6.4s,  v6.4s,  #31
+        st1             {v3.s}[1],      [x8], x12
+        ld1             {v7.4s},        [x5], #16
+        st1             {v3.s}[2],      [x8], x12
+        fcvtzs          v7.4s,  v7.4s,  #31
+        st1             {v3.s}[3],      [x8], x12
+        b.gt            6b
+6:
+        st1             {v1.s}[0],      [x8], x12
+        st1             {v1.s}[1],      [x8], x12
+        st1             {v1.s}[2],      [x8], x12
+        st1             {v1.s}[3],      [x8], x12
+        st1             {v3.s}[0],      [x8], x12
+        st1             {v3.s}[1],      [x8], x12
+        st1             {v3.s}[2],      [x8], x12
+        st1             {v3.s}[3],      [x8], x12
+        b               8f
+7:
+        sri             v5.4s,  v4.4s,  #16
+        sri             v7.4s,  v6.4s,  #16
+        st1             {v5.s}[0],      [x8], x12
+        st1             {v5.s}[1],      [x8], x12
+        st1             {v5.s}[2],      [x8], x12
+        st1             {v5.s}[3],      [x8], x12
+        st1             {v7.s}[0],      [x8], x12
+        st1             {v7.s}[1],      [x8], x12
+        st1             {v7.s}[2],      [x8], x12
+        st1             {v7.s}[3],      [x8], x12
+8:
+        subs            w3,  w3,  #2
+        add             x0,  x0,  #4
+        b.eq            end
+
+4:      // 1 channel
+        ldr             x4,  [x1]
+        tst             w2,  #8
+        mov             w9,  w2
+        mov             x5,  x0
+        ld1             {v0.4s},        [x4], #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        ld1             {v1.4s},        [x4], #16
+        fcvtzs          v1.4s,  v1.4s,  #31
+        b.ne            8f
+6:
+        subs            w9,  w9,  #16
+        ld1             {v2.4s},        [x4], #16
+        fcvtzs          v2.4s,  v2.4s,  #31
+        ld1             {v3.4s},        [x4], #16
+        fcvtzs          v3.4s,  v3.4s,  #31
+        st1             {v0.h}[1],      [x5], x12
+        st1             {v0.h}[3],      [x5], x12
+        st1             {v0.h}[5],      [x5], x12
+        st1             {v0.h}[7],      [x5], x12
+        st1             {v1.h}[1],      [x5], x12
+        st1             {v1.h}[3],      [x5], x12
+        st1             {v1.h}[5],      [x5], x12
+        st1             {v1.h}[7],      [x5], x12
+        b.eq            7f
+        ld1             {v0.4s},        [x4], #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        ld1             {v1.4s},        [x4], #16
+        fcvtzs          v1.4s,  v1.4s,  #31
+7:
+        st1             {v2.h}[1],      [x5], x12
+        st1             {v2.h}[3],      [x5], x12
+        st1             {v2.h}[5],      [x5], x12
+        st1             {v2.h}[7],      [x5], x12
+        st1             {v3.h}[1],      [x5], x12
+        st1             {v3.h}[3],      [x5], x12
+        st1             {v3.h}[5],      [x5], x12
+        st1             {v3.h}[7],      [x5], x12
+        b.gt            6b
+        ret
+8:
+        subs            w9,  w9,  #8
+        st1             {v0.h}[1],      [x5], x12
+        st1             {v0.h}[3],      [x5], x12
+        st1             {v0.h}[5],      [x5], x12
+        st1             {v0.h}[7],      [x5], x12
+        st1             {v1.h}[1],      [x5], x12
+        st1             {v1.h}[3],      [x5], x12
+        st1             {v1.h}[5],      [x5], x12
+        st1             {v1.h}[7],      [x5], x12
+        b.eq            end
+        ld1             {v0.4s},        [x4], #16
+        fcvtzs          v0.4s,  v0.4s,  #31
+        ld1             {v1.4s},        [x4], #16
+        fcvtzs          v1.4s,  v1.4s,  #31
+        b               6b
+end:
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswresample/aarch64/resample.S b/libs/ffmpeg/libswresample/aarch64/resample.S
new file mode 100644
index 000000000000..89edd1ce6042
--- /dev/null
+++ b/libs/ffmpeg/libswresample/aarch64/resample.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017 Matthieu Bouron <matthieu.bouron 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/aarch64/asm.S"
+
+function ff_resample_common_apply_filter_x4_float_neon, export=1
+        movi            v0.4s, #0                                      // accumulator
+1:      ld1             {v1.4s}, [x1], #16                             // src[0..3]
+        ld1             {v2.4s}, [x2], #16                             // filter[0..3]
+        fmla            v0.4s, v1.4s, v2.4s                            // accumulator += src[0..3] * filter[0..3]
+        subs            w3, w3, #4                                     // filter_length -= 4
+        b.gt            1b                                             // loop until filter_length
+        faddp           v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        faddp           v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        st1             {v0.s}[0], [x0], #4                            // write accumulator
+        ret
+endfunc
+
+function ff_resample_common_apply_filter_x8_float_neon, export=1
+        movi            v0.4s, #0                                      // accumulator
+1:      ld1             {v1.4s}, [x1], #16                             // src[0..3]
+        ld1             {v2.4s}, [x2], #16                             // filter[0..3]
+        ld1             {v3.4s}, [x1], #16                             // src[4..7]
+        ld1             {v4.4s}, [x2], #16                             // filter[4..7]
+        fmla            v0.4s, v1.4s, v2.4s                            // accumulator += src[0..3] * filter[0..3]
+        fmla            v0.4s, v3.4s, v4.4s                            // accumulator += src[4..7] * filter[4..7]
+        subs            w3, w3, #8                                     // filter_length -= 8
+        b.gt            1b                                             // loop until filter_length
+        faddp           v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        faddp           v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        st1             {v0.s}[0], [x0], #4                            // write accumulator
+        ret
+endfunc
+
+function ff_resample_common_apply_filter_x4_s16_neon, export=1
+        movi            v0.4s, #0                                      // accumulator
+1:      ld1             {v1.4h}, [x1], #8                              // src[0..3]
+        ld1             {v2.4h}, [x2], #8                              // filter[0..3]
+        smlal           v0.4s, v1.4h, v2.4h                            // accumulator += src[0..3] * filter[0..3]
+        subs            w3, w3, #4                                     // filter_length -= 4
+        b.gt            1b                                             // loop until filter_length
+        addp            v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        addp            v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        st1             {v0.s}[0], [x0], #4                            // write accumulator
+        ret
+endfunc
+
+function ff_resample_common_apply_filter_x8_s16_neon, export=1
+        movi            v0.4s, #0                                      // accumulator
+1:      ld1             {v1.8h}, [x1], #16                             // src[0..7]
+        ld1             {v2.8h}, [x2], #16                             // filter[0..7]
+        smlal           v0.4s, v1.4h, v2.4h                            // accumulator += src[0..3] * filter[0..3]
+        smlal2          v0.4s, v1.8h, v2.8h                            // accumulator += src[4..7] * filter[4..7]
+        subs            w3, w3, #8                                     // filter_length -= 8
+        b.gt            1b                                             // loop until filter_length
+        addp            v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        addp            v0.4s, v0.4s, v0.4s                            // pair adding of the 4x32-bit accumulated values
+        st1             {v0.s}[0], [x0], #4                            // write accumulator
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswresample/aarch64/resample_init.c b/libs/ffmpeg/libswresample/aarch64/resample_init.c
new file mode 100644
index 000000000000..87e4dd941d6c
--- /dev/null
+++ b/libs/ffmpeg/libswresample/aarch64/resample_init.c
@@ -0,0 +1,121 @@
+/*
+ * 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
+ */
+
+#include "config.h"
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/avassert.h"
+
+#include "libavutil/aarch64/cpu.h"
+#include "libswresample/resample.h"
+
+#define DECLARE_RESAMPLE_COMMON_TEMPLATE(TYPE, DELEM, FELEM, FELEM2, OUT)                         \
+                                                                                                  \
+void ff_resample_common_apply_filter_x4_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+void ff_resample_common_apply_filter_x8_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+static int ff_resample_common_##TYPE##_neon(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;                                                                         \
+    int x4_aligned_filter_length = c->filter_length & ~3;                                         \
+    int x8_aligned_filter_length = c->filter_length & ~7;                                         \
+                                                                                                  \
+    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 = 0;                                                                             \
+        int i = 0;                                                                                \
+        if (x8_aligned_filter_length >= 8) {                                                      \
+            ff_resample_common_apply_filter_x8_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x8_aligned_filter_length);   \
+            i += x8_aligned_filter_length;                                                        \
+                                                                                                  \
+        } else if (x4_aligned_filter_length >= 4) {                                               \
+            ff_resample_common_apply_filter_x4_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x4_aligned_filter_length);   \
+            i += x4_aligned_filter_length;                                                        \
+        }                                                                                         \
+        for (; i < c->filter_length; i++) {                                                       \
+            val += src[sample_index + i] * (FELEM2)filter[i];                                     \
+        }                                                                                         \
+        OUT(dst[dst_index], 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;                                                                          \
+}                                                                                                 \
+
+#define OUT(d, v) d = v
+DECLARE_RESAMPLE_COMMON_TEMPLATE(float, float, float, float, OUT)
+#undef OUT
+
+#define OUT(d, v) (v) = ((v) + (1<<(14)))>>15; (d) = av_clip_int16(v)
+DECLARE_RESAMPLE_COMMON_TEMPLATE(s16, int16_t, int16_t, int32_t, OUT)
+#undef OUT
+
+av_cold void swri_resample_dsp_aarch64_init(ResampleContext *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (!have_neon(cpu_flags))
+        return;
+
+    switch(c->format) {
+    case AV_SAMPLE_FMT_FLTP:
+        c->dsp.resample_common = ff_resample_common_float_neon;
+        break;
+    case AV_SAMPLE_FMT_S16P:
+        c->dsp.resample_common = ff_resample_common_s16_neon;
+        break;
+    }
+}
diff --git a/libs/ffmpeg/libswresample/arm/audio_convert_init.c b/libs/ffmpeg/libswresample/arm/audio_convert_init.c
new file mode 100644
index 000000000000..ec9e62ede729
--- /dev/null
+++ b/libs/ffmpeg/libswresample/arm/audio_convert_init.c
@@ -0,0 +1,67 @@
+/*
+ * 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 <stdint.h>
+
+#include "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/arm/cpu.h"
+#include "libavutil/samplefmt.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+void swri_oldapi_conv_flt_to_s16_neon(int16_t *dst, const float *src, int len);
+void swri_oldapi_conv_fltp_to_s16_2ch_neon(int16_t *dst, float *const *src, int len, int channels);
+void swri_oldapi_conv_fltp_to_s16_nch_neon(int16_t *dst, float *const *src, int len, int channels);
+
+static void conv_flt_to_s16_neon(uint8_t **dst, const uint8_t **src, int len){
+    swri_oldapi_conv_flt_to_s16_neon((int16_t*)*dst, (const float*)*src, len);
+}
+
+static void conv_fltp_to_s16_2ch_neon(uint8_t **dst, const uint8_t **src, int len){
+    swri_oldapi_conv_fltp_to_s16_2ch_neon((int16_t*)*dst, (float *const*)src, len, 2);
+}
+
+static void conv_fltp_to_s16_nch_neon(uint8_t **dst, const uint8_t **src, int len){
+    int channels;
+    for(channels=3; channels<SWR_CH_MAX && src[channels]; channels++)
+        ;
+    swri_oldapi_conv_fltp_to_s16_nch_neon((int16_t*)*dst, (float *const*)src, len, channels);
+}
+
+av_cold void swri_audio_convert_init_arm(struct AudioConvert *ac,
+                                       enum AVSampleFormat out_fmt,
+                                       enum AVSampleFormat in_fmt,
+                                       int channels)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    ac->simd_f= NULL;
+
+    if (have_neon(cpu_flags)) {
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+            ac->simd_f = conv_flt_to_s16_neon;
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels == 2)
+            ac->simd_f = conv_fltp_to_s16_2ch_neon;
+        if(out_fmt == AV_SAMPLE_FMT_S16 && in_fmt == AV_SAMPLE_FMT_FLTP && channels >  2)
+            ac->simd_f = conv_fltp_to_s16_nch_neon;
+        if(ac->simd_f)
+            ac->in_simd_align_mask = ac->out_simd_align_mask = 15;
+    }
+}
diff --git a/libs/ffmpeg/libswresample/arm/audio_convert_neon.S b/libs/ffmpeg/libswresample/arm/audio_convert_neon.S
new file mode 100644
index 000000000000..085d50aafa5c
--- /dev/null
+++ b/libs/ffmpeg/libswresample/arm/audio_convert_neon.S
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2008 Mans Rullgard <mans@mansr.com>
+ *
+ * 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 "config.h"
+#include "libavutil/arm/asm.S"
+
+function swri_oldapi_conv_flt_to_s16_neon, export=1
+.L_swri_oldapi_conv_flt_to_s16_neon:
+        subs            r2,  r2,  #8
+        vld1.32         {q0},     [r1,:128]!
+        vcvt.s32.f32    q8,  q0,  #31
+        vld1.32         {q1},     [r1,:128]!
+        vcvt.s32.f32    q9,  q1,  #31
+        beq             3f
+        bics            r12, r2,  #15
+        beq             2f
+1:      subs            r12, r12, #16
+        vqrshrn.s32     d4,  q8,  #16
+        vld1.32         {q0},     [r1,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vqrshrn.s32     d5,  q9,  #16
+        vld1.32         {q1},     [r1,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        vqrshrn.s32     d6,  q0,  #16
+        vst1.16         {q2},     [r0,:128]!
+        vqrshrn.s32     d7,  q1,  #16
+        vld1.32         {q8},     [r1,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vld1.32         {q9},     [r1,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vst1.16         {q3},     [r0,:128]!
+        bne             1b
+        ands            r2,  r2,  #15
+        beq             3f
+2:      vld1.32         {q0},     [r1,:128]!
+        vqrshrn.s32     d4,  q8,  #16
+        vcvt.s32.f32    q0,  q0,  #31
+        vld1.32         {q1},     [r1,:128]!
+        vqrshrn.s32     d5,  q9,  #16
+        vcvt.s32.f32    q1,  q1,  #31
+        vqrshrn.s32     d6,  q0,  #16
+        vst1.16         {q2},     [r0,:128]!
+        vqrshrn.s32     d7,  q1,  #16
+        vst1.16         {q3},     [r0,:128]!
+        bx              lr
+3:      vqrshrn.s32     d4,  q8,  #16
+        vqrshrn.s32     d5,  q9,  #16
+        vst1.16         {q2},     [r0,:128]!
+        bx              lr
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_2ch_neon, export=1
+.L_swri_oldapi_conv_fltp_to_s16_2ch_neon:
+        ldm             r1,  {r1, r3}
+        subs            r2,  r2,  #8
+        vld1.32         {q0},     [r1,:128]!
+        vcvt.s32.f32    q8,  q0,  #31
+        vld1.32         {q1},     [r1,:128]!
+        vcvt.s32.f32    q9,  q1,  #31
+        vld1.32         {q10},    [r3,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vld1.32         {q11},    [r3,:128]!
+        vcvt.s32.f32    q11, q11, #31
+        beq             3f
+        bics            r12, r2,  #15
+        beq             2f
+1:      subs            r12, r12, #16
+        vld1.32         {q0},     [r1,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vsri.32         q10, q8,  #16
+        vld1.32         {q1},     [r1,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        vld1.32         {q12},    [r3,:128]!
+        vcvt.s32.f32    q12, q12, #31
+        vld1.32         {q13},    [r3,:128]!
+        vsri.32         q11, q9,  #16
+        vst1.16         {q10},    [r0,:128]!
+        vcvt.s32.f32    q13, q13, #31
+        vst1.16         {q11},    [r0,:128]!
+        vsri.32         q12, q0,  #16
+        vld1.32         {q8},     [r1,:128]!
+        vsri.32         q13, q1,  #16
+        vst1.16         {q12},    [r0,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vld1.32         {q9},     [r1,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vld1.32         {q10},    [r3,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vld1.32         {q11},    [r3,:128]!
+        vcvt.s32.f32    q11, q11, #31
+        vst1.16         {q13},    [r0,:128]!
+        bne             1b
+        ands            r2,  r2,  #15
+        beq             3f
+2:      vsri.32         q10, q8,  #16
+        vld1.32         {q0},     [r1,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vld1.32         {q1},     [r1,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        vld1.32         {q12},    [r3,:128]!
+        vcvt.s32.f32    q12, q12, #31
+        vsri.32         q11, q9,  #16
+        vld1.32         {q13},    [r3,:128]!
+        vcvt.s32.f32    q13, q13, #31
+        vst1.16         {q10},    [r0,:128]!
+        vsri.32         q12, q0,  #16
+        vst1.16         {q11},    [r0,:128]!
+        vsri.32         q13, q1,  #16
+        vst1.16         {q12-q13},[r0,:128]!
+        bx              lr
+3:      vsri.32         q10, q8,  #16
+        vsri.32         q11, q9,  #16
+        vst1.16         {q10-q11},[r0,:128]!
+        bx              lr
+endfunc
+
+function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1
+        cmp             r3,  #2
+        itt             lt
+        ldrlt           r1,  [r1]
+        blt             .L_swri_oldapi_conv_flt_to_s16_neon
+        beq             .L_swri_oldapi_conv_fltp_to_s16_2ch_neon
+
+        push            {r4-r8, lr}
+        cmp             r3,  #4
+        lsl             r12, r3,  #1
+        blt             4f
+
+        @ 4 channels
+5:      ldm             r1!, {r4-r7}
+        mov             lr,  r2
+        mov             r8,  r0
+        vld1.32         {q8},     [r4,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vld1.32         {q9},     [r5,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vld1.32         {q10},    [r6,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vld1.32         {q11},    [r7,:128]!
+        vcvt.s32.f32    q11, q11, #31
+6:      subs            lr,  lr,  #8
+        vld1.32         {q0},     [r4,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vsri.32         q9,  q8,  #16
+        vld1.32         {q1},     [r5,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        vsri.32         q11, q10, #16
+        vld1.32         {q2},     [r6,:128]!
+        vcvt.s32.f32    q2,  q2,  #31
+        vzip.32         d18, d22
+        vld1.32         {q3},     [r7,:128]!
+        vcvt.s32.f32    q3,  q3,  #31
+        vzip.32         d19, d23
+        vst1.16         {d18},    [r8], r12
+        vsri.32         q1,  q0,  #16
+        vst1.16         {d22},    [r8], r12
+        vsri.32         q3,  q2,  #16
+        vst1.16         {d19},    [r8], r12
+        vzip.32         d2,  d6
+        vst1.16         {d23},    [r8], r12
+        vzip.32         d3,  d7
+        beq             7f
+        vld1.32         {q8},     [r4,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vst1.16         {d2},     [r8], r12
+        vld1.32         {q9},     [r5,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vst1.16         {d6},     [r8], r12
+        vld1.32         {q10},    [r6,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vst1.16         {d3},     [r8], r12
+        vld1.32         {q11},    [r7,:128]!
+        vcvt.s32.f32    q11, q11, #31
+        vst1.16         {d7},     [r8], r12
+        b               6b
+7:      vst1.16         {d2},     [r8], r12
+        vst1.16         {d6},     [r8], r12
+        vst1.16         {d3},     [r8], r12
+        vst1.16         {d7},     [r8], r12
+        subs            r3,  r3,  #4
+        it              eq
+        popeq           {r4-r8, pc}
+        cmp             r3,  #4
+        add             r0,  r0,  #8
+        bge             5b
+
+        @ 2 channels
+4:      cmp             r3,  #2
+        blt             4f
+        ldm             r1!, {r4-r5}
+        mov             lr,  r2
+        mov             r8,  r0
+        tst             lr,  #8
+        vld1.32         {q8},     [r4,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vld1.32         {q9},     [r5,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vld1.32         {q10},    [r4,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vld1.32         {q11},    [r5,:128]!
+        vcvt.s32.f32    q11, q11, #31
+        beq             6f
+        subs            lr,  lr,  #8
+        beq             7f
+        vsri.32         d18, d16, #16
+        vsri.32         d19, d17, #16
+        vld1.32         {q8},     [r4,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vst1.32         {d18[0]}, [r8], r12
+        vsri.32         d22, d20, #16
+        vst1.32         {d18[1]}, [r8], r12
+        vsri.32         d23, d21, #16
+        vst1.32         {d19[0]}, [r8], r12
+        vst1.32         {d19[1]}, [r8], r12
+        vld1.32         {q9},     [r5,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vst1.32         {d22[0]}, [r8], r12
+        vst1.32         {d22[1]}, [r8], r12
+        vld1.32         {q10},    [r4,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vst1.32         {d23[0]}, [r8], r12
+        vst1.32         {d23[1]}, [r8], r12
+        vld1.32         {q11},    [r5,:128]!
+        vcvt.s32.f32    q11, q11, #31
+6:      subs            lr,  lr,  #16
+        vld1.32         {q0},     [r4,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vsri.32         d18, d16, #16
+        vld1.32         {q1},     [r5,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        vsri.32         d19, d17, #16
+        vld1.32         {q2},     [r4,:128]!
+        vcvt.s32.f32    q2,  q2,  #31
+        vld1.32         {q3},     [r5,:128]!
+        vcvt.s32.f32    q3,  q3,  #31
+        vst1.32         {d18[0]}, [r8], r12
+        vsri.32         d22, d20, #16
+        vst1.32         {d18[1]}, [r8], r12
+        vsri.32         d23, d21, #16
+        vst1.32         {d19[0]}, [r8], r12
+        vsri.32         d2,  d0,  #16
+        vst1.32         {d19[1]}, [r8], r12
+        vsri.32         d3,  d1,  #16
+        vst1.32         {d22[0]}, [r8], r12
+        vsri.32         d6,  d4,  #16
+        vst1.32         {d22[1]}, [r8], r12
+        vsri.32         d7,  d5,  #16
+        vst1.32         {d23[0]}, [r8], r12
+        vst1.32         {d23[1]}, [r8], r12
+        beq             6f
+        vld1.32         {q8},     [r4,:128]!
+        vcvt.s32.f32    q8,  q8,  #31
+        vst1.32         {d2[0]},  [r8], r12
+        vst1.32         {d2[1]},  [r8], r12
+        vld1.32         {q9},     [r5,:128]!
+        vcvt.s32.f32    q9,  q9,  #31
+        vst1.32         {d3[0]},  [r8], r12
+        vst1.32         {d3[1]},  [r8], r12
+        vld1.32         {q10},    [r4,:128]!
+        vcvt.s32.f32    q10, q10, #31
+        vst1.32         {d6[0]},  [r8], r12
+        vst1.32         {d6[1]},  [r8], r12
+        vld1.32         {q11},    [r5,:128]!
+        vcvt.s32.f32    q11, q11, #31
+        vst1.32         {d7[0]},  [r8], r12
+        vst1.32         {d7[1]},  [r8], r12
+        bgt             6b
+6:      vst1.32         {d2[0]},  [r8], r12
+        vst1.32         {d2[1]},  [r8], r12
+        vst1.32         {d3[0]},  [r8], r12
+        vst1.32         {d3[1]},  [r8], r12
+        vst1.32         {d6[0]},  [r8], r12
+        vst1.32         {d6[1]},  [r8], r12
+        vst1.32         {d7[0]},  [r8], r12
+        vst1.32         {d7[1]},  [r8], r12
+        b               8f
+7:      vsri.32         d18, d16, #16
+        vsri.32         d19, d17, #16
+        vst1.32         {d18[0]}, [r8], r12
+        vsri.32         d22, d20, #16
+        vst1.32         {d18[1]}, [r8], r12
+        vsri.32         d23, d21, #16
+        vst1.32         {d19[0]}, [r8], r12
+        vst1.32         {d19[1]}, [r8], r12
+        vst1.32         {d22[0]}, [r8], r12
+        vst1.32         {d22[1]}, [r8], r12
+        vst1.32         {d23[0]}, [r8], r12
+        vst1.32         {d23[1]}, [r8], r12
+8:      subs            r3,  r3,  #2
+        add             r0,  r0,  #4
+        it              eq
+        popeq           {r4-r8, pc}
+
+        @ 1 channel
+4:      ldr             r4,  [r1]
+        tst             r2,  #8
+        mov             lr,  r2
+        mov             r5,  r0
+        vld1.32         {q0},     [r4,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vld1.32         {q1},     [r4,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        bne             8f
+6:      subs            lr,  lr,  #16
+        vld1.32         {q2},     [r4,:128]!
+        vcvt.s32.f32    q2,  q2,  #31
+        vld1.32         {q3},     [r4,:128]!
+        vcvt.s32.f32    q3,  q3,  #31
+        vst1.16         {d0[1]},  [r5,:16], r12
+        vst1.16         {d0[3]},  [r5,:16], r12
+        vst1.16         {d1[1]},  [r5,:16], r12
+        vst1.16         {d1[3]},  [r5,:16], r12
+        vst1.16         {d2[1]},  [r5,:16], r12
+        vst1.16         {d2[3]},  [r5,:16], r12
+        vst1.16         {d3[1]},  [r5,:16], r12
+        vst1.16         {d3[3]},  [r5,:16], r12
+        beq             7f
+        vld1.32         {q0},     [r4,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vld1.32         {q1},     [r4,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+7:      vst1.16         {d4[1]},  [r5,:16], r12
+        vst1.16         {d4[3]},  [r5,:16], r12
+        vst1.16         {d5[1]},  [r5,:16], r12
+        vst1.16         {d5[3]},  [r5,:16], r12
+        vst1.16         {d6[1]},  [r5,:16], r12
+        vst1.16         {d6[3]},  [r5,:16], r12
+        vst1.16         {d7[1]},  [r5,:16], r12
+        vst1.16         {d7[3]},  [r5,:16], r12
+        bgt             6b
+        pop             {r4-r8, pc}
+8:      subs            lr,  lr,  #8
+        vst1.16         {d0[1]},  [r5,:16], r12
+        vst1.16         {d0[3]},  [r5,:16], r12
+        vst1.16         {d1[1]},  [r5,:16], r12
+        vst1.16         {d1[3]},  [r5,:16], r12
+        vst1.16         {d2[1]},  [r5,:16], r12
+        vst1.16         {d2[3]},  [r5,:16], r12
+        vst1.16         {d3[1]},  [r5,:16], r12
+        vst1.16         {d3[3]},  [r5,:16], r12
+        it              eq
+        popeq           {r4-r8, pc}
+        vld1.32         {q0},     [r4,:128]!
+        vcvt.s32.f32    q0,  q0,  #31
+        vld1.32         {q1},     [r4,:128]!
+        vcvt.s32.f32    q1,  q1,  #31
+        b               6b
+endfunc
diff --git a/libs/ffmpeg/libswresample/arm/resample.S b/libs/ffmpeg/libswresample/arm/resample.S
new file mode 100644
index 000000000000..791f4cc0167c
--- /dev/null
+++ b/libs/ffmpeg/libswresample/arm/resample.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.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/arm/asm.S"
+
+function ff_resample_common_apply_filter_x4_float_neon, export=1
+    vmov.f32            q0, #0.0                                       @ accumulator
+1:  vld1.32             {q1}, [r1]!                                    @ src[0..3]
+    vld1.32             {q2}, [r2]!                                    @ filter[0..3]
+    vmla.f32            q0, q1, q2                                     @ accumulator += src[0..3] * filter[0..3]
+    subs                r3, #4                                         @ filter_length -= 4
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.f32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.f32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    bx                  lr
+endfunc
+
+function ff_resample_common_apply_filter_x8_float_neon, export=1
+    vmov.f32            q0, #0.0                                       @ accumulator
+1:  vld1.32             {q1}, [r1]!                                    @ src[0..3]
+    vld1.32             {q2}, [r2]!                                    @ filter[0..3]
+    vld1.32             {q8}, [r1]!                                    @ src[4..7]
+    vld1.32             {q9}, [r2]!                                    @ filter[4..7]
+    vmla.f32            q0, q1, q2                                     @ accumulator += src[0..3] * filter[0..3]
+    vmla.f32            q0, q8, q9                                     @ accumulator += src[4..7] * filter[4..7]
+    subs                r3, #8                                         @ filter_length -= 8
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.f32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.f32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    bx                  lr
+endfunc
+
+function ff_resample_common_apply_filter_x4_s16_neon, export=1
+    vmov.s32            q0, #0                                         @ accumulator
+1:  vld1.16             {d2}, [r1]!                                    @ src[0..3]
+    vld1.16             {d4}, [r2]!                                    @ filter[0..3]
+    vmlal.s16           q0, d2, d4                                     @ accumulator += src[0..3] * filter[0..3]
+    subs                r3, #4                                         @ filter_length -= 4
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.s32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.s32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    bx                  lr
+endfunc
+
+function ff_resample_common_apply_filter_x8_s16_neon, export=1
+    vmov.s32            q0, #0                                         @ accumulator
+1:  vld1.16             {q1}, [r1]!                                    @ src[0..7]
+    vld1.16             {q2}, [r2]!                                    @ filter[0..7]
+    vmlal.s16           q0, d2, d4                                     @ accumulator += src[0..3] * filter[0..3]
+    vmlal.s16           q0, d3, d5                                     @ accumulator += src[4..7] * filter[4..7]
+    subs                r3, #8                                         @ filter_length -= 8
+    bgt                 1b                                             @ loop until filter_length
+    vpadd.s32           d0, d0, d1                                     @ pair adding of the 4x32-bit accumulated values
+    vpadd.s32           d0, d0, d0                                     @ pair adding of the 4x32-bit accumulator values
+    vst1.32             {d0[0]}, [r0]                                  @ write accumulator
+    bx                  lr
+endfunc
diff --git a/libs/ffmpeg/libswresample/arm/resample_init.c b/libs/ffmpeg/libswresample/arm/resample_init.c
new file mode 100644
index 000000000000..b119943a7c5d
--- /dev/null
+++ b/libs/ffmpeg/libswresample/arm/resample_init.c
@@ -0,0 +1,121 @@
+/*
+ * 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
+ */
+
+#include "config.h"
+
+#include "libavutil/attributes.h"
+#include "libavutil/cpu.h"
+#include "libavutil/avassert.h"
+
+#include "libavutil/arm/cpu.h"
+#include "libswresample/resample.h"
+
+#define DECLARE_RESAMPLE_COMMON_TEMPLATE(TYPE, DELEM, FELEM, FELEM2, OUT)                         \
+                                                                                                  \
+void ff_resample_common_apply_filter_x4_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+void ff_resample_common_apply_filter_x8_##TYPE##_neon(FELEM2 *acc, const DELEM *src,              \
+                                                      const FELEM *filter, int length);           \
+                                                                                                  \
+static int ff_resample_common_##TYPE##_neon(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;                                                                         \
+    int x4_aligned_filter_length = c->filter_length & ~3;                                         \
+    int x8_aligned_filter_length = c->filter_length & ~7;                                         \
+                                                                                                  \
+    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 = 0;                                                                             \
+        int i = 0;                                                                                \
+        if (x8_aligned_filter_length >= 8) {                                                      \
+            ff_resample_common_apply_filter_x8_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x8_aligned_filter_length);   \
+            i += x8_aligned_filter_length;                                                        \
+                                                                                                  \
+        } else if (x4_aligned_filter_length >= 4) {                                               \
+            ff_resample_common_apply_filter_x4_##TYPE##_neon(&val, &src[sample_index],            \
+                                                             filter, x4_aligned_filter_length);   \
+            i += x4_aligned_filter_length;                                                        \
+        }                                                                                         \
+        for (; i < c->filter_length; i++) {                                                       \
+            val += src[sample_index + i] * (FELEM2)filter[i];                                     \
+        }                                                                                         \
+        OUT(dst[dst_index], 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;                                                                          \
+}                                                                                                 \
+
+#define OUT(d, v) d = v
+DECLARE_RESAMPLE_COMMON_TEMPLATE(float, float, float, float, OUT)
+#undef OUT
+
+#define OUT(d, v) (v) = ((v) + (1<<(14)))>>15; (d) = av_clip_int16(v)
+DECLARE_RESAMPLE_COMMON_TEMPLATE(s16, int16_t, int16_t, int32_t, OUT)
+#undef OUT
+
+av_cold void swri_resample_dsp_arm_init(ResampleContext *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (!have_neon(cpu_flags))
+        return;
+
+    switch(c->format) {
+    case AV_SAMPLE_FMT_FLTP:
+        c->dsp.resample_common = ff_resample_common_float_neon;
+        break;
+    case AV_SAMPLE_FMT_S16P:
+        c->dsp.resample_common = ff_resample_common_s16_neon;
+        break;
+    }
+}
diff --git a/libs/ffmpeg/libswresample/audioconvert.c b/libs/ffmpeg/libswresample/audioconvert.c
new file mode 100644
index 000000000000..f8bac98ca567
--- /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 000000000000..bb143a876de8
--- /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 000000000000..61151a26ea40
--- /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 000000000000..947eb717a417
--- /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/noise_shaping_data.c b/libs/ffmpeg/libswresample/noise_shaping_data.c
new file mode 100644
index 000000000000..ef9db8a56eaf
--- /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 000000000000..11b2884e3c5d
--- /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 000000000000..a4911a292214
--- /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 000000000000..a18f82a3f1bf
--- /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 000000000000..16d48e93dafa
--- /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 000000000000..1731dad3cf8c
--- /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 000000000000..96f567fe323f
--- /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 000000000000..65682cc38755
--- /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 000000000000..d777efd802f3
--- /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 000000000000..052089acca54
--- /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 000000000000..1334f462a459
--- /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 000000000000..ca2e0d753441
--- /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/version.c b/libs/ffmpeg/libswresample/version.c
new file mode 100644
index 000000000000..06c3d60636a2
--- /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 000000000000..403be6227a03
--- /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 000000000000..4e0bc0ab1997
--- /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/libswresample/x86/audio_convert.asm b/libs/ffmpeg/libswresample/x86/audio_convert.asm
new file mode 100644
index 000000000000..40778e082301
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/audio_convert.asm
@@ -0,0 +1,717 @@
+;******************************************************************************
+;* Copyright (c) 2012 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 "libavutil/x86/x86util.asm"
+
+SECTION_RODATA 32
+flt2pm31: times 8 dd 4.6566129e-10
+flt2p31 : times 8 dd 2147483648.0
+flt2p15 : times 8 dd 32768.0
+
+word_unpack_shuf : db  0, 1, 4, 5, 8, 9,12,13, 2, 3, 6, 7,10,11,14,15
+
+SECTION .text
+
+
+;to, from, a/u, log2_outsize, log_intsize, const
+%macro PACK_2CH 5-7
+cglobal pack_2ch_%2_to_%1_%3, 3, 4, 6, dst, src, len, src2
+    mov src2q   , [srcq+gprsize]
+    mov srcq    , [srcq]
+    mov dstq    , [dstq]
+%ifidn %3, a
+    test dstq, mmsize-1
+        jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+    test src2q, mmsize-1
+        jne pack_2ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_2ch_%2_to_%1_u_int %+ SUFFIX:
+%endif
+    lea     srcq , [srcq  + (1<<%5)*lenq]
+    lea     src2q, [src2q + (1<<%5)*lenq]
+    lea     dstq , [dstq  + (2<<%4)*lenq]
+    neg     lenq
+    %7 m0,m1,m2,m3,m4,m5
+.next:
+%if %4 >= %5
+    mov%3     m0, [         srcq +(1<<%5)*lenq]
+    mova      m1, m0
+    mov%3     m2, [         src2q+(1<<%5)*lenq]
+%if %5 == 1
+    punpcklwd m0, m2
+    punpckhwd m1, m2
+%else
+    punpckldq m0, m2
+    punpckhdq m1, m2
+%endif
+    %6 m0,m1,m2,m3,m4,m5
+%else
+    mov%3     m0, [         srcq +(1<<%5)*lenq]
+    mov%3     m1, [mmsize + srcq +(1<<%5)*lenq]
+    mov%3     m2, [         src2q+(1<<%5)*lenq]
+    mov%3     m3, [mmsize + src2q+(1<<%5)*lenq]
+    %6 m0,m1,m2,m3,m4,m5
+    mova      m2, m0
+    punpcklwd m0, m1
+    punpckhwd m2, m1
+    SWAP 1,2
+%endif
+    mov%3 [           dstq+(2<<%4)*lenq], m0
+    mov%3 [  mmsize + dstq+(2<<%4)*lenq], m1
+%if %4 > %5
+    mov%3 [2*mmsize + dstq+(2<<%4)*lenq], m2
+    mov%3 [3*mmsize + dstq+(2<<%4)*lenq], m3
+    add lenq, 4*mmsize/(2<<%4)
+%else
+    add lenq, 2*mmsize/(2<<%4)
+%endif
+        jl .next
+    RET
+%endmacro
+
+%macro UNPACK_2CH 5-7
+cglobal unpack_2ch_%2_to_%1_%3, 3, 4, 7, dst, src, len, dst2
+    mov dst2q   , [dstq+gprsize]
+    mov srcq    , [srcq]
+    mov dstq    , [dstq]
+%ifidn %3, a
+    test dstq, mmsize-1
+        jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+    test dst2q, mmsize-1
+        jne unpack_2ch_%2_to_%1_u_int %+ SUFFIX
+%else
+unpack_2ch_%2_to_%1_u_int %+ SUFFIX:
+%endif
+    lea     srcq , [srcq  + (2<<%5)*lenq]
+    lea     dstq , [dstq  + (1<<%4)*lenq]
+    lea     dst2q, [dst2q + (1<<%4)*lenq]
+    neg     lenq
+    %7 m0,m1,m2,m3,m4,m5
+    mova      m6, [word_unpack_shuf]
+.next:
+    mov%3     m0, [           srcq +(2<<%5)*lenq]
+    mov%3     m2, [  mmsize + srcq +(2<<%5)*lenq]
+%if %5 == 1
+%ifidn SUFFIX, _ssse3
+    pshufb    m0, m6
+    mova      m1, m0
+    pshufb    m2, m6
+    punpcklqdq m0,m2
+    punpckhqdq m1,m2
+%else
+    mova      m1, m0
+    punpcklwd m0,m2
+    punpckhwd m1,m2
+
+    mova      m2, m0
+    punpcklwd m0,m1
+    punpckhwd m2,m1
+
+    mova      m1, m0
+    punpcklwd m0,m2
+    punpckhwd m1,m2
+%endif
+%else
+    mova      m1, m0
+    shufps    m0, m2, 10001000b
+    shufps    m1, m2, 11011101b
+%endif
+%if %4 < %5
+    mov%3     m2, [2*mmsize + srcq +(2<<%5)*lenq]
+    mova      m3, m2
+    mov%3     m4, [3*mmsize + srcq +(2<<%5)*lenq]
+    shufps    m2, m4, 10001000b
+    shufps    m3, m4, 11011101b
+    SWAP 1,2
+%endif
+    %6 m0,m1,m2,m3,m4,m5
+    mov%3 [           dstq+(1<<%4)*lenq], m0
+%if %4 > %5
+    mov%3 [          dst2q+(1<<%4)*lenq], m2
+    mov%3 [ mmsize +  dstq+(1<<%4)*lenq], m1
+    mov%3 [ mmsize + dst2q+(1<<%4)*lenq], m3
+    add lenq, 2*mmsize/(1<<%4)
+%else
+    mov%3 [          dst2q+(1<<%4)*lenq], m1
+    add lenq, mmsize/(1<<%4)
+%endif
+        jl .next
+    RET
+%endmacro
+
+%macro CONV 5-7
+cglobal %2_to_%1_%3, 3, 3, 6, dst, src, len
+    mov srcq    , [srcq]
+    mov dstq    , [dstq]
+%ifidn %3, a
+    test dstq, mmsize-1
+        jne %2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne %2_to_%1_u_int %+ SUFFIX
+%else
+%2_to_%1_u_int %+ SUFFIX:
+%endif
+    lea     srcq , [srcq  + (1<<%5)*lenq]
+    lea     dstq , [dstq  + (1<<%4)*lenq]
+    neg     lenq
+    %7 m0,m1,m2,m3,m4,m5
+.next:
+    mov%3     m0, [           srcq +(1<<%5)*lenq]
+    mov%3     m1, [  mmsize + srcq +(1<<%5)*lenq]
+%if %4 < %5
+    mov%3     m2, [2*mmsize + srcq +(1<<%5)*lenq]
+    mov%3     m3, [3*mmsize + srcq +(1<<%5)*lenq]
+%endif
+    %6 m0,m1,m2,m3,m4,m5
+    mov%3 [           dstq+(1<<%4)*lenq], m0
+    mov%3 [  mmsize + dstq+(1<<%4)*lenq], m1
+%if %4 > %5
+    mov%3 [2*mmsize + dstq+(1<<%4)*lenq], m2
+    mov%3 [3*mmsize + dstq+(1<<%4)*lenq], m3
+    add lenq, 4*mmsize/(1<<%4)
+%else
+    add lenq, 2*mmsize/(1<<%4)
+%endif
+        jl .next
+%if mmsize == 8
+    emms
+    RET
+%else
+    RET
+%endif
+%endmacro
+
+%macro PACK_6CH 8
+cglobal pack_6ch_%2_to_%1_%3, 2, 8, %6, dst, src, src1, src2, src3, src4, src5, len
+%if ARCH_X86_64
+    mov     lend, r2d
+%else
+    %define lend dword r2m
+%endif
+    mov    src1q, [srcq+1*gprsize]
+    mov    src2q, [srcq+2*gprsize]
+    mov    src3q, [srcq+3*gprsize]
+    mov    src4q, [srcq+4*gprsize]
+    mov    src5q, [srcq+5*gprsize]
+    mov     srcq, [srcq]
+    mov     dstq, [dstq]
+%ifidn %3, a
+    test dstq, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test src1q, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test src2q, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test src3q, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test src4q, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test src5q, mmsize-1
+        jne pack_6ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_6ch_%2_to_%1_u_int %+ SUFFIX:
+%endif
+    sub    src1q, srcq
+    sub    src2q, srcq
+    sub    src3q, srcq
+    sub    src4q, srcq
+    sub    src5q, srcq
+    %8 x,x,x,x,m7,x
+.loop:
+    mov%3     m0, [srcq      ]
+    mov%3     m1, [srcq+src1q]
+    mov%3     m2, [srcq+src2q]
+    mov%3     m3, [srcq+src3q]
+    mov%3     m4, [srcq+src4q]
+    mov%3     m5, [srcq+src5q]
+    SBUTTERFLYPS 0, 1, 6
+    SBUTTERFLYPS 2, 3, 6
+    SBUTTERFLYPS 4, 5, 6
+
+%if cpuflag(avx)
+    blendps   m6, m4, m0, 1100b
+%else
+    movaps    m6, m4
+    shufps    m4, m0, q3210
+    SWAP 4,6
+%endif
+    movlhps   m0, m2
+    movhlps   m4, m2
+%if cpuflag(avx)
+    blendps   m2, m5, m1, 1100b
+%else
+    movaps    m2, m5
+    shufps    m5, m1, q3210
+    SWAP 2,5
+%endif
+    movlhps   m1, m3
+    movhlps   m5, m3
+
+    %7 m0,m6,x,x,m7,m3
+    %7 m4,m1,x,x,m7,m3
+    %7 m2,m5,x,x,m7,m3
+
+    mov %+ %3 %+ ps [dstq   ], m0
+    mov %+ %3 %+ ps [dstq+16], m6
+    mov %+ %3 %+ ps [dstq+32], m4
+    mov %+ %3 %+ ps [dstq+48], m1
+    mov %+ %3 %+ ps [dstq+64], m2
+    mov %+ %3 %+ ps [dstq+80], m5
+    add      srcq, mmsize
+    add      dstq, mmsize*6
+    sub      lend, mmsize/4
+    jg .loop
+%if mmsize == 8
+    emms
+    RET
+%else
+    RET
+%endif
+%endmacro
+
+%macro UNPACK_6CH 8
+cglobal unpack_6ch_%2_to_%1_%3, 2, 8, %6, dst, src, dst1, dst2, dst3, dst4, dst5, len
+%if ARCH_X86_64
+    mov     lend, r2d
+%else
+    %define lend dword r2m
+%endif
+    mov    dst1q, [dstq+1*gprsize]
+    mov    dst2q, [dstq+2*gprsize]
+    mov    dst3q, [dstq+3*gprsize]
+    mov    dst4q, [dstq+4*gprsize]
+    mov    dst5q, [dstq+5*gprsize]
+    mov     dstq, [dstq]
+    mov     srcq, [srcq]
+%ifidn %3, a
+    test dstq, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test dst1q, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test dst2q, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test dst3q, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test dst4q, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+    test dst5q, mmsize-1
+        jne unpack_6ch_%2_to_%1_u_int %+ SUFFIX
+%else
+unpack_6ch_%2_to_%1_u_int %+ SUFFIX:
+%endif
+    sub    dst1q, dstq
+    sub    dst2q, dstq
+    sub    dst3q, dstq
+    sub    dst4q, dstq
+    sub    dst5q, dstq
+    %8 x,x,x,x,m7,x
+.loop:
+    mov%3     m0, [srcq   ]
+    mov%3     m1, [srcq+16]
+    mov%3     m2, [srcq+32]
+    mov%3     m3, [srcq+48]
+    mov%3     m4, [srcq+64]
+    mov%3     m5, [srcq+80]
+
+    SBUTTERFLYPS 0, 3, 6
+    SBUTTERFLYPS 1, 4, 6
+    SBUTTERFLYPS 2, 5, 6
+    SBUTTERFLYPS 0, 4, 6
+    SBUTTERFLYPS 3, 2, 6
+    SBUTTERFLYPS 1, 5, 6
+    SWAP 1, 4
+    SWAP 2, 3
+
+    %7 m0,m1,x,x,m7,m6
+    %7 m2,m3,x,x,m7,m6
+    %7 m4,m5,x,x,m7,m6
+
+    mov %+ %3 %+ ps [dstq      ], m0
+    mov %+ %3 %+ ps [dstq+dst1q], m1
+    mov %+ %3 %+ ps [dstq+dst2q], m2
+    mov %+ %3 %+ ps [dstq+dst3q], m3
+    mov %+ %3 %+ ps [dstq+dst4q], m4
+    mov %+ %3 %+ ps [dstq+dst5q], m5
+
+    add      srcq, mmsize*6
+    add      dstq, mmsize
+    sub      lend, mmsize/4
+    jg .loop
+    RET
+%endmacro
+
+%define PACK_8CH_GPRS (10 * ARCH_X86_64) + ((6 + HAVE_ALIGNED_STACK) * ARCH_X86_32)
+
+%macro PACK_8CH 8
+cglobal pack_8ch_%2_to_%1_%3, 2, PACK_8CH_GPRS, %6, ARCH_X86_32*48, dst, src, len, src1, src2, src3, src4, src5, src6, src7
+    mov     dstq, [dstq]
+%if ARCH_X86_32
+    DEFINE_ARGS dst, src, src2, src3, src4, src5, src6
+    %define lend dword r2m
+    %define src1q r0q
+    %define src1m dword [rsp+32]
+%if HAVE_ALIGNED_STACK == 0
+    DEFINE_ARGS dst, src, src2, src3, src5, src6
+    %define src4q r0q
+    %define src4m dword [rsp+36]
+%endif
+    %define src7q r0q
+    %define src7m dword [rsp+40]
+    mov     dstm, dstq
+%endif
+    mov    src7q, [srcq+7*gprsize]
+    mov    src6q, [srcq+6*gprsize]
+%if ARCH_X86_32
+    mov    src7m, src7q
+%endif
+    mov    src5q, [srcq+5*gprsize]
+    mov    src4q, [srcq+4*gprsize]
+    mov    src3q, [srcq+3*gprsize]
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+    mov    src4m, src4q
+%endif
+    mov    src2q, [srcq+2*gprsize]
+    mov    src1q, [srcq+1*gprsize]
+    mov     srcq, [srcq]
+%ifidn %3, a
+%if ARCH_X86_32
+    test dstmp, mmsize-1
+%else
+    test dstq, mmsize-1
+%endif
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test srcq, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test src1q, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test src2q, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test src3q, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+    test src4m, mmsize-1
+%else
+    test src4q, mmsize-1
+%endif
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test src5q, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+    test src6q, mmsize-1
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%if ARCH_X86_32
+    test src7m, mmsize-1
+%else
+    test src7q, mmsize-1
+%endif
+        jne pack_8ch_%2_to_%1_u_int %+ SUFFIX
+%else
+pack_8ch_%2_to_%1_u_int %+ SUFFIX:
+%endif
+    sub    src1q, srcq
+    sub    src2q, srcq
+    sub    src3q, srcq
+%if ARCH_X86_64 || HAVE_ALIGNED_STACK
+    sub    src4q, srcq
+%else
+    sub    src4m, srcq
+%endif
+    sub    src5q, srcq
+    sub    src6q, srcq
+%if ARCH_X86_64
+    sub    src7q, srcq
+%else
+    mov src1m, src1q
+    sub src7m, srcq
+%endif
+
+%if ARCH_X86_64
+    %8 x,x,x,x,m9,x
+%elifidn %1, int32
+    %define m9 [flt2p31]
+%else
+    %define m9 [flt2pm31]
+%endif
+
+.loop:
+    mov%3     m0, [srcq      ]
+    mov%3     m1, [srcq+src1q]
+    mov%3     m2, [srcq+src2q]
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+    mov    src4q, src4m
+%endif
+    mov%3     m3, [srcq+src3q]
+    mov%3     m4, [srcq+src4q]
+    mov%3     m5, [srcq+src5q]
+%if ARCH_X86_32
+    mov    src7q, src7m
+%endif
+    mov%3     m6, [srcq+src6q]
+    mov%3     m7, [srcq+src7q]
+
+%if ARCH_X86_64
+    TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, 8
+
+    %7 m0,m1,x,x,m9,m8
+    %7 m2,m3,x,x,m9,m8
+    %7 m4,m5,x,x,m9,m8
+    %7 m6,m7,x,x,m9,m8
+
+    mov%3 [dstq], m0
+%else
+    mov     dstq, dstm
+
+    TRANSPOSE8x4D 0, 1, 2, 3, 4, 5, 6, 7, [rsp], [rsp+16], 1
+
+    %7 m0,m1,x,x,m9,m2
+    mova     m2, [rsp]
+    mov%3   [dstq], m0
+    %7 m2,m3,x,x,m9,m0
+    %7 m4,m5,x,x,m9,m0
+    %7 m6,m7,x,x,m9,m0
+
+%endif
+
+    mov%3 [dstq+16],  m1
+    mov%3 [dstq+32],  m2
+    mov%3 [dstq+48],  m3
+    mov%3 [dstq+64],  m4
+    mov%3 [dstq+80],  m5
+    mov%3 [dstq+96],  m6
+    mov%3 [dstq+112], m7
+
+    add      srcq, mmsize
+    add      dstq, mmsize*8
+%if ARCH_X86_32
+    mov      dstm, dstq
+    mov      src1q, src1m
+%endif
+    sub      lend, mmsize/4
+    jg .loop
+    RET
+%endmacro
+
+%macro INT16_TO_INT32_N 6
+    pxor      m2, m2
+    pxor      m3, m3
+    punpcklwd m2, m1
+    punpckhwd m3, m1
+    SWAP 4,0
+    pxor      m0, m0
+    pxor      m1, m1
+    punpcklwd m0, m4
+    punpckhwd m1, m4
+%endmacro
+
+%macro INT32_TO_INT16_N 6
+    psrad     m0, 16
+    psrad     m1, 16
+    psrad     m2, 16
+    psrad     m3, 16
+    packssdw  m0, m1
+    packssdw  m2, m3
+    SWAP 1,2
+%endmacro
+
+%macro INT32_TO_FLOAT_INIT 6
+    mova      %5, [flt2pm31]
+%endmacro
+%macro INT32_TO_FLOAT_N 6
+    cvtdq2ps  %1, %1
+    cvtdq2ps  %2, %2
+    mulps %1, %1, %5
+    mulps %2, %2, %5
+%endmacro
+
+%macro FLOAT_TO_INT32_INIT 6
+    mova      %5, [flt2p31]
+%endmacro
+%macro FLOAT_TO_INT32_N 6
+    mulps %1, %5
+    mulps %2, %5
+    cvtps2dq  %6, %1
+    cmpps %1, %1, %5, 5
+    paddd %1, %6
+    cvtps2dq  %6, %2
+    cmpps %2, %2, %5, 5
+    paddd %2, %6
+%endmacro
+
+%macro INT16_TO_FLOAT_INIT 6
+    mova      m5, [flt2pm31]
+%endmacro
+%macro INT16_TO_FLOAT_N 6
+    INT16_TO_INT32_N %1,%2,%3,%4,%5,%6
+    cvtdq2ps  m0, m0
+    cvtdq2ps  m1, m1
+    cvtdq2ps  m2, m2
+    cvtdq2ps  m3, m3
+    mulps m0, m0, m5
+    mulps m1, m1, m5
+    mulps m2, m2, m5
+    mulps m3, m3, m5
+%endmacro
+
+%macro FLOAT_TO_INT16_INIT 6
+    mova      m5, [flt2p15]
+%endmacro
+%macro FLOAT_TO_INT16_N 6
+    mulps m0, m5
+    mulps m1, m5
+    mulps m2, m5
+    mulps m3, m5
+    cvtps2dq  m0, m0
+    cvtps2dq  m1, m1
+    packssdw  m0, m1
+    cvtps2dq  m1, m2
+    cvtps2dq  m3, m3
+    packssdw  m1, m3
+%endmacro
+
+%macro NOP_N 0-6
+%endmacro
+
+INIT_XMM sse
+PACK_6CH float, float, u, 2, 2, 7, NOP_N, NOP_N
+PACK_6CH float, float, a, 2, 2, 7, NOP_N, NOP_N
+
+UNPACK_6CH float, float, u, 2, 2, 7, NOP_N, NOP_N
+UNPACK_6CH float, float, a, 2, 2, 7, NOP_N, NOP_N
+
+INIT_XMM sse2
+CONV int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+CONV int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+CONV int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+PACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+PACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+PACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N
+PACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N
+PACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+PACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+PACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+PACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int32, int32, u, 2, 2, NOP_N, NOP_N
+UNPACK_2CH int32, int32, a, 2, 2, NOP_N, NOP_N
+UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int16, int32, u, 1, 2, INT32_TO_INT16_N, NOP_N
+UNPACK_2CH int16, int32, a, 1, 2, INT32_TO_INT16_N, NOP_N
+
+CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+CONV float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+CONV int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+CONV int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+PACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+PACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+PACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+PACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+UNPACK_2CH float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_2CH float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_2CH int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_2CH int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH int16, float, u, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+UNPACK_2CH int16, float, a, 1, 2, FLOAT_TO_INT16_N, FLOAT_TO_INT16_INIT
+
+PACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+UNPACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+PACK_8CH float, float, u, 2, 2, 9, NOP_N, NOP_N
+PACK_8CH float, float, a, 2, 2, 9, NOP_N, NOP_N
+
+PACK_8CH float, int32, u, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH float, int32, a, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH int32, float, u, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_8CH int32, float, a, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+INIT_XMM ssse3
+UNPACK_2CH int16, int16, u, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int16, int16, a, 1, 1, NOP_N, NOP_N
+UNPACK_2CH int32, int16, u, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH int32, int16, a, 2, 1, INT16_TO_INT32_N, NOP_N
+UNPACK_2CH float, int16, u, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+UNPACK_2CH float, int16, a, 2, 1, INT16_TO_FLOAT_N, INT16_TO_FLOAT_INIT
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+PACK_6CH float, float, u, 2, 2, 8, NOP_N, NOP_N
+PACK_6CH float, float, a, 2, 2, 8, NOP_N, NOP_N
+
+UNPACK_6CH float, float, u, 2, 2, 8, NOP_N, NOP_N
+UNPACK_6CH float, float, a, 2, 2, 8, NOP_N, NOP_N
+
+PACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+UNPACK_6CH float, int32, u, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH float, int32, a, 2, 2, 8, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+UNPACK_6CH int32, float, u, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+UNPACK_6CH int32, float, a, 2, 2, 8, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+PACK_8CH float, float, u, 2, 2, 9, NOP_N, NOP_N
+PACK_8CH float, float, a, 2, 2, 9, NOP_N, NOP_N
+
+PACK_8CH float, int32, u, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH float, int32, a, 2, 2, 10, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+PACK_8CH int32, float, u, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+PACK_8CH int32, float, a, 2, 2, 10, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+
+INIT_YMM avx
+CONV float, int32, u, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+CONV float, int32, a, 2, 2, INT32_TO_FLOAT_N, INT32_TO_FLOAT_INIT
+%endif
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+CONV int32, float, u, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+CONV int32, float, a, 2, 2, FLOAT_TO_INT32_N, FLOAT_TO_INT32_INIT
+%endif
diff --git a/libs/ffmpeg/libswresample/x86/audio_convert_init.c b/libs/ffmpeg/libswresample/x86/audio_convert_init.c
new file mode 100644
index 000000000000..35458954f266
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/audio_convert_init.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libswresample/swresample_internal.h"
+#include "libswresample/audioconvert.h"
+
+#define PROTO(pre, in, out, cap) void ff ## pre ## in## _to_ ##out## _a_ ##cap(uint8_t **dst, const uint8_t **src, int len);
+#define PROTO2(pre, out, cap) PROTO(pre, int16, out, cap) PROTO(pre, int32, out, cap) PROTO(pre, float, out, cap)
+#define PROTO3(pre, cap) PROTO2(pre, int16, cap) PROTO2(pre, int32, cap) PROTO2(pre, float, cap)
+#define PROTO4(pre) PROTO3(pre, sse) PROTO3(pre, sse2) PROTO3(pre, ssse3) PROTO3(pre, sse4) PROTO3(pre, avx) PROTO3(pre, avx2)
+PROTO4(_)
+PROTO4(_pack_2ch_)
+PROTO4(_pack_6ch_)
+PROTO4(_pack_8ch_)
+PROTO4(_unpack_2ch_)
+PROTO4(_unpack_6ch_)
+
+av_cold void swri_audio_convert_init_x86(struct AudioConvert *ac,
+                                 enum AVSampleFormat out_fmt,
+                                 enum AVSampleFormat in_fmt,
+                                 int channels){
+    int mm_flags = av_get_cpu_flags();
+
+    ac->simd_f= NULL;
+
+//FIXME add memcpy case
+
+#define MULTI_CAPS_FUNC(flag, cap) \
+    if (EXTERNAL_##flag(mm_flags)) {\
+        if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S16P)\
+            ac->simd_f =  ff_int16_to_int32_a_ ## cap;\
+        if(   out_fmt == AV_SAMPLE_FMT_S16  && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_S32P)\
+            ac->simd_f =  ff_int32_to_int16_a_ ## cap;\
+    }
+
+MULTI_CAPS_FUNC(SSE2, sse2)
+
+    if(EXTERNAL_SSE(mm_flags)) {
+        if(channels == 6) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_6ch_float_to_float_a_sse;
+
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_6ch_float_to_float_a_sse;
+        }
+    }
+    if(EXTERNAL_SSE2(mm_flags)) {
+        if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P)
+            ac->simd_f =  ff_int32_to_float_a_sse2;
+        if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S16 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S16P)
+            ac->simd_f =  ff_int16_to_float_a_sse2;
+        if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP)
+            ac->simd_f =  ff_float_to_int32_a_sse2;
+        if(   out_fmt == AV_SAMPLE_FMT_S16  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S16P && in_fmt == AV_SAMPLE_FMT_FLTP)
+            ac->simd_f =  ff_float_to_int16_a_sse2;
+
+        if(channels == 2) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_2ch_int32_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16  && in_fmt == AV_SAMPLE_FMT_S16P)
+                ac->simd_f =  ff_pack_2ch_int16_to_int16_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_S16P)
+                ac->simd_f =  ff_pack_2ch_int16_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_2ch_int32_to_int16_a_sse2;
+
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_2ch_int32_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16P  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_int16_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32P  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16P  && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_2ch_int32_to_int16_a_sse2;
+
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_2ch_int32_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_2ch_float_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S16P)
+                ac->simd_f =  ff_pack_2ch_int16_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_2ch_float_to_int16_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_2ch_int32_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32P  && in_fmt == AV_SAMPLE_FMT_FLT)
+                ac->simd_f =  ff_unpack_2ch_float_to_int32_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S16P  && in_fmt == AV_SAMPLE_FMT_FLT)
+                ac->simd_f =  ff_unpack_2ch_float_to_int16_a_sse2;
+        }
+        if(channels == 6) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_6ch_int32_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_6ch_float_to_int32_a_sse2;
+
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_6ch_int32_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32P  && in_fmt == AV_SAMPLE_FMT_FLT)
+                ac->simd_f =  ff_unpack_6ch_float_to_int32_a_sse2;
+        }
+        if(channels == 8) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_8ch_float_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_8ch_int32_to_float_a_sse2;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_8ch_float_to_int32_a_sse2;
+        }
+    }
+    if(EXTERNAL_SSSE3(mm_flags)) {
+        if(channels == 2) {
+            if(   out_fmt == AV_SAMPLE_FMT_S16P  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_int16_a_ssse3;
+            if(   out_fmt == AV_SAMPLE_FMT_S32P  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_int32_a_ssse3;
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_S16)
+                ac->simd_f =  ff_unpack_2ch_int16_to_float_a_ssse3;
+        }
+    }
+    if(EXTERNAL_AVX_FAST(mm_flags)) {
+        if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32 || out_fmt == AV_SAMPLE_FMT_FLTP && in_fmt == AV_SAMPLE_FMT_S32P)
+            ac->simd_f =  ff_int32_to_float_a_avx;
+    }
+    if(EXTERNAL_AVX(mm_flags)) {
+        if(channels == 6) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_6ch_float_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_6ch_int32_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_6ch_float_to_int32_a_avx;
+
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_6ch_float_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_FLTP  && in_fmt == AV_SAMPLE_FMT_S32)
+                ac->simd_f =  ff_unpack_6ch_int32_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_S32P  && in_fmt == AV_SAMPLE_FMT_FLT)
+                ac->simd_f =  ff_unpack_6ch_float_to_int32_a_avx;
+        }
+        if(channels == 8) {
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_FLTP || out_fmt == AV_SAMPLE_FMT_S32 && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_8ch_float_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_FLT  && in_fmt == AV_SAMPLE_FMT_S32P)
+                ac->simd_f =  ff_pack_8ch_int32_to_float_a_avx;
+            if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLTP)
+                ac->simd_f =  ff_pack_8ch_float_to_int32_a_avx;
+        }
+    }
+    if(EXTERNAL_AVX2_FAST(mm_flags)) {
+        if(   out_fmt == AV_SAMPLE_FMT_S32  && in_fmt == AV_SAMPLE_FMT_FLT || out_fmt == AV_SAMPLE_FMT_S32P && in_fmt == AV_SAMPLE_FMT_FLTP)
+            ac->simd_f =  ff_float_to_int32_a_avx2;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libswresample/x86/rematrix.asm b/libs/ffmpeg/libswresample/x86/rematrix.asm
new file mode 100644
index 000000000000..e2b2a8631795
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/rematrix.asm
@@ -0,0 +1,244 @@
+;******************************************************************************
+;* Copyright (c) 2012 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 "libavutil/x86/x86util.asm"
+
+
+SECTION_RODATA 32
+dw1: times 8  dd 1
+w1 : times 16 dw 1
+
+SECTION .text
+
+%macro MIX2_FLT 1
+cglobal mix_2_1_%1_float, 7, 7, 6, out, in1, in2, coeffp, index1, index2, len
+%ifidn %1, a
+    test in1q, mmsize-1
+        jne mix_2_1_float_u_int %+ SUFFIX
+    test in2q, mmsize-1
+        jne mix_2_1_float_u_int %+ SUFFIX
+    test outq, mmsize-1
+        jne mix_2_1_float_u_int %+ SUFFIX
+%else
+mix_2_1_float_u_int %+ SUFFIX:
+%endif
+    VBROADCASTSS m4, [coeffpq + 4*index1q]
+    VBROADCASTSS m5, [coeffpq + 4*index2q]
+    shl lend    , 2
+    add in1q    , lenq
+    add in2q    , lenq
+    add outq    , lenq
+    neg lenq
+.next:
+%ifidn %1, a
+    mulps        m0, m4, [in1q + lenq         ]
+    mulps        m1, m5, [in2q + lenq         ]
+    mulps        m2, m4, [in1q + lenq + mmsize]
+    mulps        m3, m5, [in2q + lenq + mmsize]
+%else
+    movu         m0, [in1q + lenq         ]
+    movu         m1, [in2q + lenq         ]
+    movu         m2, [in1q + lenq + mmsize]
+    movu         m3, [in2q + lenq + mmsize]
+    mulps        m0, m0, m4
+    mulps        m1, m1, m5
+    mulps        m2, m2, m4
+    mulps        m3, m3, m5
+%endif
+    addps        m0, m0, m1
+    addps        m2, m2, m3
+    mov%1  [outq + lenq         ], m0
+    mov%1  [outq + lenq + mmsize], m2
+    add        lenq, mmsize*2
+        jl .next
+    RET
+%endmacro
+
+%macro MIX1_FLT 1
+cglobal mix_1_1_%1_float, 5, 5, 3, out, in, coeffp, index, len
+%ifidn %1, a
+    test inq, mmsize-1
+        jne mix_1_1_float_u_int %+ SUFFIX
+    test outq, mmsize-1
+        jne mix_1_1_float_u_int %+ SUFFIX
+%else
+mix_1_1_float_u_int %+ SUFFIX:
+%endif
+    VBROADCASTSS m2, [coeffpq + 4*indexq]
+    shl lenq    , 2
+    add inq     , lenq
+    add outq    , lenq
+    neg lenq
+.next:
+%ifidn %1, a
+    mulps        m0, m2, [inq + lenq         ]
+    mulps        m1, m2, [inq + lenq + mmsize]
+%else
+    movu         m0, [inq + lenq         ]
+    movu         m1, [inq + lenq + mmsize]
+    mulps        m0, m0, m2
+    mulps        m1, m1, m2
+%endif
+    mov%1  [outq + lenq         ], m0
+    mov%1  [outq + lenq + mmsize], m1
+    add        lenq, mmsize*2
+        jl .next
+    RET
+%endmacro
+
+%macro MIX1_INT16 1
+cglobal mix_1_1_%1_int16, 5, 5, 6, out, in, coeffp, index, len
+%ifidn %1, a
+    test inq, mmsize-1
+        jne mix_1_1_int16_u_int %+ SUFFIX
+    test outq, mmsize-1
+        jne mix_1_1_int16_u_int %+ SUFFIX
+%else
+mix_1_1_int16_u_int %+ SUFFIX:
+%endif
+    movd   m4, [coeffpq + 4*indexq]
+    SPLATW m5, m4
+    psllq  m4, 32
+    psrlq  m4, 48
+    mova   m0, [w1]
+    psllw  m0, m4
+    psrlw  m0, 1
+    punpcklwd m5, m0
+    add lenq    , lenq
+    add inq     , lenq
+    add outq    , lenq
+    neg lenq
+.next:
+    mov%1        m0, [inq + lenq         ]
+    mov%1        m2, [inq + lenq + mmsize]
+    mova         m1, m0
+    mova         m3, m2
+    punpcklwd    m0, [w1]
+    punpckhwd    m1, [w1]
+    punpcklwd    m2, [w1]
+    punpckhwd    m3, [w1]
+    pmaddwd      m0, m5
+    pmaddwd      m1, m5
+    pmaddwd      m2, m5
+    pmaddwd      m3, m5
+    psrad        m0, m4
+    psrad        m1, m4
+    psrad        m2, m4
+    psrad        m3, m4
+    packssdw     m0, m1
+    packssdw     m2, m3
+    mov%1  [outq + lenq         ], m0
+    mov%1  [outq + lenq + mmsize], m2
+    add        lenq, mmsize*2
+        jl .next
+%if mmsize == 8
+    emms
+    RET
+%else
+    RET
+%endif
+%endmacro
+
+%macro MIX2_INT16 1
+cglobal mix_2_1_%1_int16, 7, 7, 8, out, in1, in2, coeffp, index1, index2, len
+%ifidn %1, a
+    test in1q, mmsize-1
+        jne mix_2_1_int16_u_int %+ SUFFIX
+    test in2q, mmsize-1
+        jne mix_2_1_int16_u_int %+ SUFFIX
+    test outq, mmsize-1
+        jne mix_2_1_int16_u_int %+ SUFFIX
+%else
+mix_2_1_int16_u_int %+ SUFFIX:
+%endif
+    movd   m4, [coeffpq + 4*index1q]
+    movd   m6, [coeffpq + 4*index2q]
+    SPLATW m5, m4
+    SPLATW m6, m6
+    psllq  m4, 32
+    psrlq  m4, 48
+    mova   m7, [dw1]
+    pslld  m7, m4
+    psrld  m7, 1
+    punpcklwd m5, m6
+    add lend    , lend
+    add in1q    , lenq
+    add in2q    , lenq
+    add outq    , lenq
+    neg lenq
+.next:
+    mov%1        m0, [in1q + lenq         ]
+    mov%1        m2, [in2q + lenq         ]
+    mova         m1, m0
+    punpcklwd    m0, m2
+    punpckhwd    m1, m2
+
+    mov%1        m2, [in1q + lenq + mmsize]
+    mov%1        m6, [in2q + lenq + mmsize]
+    mova         m3, m2
+    punpcklwd    m2, m6
+    punpckhwd    m3, m6
+
+    pmaddwd      m0, m5
+    pmaddwd      m1, m5
+    pmaddwd      m2, m5
+    pmaddwd      m3, m5
+    paddd        m0, m7
+    paddd        m1, m7
+    paddd        m2, m7
+    paddd        m3, m7
+    psrad        m0, m4
+    psrad        m1, m4
+    psrad        m2, m4
+    psrad        m3, m4
+    packssdw     m0, m1
+    packssdw     m2, m3
+    mov%1  [outq + lenq         ], m0
+    mov%1  [outq + lenq + mmsize], m2
+    add        lenq, mmsize*2
+        jl .next
+%if mmsize == 8
+    emms
+    RET
+%else
+    RET
+%endif
+%endmacro
+
+
+INIT_XMM sse
+MIX2_FLT u
+MIX2_FLT a
+MIX1_FLT u
+MIX1_FLT a
+
+INIT_XMM sse2
+MIX1_INT16 u
+MIX1_INT16 a
+MIX2_INT16 u
+MIX2_INT16 a
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+MIX2_FLT u
+MIX2_FLT a
+MIX1_FLT u
+MIX1_FLT a
+%endif
diff --git a/libs/ffmpeg/libswresample/x86/rematrix_init.c b/libs/ffmpeg/libswresample/x86/rematrix_init.c
new file mode 100644
index 000000000000..41076d590e63
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/rematrix_init.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/mem.h"
+#include "libavutil/x86/cpu.h"
+#include "libswresample/swresample_internal.h"
+
+#define D(type, simd) \
+mix_1_1_func_type ff_mix_1_1_a_## type ## _ ## simd;\
+mix_2_1_func_type ff_mix_2_1_a_## type ## _ ## simd;
+
+D(float, sse)
+D(float, avx)
+D(int16, sse2)
+
+av_cold int swri_rematrix_init_x86(struct SwrContext *s){
+    int mm_flags = av_get_cpu_flags();
+    int nb_in  = s->used_ch_layout.nb_channels;
+    int nb_out = s->out.ch_count;
+    int num    = nb_in * nb_out;
+    int i,j;
+
+    s->mix_1_1_simd = NULL;
+    s->mix_2_1_simd = NULL;
+
+    if (s->midbuf.fmt == AV_SAMPLE_FMT_S16P){
+        if(EXTERNAL_SSE2(mm_flags)) {
+            s->mix_1_1_simd = ff_mix_1_1_a_int16_sse2;
+            s->mix_2_1_simd = ff_mix_2_1_a_int16_sse2;
+        }
+        s->native_simd_matrix = av_calloc(num,  2 * sizeof(int16_t));
+        if (!s->native_simd_matrix)
+            return AVERROR(ENOMEM);
+
+        for(i=0; i<nb_out; i++){
+            int sh = 0;
+            for(j=0; j<nb_in; j++)
+                sh = FFMAX(sh, FFABS(((int*)s->native_matrix)[i * nb_in + j]));
+            sh = FFMAX(av_log2(sh) - 14, 0);
+            for(j=0; j<nb_in; j++) {
+                ((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)+1] = 15 - sh;
+                ((int16_t*)s->native_simd_matrix)[2*(i * nb_in + j)] =
+                    ((((int*)s->native_matrix)[i * nb_in + j]) + (1<<sh>>1)) >> sh;
+            }
+        }
+        s->native_simd_one.i16[1] = 14;
+        s->native_simd_one.i16[0] = 16384;
+    } else if(s->midbuf.fmt == AV_SAMPLE_FMT_FLTP){
+        if(EXTERNAL_SSE(mm_flags)) {
+            s->mix_1_1_simd = ff_mix_1_1_a_float_sse;
+            s->mix_2_1_simd = ff_mix_2_1_a_float_sse;
+        }
+        if(EXTERNAL_AVX_FAST(mm_flags)) {
+            s->mix_1_1_simd = ff_mix_1_1_a_float_avx;
+            s->mix_2_1_simd = ff_mix_2_1_a_float_avx;
+        }
+        s->native_simd_matrix = av_calloc(num, sizeof(float));
+        if (!s->native_simd_matrix)
+            return AVERROR(ENOMEM);
+        memcpy(s->native_simd_matrix, s->native_matrix, num * sizeof(float));
+        s->native_simd_one.f = s->native_one.f;
+    }
+
+    return 0;
+}
+
+#endif
diff --git a/libs/ffmpeg/libswresample/x86/resample.asm b/libs/ffmpeg/libswresample/x86/resample.asm
new file mode 100644
index 000000000000..6c3dc28703b1
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/resample.asm
@@ -0,0 +1,614 @@
+;******************************************************************************
+;* Copyright (c) 2012 Michael Niedermayer
+;* Copyright (c) 2014 James Almer <jamrial <at> gmail.com>
+;* Copyright (c) 2014 Ronald S. Bultje <rsbultje@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/x86/x86util.asm"
+
+%if ARCH_X86_64
+%define pointer resq
+%else
+%define pointer resd
+%endif
+
+struc ResampleContext
+    .av_class:              pointer 1
+    .filter_bank:           pointer 1
+    .filter_length:         resd 1
+    .filter_alloc:          resd 1
+    .ideal_dst_incr:        resd 1
+    .dst_incr:              resd 1
+    .dst_incr_div:          resd 1
+    .dst_incr_mod:          resd 1
+    .index:                 resd 1
+    .frac:                  resd 1
+    .src_incr:              resd 1
+    .compensation_distance: resd 1
+    .phase_count:           resd 1
+
+    ; there's a few more here but we only care about the first few
+endstruc
+
+SECTION_RODATA
+
+pf_1:      dd 1.0
+pdbl_1:    dq 1.0
+pd_0x4000: dd 0x4000
+
+SECTION .text
+
+; FIXME remove unneeded variables (index_incr, phase_mask)
+%macro RESAMPLE_FNS 3-5 ; format [float or int16], bps, log2_bps, float op suffix [s or d], 1.0 constant
+; int resample_common_$format(ResampleContext *ctx, $format *dst,
+;                             const $format *src, int size, int update_ctx)
+%if ARCH_X86_64 ; unix64 and win64
+cglobal resample_common_%1, 0, 15, 2, ctx, dst, src, phase_count, index, frac, \
+                                      dst_incr_mod, size, min_filter_count_x4, \
+                                      min_filter_len_x4, dst_incr_div, src_incr, \
+                                      phase_mask, dst_end, filter_bank
+
+    ; use red-zone for variable storage
+%define ctx_stackq            [rsp-0x8]
+%define src_stackq            [rsp-0x10]
+%if WIN64
+%define update_context_stackd r4m
+%else ; unix64
+%define update_context_stackd [rsp-0x14]
+%endif
+
+    ; load as many variables in registers as possible; for the rest, store
+    ; on stack so that we have 'ctx' available as one extra register
+    mov                        sized, r3d
+%if UNIX64
+    mov        update_context_stackd, r4d
+%endif
+    mov                       indexd, [ctxq+ResampleContext.index]
+    mov                        fracd, [ctxq+ResampleContext.frac]
+    mov                dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod]
+    mov                 filter_bankq, [ctxq+ResampleContext.filter_bank]
+    mov                    src_incrd, [ctxq+ResampleContext.src_incr]
+    mov                   ctx_stackq, ctxq
+    mov           min_filter_len_x4d, [ctxq+ResampleContext.filter_length]
+    mov                dst_incr_divd, [ctxq+ResampleContext.dst_incr_div]
+    shl           min_filter_len_x4d, %3
+    lea                     dst_endq, [dstq+sizeq*%2]
+
+%if UNIX64
+    mov                          ecx, [ctxq+ResampleContext.phase_count]
+    mov                          edi, [ctxq+ResampleContext.filter_alloc]
+
+    DEFINE_ARGS filter_alloc, dst, src, phase_count, index, frac, dst_incr_mod, \
+                filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+                src_incr, phase_mask, dst_end, filter_bank
+%elif WIN64
+    mov                          R9d, [ctxq+ResampleContext.filter_alloc]
+    mov                          ecx, [ctxq+ResampleContext.phase_count]
+
+    DEFINE_ARGS phase_count, dst, src, filter_alloc, index, frac, dst_incr_mod, \
+                filter, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+                src_incr, phase_mask, dst_end, filter_bank
+%endif
+
+    neg           min_filter_len_x4q
+    sub                 filter_bankq, min_filter_len_x4q
+    sub                         srcq, min_filter_len_x4q
+    mov                   src_stackq, srcq
+%else ; x86-32
+cglobal resample_common_%1, 1, 7, 2, ctx, phase_count, dst, frac, \
+                                     index, min_filter_length_x4, filter_bank
+
+    ; push temp variables to stack
+%define ctx_stackq            r0mp
+%define src_stackq            r2mp
+%define update_context_stackd r4m
+
+    mov                         dstq, r1mp
+    mov                           r3, r3mp
+    lea                           r3, [dstq+r3*%2]
+    PUSH                              dword [ctxq+ResampleContext.dst_incr_div]
+    PUSH                              dword [ctxq+ResampleContext.dst_incr_mod]
+    PUSH                              dword [ctxq+ResampleContext.filter_alloc]
+    PUSH                              r3
+    PUSH                              dword [ctxq+ResampleContext.phase_count]  ; unneeded replacement for phase_mask
+    PUSH                              dword [ctxq+ResampleContext.src_incr]
+    mov        min_filter_length_x4d, [ctxq+ResampleContext.filter_length]
+    mov                       indexd, [ctxq+ResampleContext.index]
+    shl        min_filter_length_x4d, %3
+    mov                        fracd, [ctxq+ResampleContext.frac]
+    neg        min_filter_length_x4q
+    mov                 filter_bankq, [ctxq+ResampleContext.filter_bank]
+    sub                         r2mp, min_filter_length_x4q
+    sub                 filter_bankq, min_filter_length_x4q
+    PUSH                              min_filter_length_x4q
+    PUSH                              filter_bankq
+    mov                 phase_countd, [ctxq+ResampleContext.phase_count]
+
+    DEFINE_ARGS src, phase_count, dst, frac, index, min_filter_count_x4, filter
+
+%define filter_bankq          dword [rsp+0x0]
+%define min_filter_length_x4q dword [rsp+0x4]
+%define src_incrd             dword [rsp+0x8]
+%define phase_maskd           dword [rsp+0xc]
+%define dst_endq              dword [rsp+0x10]
+%define filter_allocd         dword [rsp+0x14]
+%define dst_incr_modd         dword [rsp+0x18]
+%define dst_incr_divd         dword [rsp+0x1c]
+
+    mov                         srcq, r2mp
+%endif
+
+.loop:
+    mov                      filterd, filter_allocd
+    imul                     filterd, indexd
+%if ARCH_X86_64
+    mov         min_filter_count_x4q, min_filter_len_x4q
+    lea                      filterq, [filter_bankq+filterq*%2]
+%else ; x86-32
+    mov         min_filter_count_x4q, filter_bankq
+    lea                      filterq, [min_filter_count_x4q+filterq*%2]
+    mov         min_filter_count_x4q, min_filter_length_x4q
+%endif
+%ifidn %1, int16
+    movd                          m0, [pd_0x4000]
+%else ; float/double
+    xorps                         m0, m0, m0
+%endif
+
+    align 16
+.inner_loop:
+    movu                          m1, [srcq+min_filter_count_x4q*1]
+%ifidn %1, int16
+%if cpuflag(xop)
+    vpmadcswd                     m0, m1, [filterq+min_filter_count_x4q*1], m0
+%else
+    pmaddwd                       m1, [filterq+min_filter_count_x4q*1]
+    paddd                         m0, m1
+%endif
+%else ; float/double
+%if cpuflag(fma4) || cpuflag(fma3)
+    fmaddp%4                      m0, m1, [filterq+min_filter_count_x4q*1], m0
+%else
+    mulp%4                        m1, m1, [filterq+min_filter_count_x4q*1]
+    addp%4                        m0, m0, m1
+%endif ; cpuflag
+%endif
+    add         min_filter_count_x4q, mmsize
+    js .inner_loop
+
+%ifidn %1, int16
+    HADDD                         m0, m1
+    psrad                         m0, 15
+    add                        fracd, dst_incr_modd
+    packssdw                      m0, m0
+    add                       indexd, dst_incr_divd
+    movd                      [dstq], m0
+%else ; float/double
+    ; horizontal sum & store
+%if mmsize == 32
+    vextractf128                 xm1, m0, 0x1
+    addp%4                       xm0, xm1
+%endif
+    movhlps                      xm1, xm0
+%ifidn %1, float
+    addps                        xm0, xm1
+    shufps                       xm1, xm0, xm0, q0001
+%endif
+    add                        fracd, dst_incr_modd
+    addp%4                       xm0, xm1
+    add                       indexd, dst_incr_divd
+    movs%4                    [dstq], xm0
+%endif
+    cmp                        fracd, src_incrd
+    jl .skip
+    sub                        fracd, src_incrd
+    inc                       indexd
+
+%if UNIX64
+    DEFINE_ARGS filter_alloc, dst, src, phase_count, index, frac, dst_incr_mod, \
+                index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+                src_incr, phase_mask, dst_end, filter_bank
+%elif WIN64
+    DEFINE_ARGS phase_count, dst, src, filter_alloc, index, frac, dst_incr_mod, \
+                index_incr, min_filter_count_x4, min_filter_len_x4, dst_incr_div, \
+                src_incr, phase_mask, dst_end, filter_bank
+%else ; x86-32
+    DEFINE_ARGS src, phase_count, dst, frac, index, index_incr
+%endif
+
+.skip:
+    add                         dstq, %2
+    cmp                       indexd, phase_countd
+    jb .index_skip
+.index_while:
+    sub                       indexd, phase_countd
+    lea                         srcq, [srcq+%2]
+    cmp                       indexd, phase_countd
+    jnb .index_while
+.index_skip:
+    cmp                         dstq, dst_endq
+    jne .loop
+
+%if ARCH_X86_64
+    DEFINE_ARGS ctx, dst, src, phase_count, index, frac
+%else ; x86-32
+    DEFINE_ARGS src, ctx, update_context, frac, index
+%endif
+
+    cmp  dword update_context_stackd, 0
+    jz .skip_store
+    ; strictly speaking, the function should always return the consumed
+    ; number of bytes; however, we only use the value if update_context
+    ; is true, so let's just leave it uninitialized otherwise
+    mov                         ctxq, ctx_stackq
+    movifnidn                    rax, srcq
+    mov [ctxq+ResampleContext.frac ], fracd
+    sub                          rax, src_stackq
+    mov [ctxq+ResampleContext.index], indexd
+    shr                          rax, %3
+
+.skip_store:
+%if ARCH_X86_32
+    ADD                          rsp, 0x20
+%endif
+    RET
+
+; int resample_linear_$format(ResampleContext *ctx, float *dst,
+;                             const float *src, int size, int update_ctx)
+%if ARCH_X86_64 ; unix64 and win64
+%if UNIX64
+cglobal resample_linear_%1, 0, 15, 5, ctx, dst, phase_mask, phase_count, index, frac, \
+                                      size, dst_incr_mod, min_filter_count_x4, \
+                                      min_filter_len_x4, dst_incr_div, src_incr, \
+                                      src, dst_end, filter_bank
+
+    mov                         srcq, r2mp
+%else ; win64
+cglobal resample_linear_%1, 0, 15, 5, ctx, phase_mask, src, phase_count, index, frac, \
+                                      size, dst_incr_mod, min_filter_count_x4, \
+                                      min_filter_len_x4, dst_incr_div, src_incr, \
+                                      dst, dst_end, filter_bank
+
+    mov                         dstq, r1mp
+%endif
+
+    ; use red-zone for variable storage
+%define ctx_stackq            [rsp-0x8]
+%define src_stackq            [rsp-0x10]
+%define phase_mask_stackd     [rsp-0x14]
+%if WIN64
+%define update_context_stackd r4m
+%else ; unix64
+%define update_context_stackd [rsp-0x18]
+%endif
+
+    ; load as many variables in registers as possible; for the rest, store
+    ; on stack so that we have 'ctx' available as one extra register
+    mov                        sized, r3d
+%if UNIX64
+    mov        update_context_stackd, r4d
+%endif
+    mov                       indexd, [ctxq+ResampleContext.index]
+    mov                        fracd, [ctxq+ResampleContext.frac]
+    mov                dst_incr_modd, [ctxq+ResampleContext.dst_incr_mod]
+    mov                 filter_bankq, [ctxq+ResampleContext.filter_bank]
+    mov                    src_incrd, [ctxq+ResampleContext.src_incr]
+    mov                   ctx_stackq, ctxq
+    mov           min_filter_len_x4d, [ctxq+ResampleContext.filter_length]
+%ifidn %1, int16
+    movd                          m4, [pd_0x4000]
+%else ; float/double
+    cvtsi2s%4                    xm0, src_incrd
+    movs%4                       xm4, [%5]
+    divs%4                       xm4, xm0
+%endif
+    mov                dst_incr_divd, [ctxq+ResampleContext.dst_incr_div]
+    shl           min_filter_len_x4d, %3
+    lea                     dst_endq, [dstq+sizeq*%2]
+
+%if UNIX64
+    mov                          ecx, [ctxq+ResampleContext.phase_count]
+    mov                          edi, [ctxq+ResampleContext.filter_alloc]
+
+    DEFINE_ARGS filter_alloc, dst, filter2, phase_count, index, frac, filter1, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+    mov                          R9d, [ctxq+ResampleContext.filter_alloc]
+    mov                          ecx, [ctxq+ResampleContext.phase_count]
+
+    DEFINE_ARGS phase_count, filter2, src, filter_alloc, index, frac, filter1, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, dst, dst_end, filter_bank
+%endif
+
+    neg           min_filter_len_x4q
+    sub                 filter_bankq, min_filter_len_x4q
+    sub                         srcq, min_filter_len_x4q
+    mov                   src_stackq, srcq
+%else ; x86-32
+cglobal resample_linear_%1, 1, 7, 5, ctx, min_filter_length_x4, filter2, \
+                                     frac, index, dst, filter_bank
+
+    ; push temp variables to stack
+%define ctx_stackq            r0mp
+%define src_stackq            r2mp
+%define update_context_stackd r4m
+
+    mov                         dstq, r1mp
+    mov                           r3, r3mp
+    lea                           r3, [dstq+r3*%2]
+    PUSH                              dword [ctxq+ResampleContext.dst_incr_div]
+    PUSH                              r3
+    mov                           r3, dword [ctxq+ResampleContext.filter_alloc]
+    PUSH                              dword [ctxq+ResampleContext.dst_incr_mod]
+    PUSH                              r3
+    shl                           r3, %3
+    PUSH                              r3
+    mov                           r3, dword [ctxq+ResampleContext.src_incr]
+    PUSH                              dword [ctxq+ResampleContext.phase_count]  ; unneeded replacement of phase_mask
+    PUSH                              r3d
+%ifidn %1, int16
+    movd                          m4, [pd_0x4000]
+%else ; float/double
+    cvtsi2s%4                    xm0, r3d
+    movs%4                       xm4, [%5]
+    divs%4                       xm4, xm0
+%endif
+    mov        min_filter_length_x4d, [ctxq+ResampleContext.filter_length]
+    mov                       indexd, [ctxq+ResampleContext.index]
+    shl        min_filter_length_x4d, %3
+    mov                        fracd, [ctxq+ResampleContext.frac]
+    neg        min_filter_length_x4q
+    mov                 filter_bankq, [ctxq+ResampleContext.filter_bank]
+    sub                         r2mp, min_filter_length_x4q
+    sub                 filter_bankq, min_filter_length_x4q
+    PUSH                              min_filter_length_x4q
+    PUSH                              filter_bankq
+    PUSH                              dword [ctxq+ResampleContext.phase_count]
+
+    DEFINE_ARGS filter1, min_filter_count_x4, filter2, frac, index, dst, src
+
+%define phase_count_stackd    dword [rsp+0x0]
+%define filter_bankq          dword [rsp+0x4]
+%define min_filter_length_x4q dword [rsp+0x8]
+%define src_incrd             dword [rsp+0xc]
+%define phase_mask_stackd     dword [rsp+0x10]
+%define filter_alloc_x4q      dword [rsp+0x14]
+%define filter_allocd         dword [rsp+0x18]
+%define dst_incr_modd         dword [rsp+0x1c]
+%define dst_endq              dword [rsp+0x20]
+%define dst_incr_divd         dword [rsp+0x24]
+
+    mov                         srcq, r2mp
+%endif
+
+.loop:
+    mov                     filter1d, filter_allocd
+    imul                    filter1d, indexd
+%if ARCH_X86_64
+    mov         min_filter_count_x4q, min_filter_len_x4q
+    lea                     filter1q, [filter_bankq+filter1q*%2]
+    lea                     filter2q, [filter1q+filter_allocq*%2]
+%else ; x86-32
+    mov         min_filter_count_x4q, filter_bankq
+    lea                     filter1q, [min_filter_count_x4q+filter1q*%2]
+    mov         min_filter_count_x4q, min_filter_length_x4q
+    mov                     filter2q, filter1q
+    add                     filter2q, filter_alloc_x4q
+%endif
+%ifidn %1, int16
+    mova                          m0, m4
+    mova                          m2, m4
+%else ; float/double
+    xorps                         m0, m0, m0
+    xorps                         m2, m2, m2
+%endif
+
+    align 16
+.inner_loop:
+    movu                          m1, [srcq+min_filter_count_x4q*1]
+%ifidn %1, int16
+%if cpuflag(xop)
+    vpmadcswd                     m2, m1, [filter2q+min_filter_count_x4q*1], m2
+    vpmadcswd                     m0, m1, [filter1q+min_filter_count_x4q*1], m0
+%else
+    pmaddwd                       m3, m1, [filter2q+min_filter_count_x4q*1]
+    pmaddwd                       m1, [filter1q+min_filter_count_x4q*1]
+    paddd                         m2, m3
+    paddd                         m0, m1
+%endif ; cpuflag
+%else ; float/double
+%if cpuflag(fma4) || cpuflag(fma3)
+    fmaddp%4                      m2, m1, [filter2q+min_filter_count_x4q*1], m2
+    fmaddp%4                      m0, m1, [filter1q+min_filter_count_x4q*1], m0
+%else
+    mulp%4                        m3, m1, [filter2q+min_filter_count_x4q*1]
+    mulp%4                        m1, m1, [filter1q+min_filter_count_x4q*1]
+    addp%4                        m2, m2, m3
+    addp%4                        m0, m0, m1
+%endif ; cpuflag
+%endif
+    add         min_filter_count_x4q, mmsize
+    js .inner_loop
+
+%ifidn %1, int16
+%if mmsize == 16
+%if cpuflag(xop)
+    vphadddq                      m2, m2
+    vphadddq                      m0, m0
+%endif
+    pshufd                        m3, m2, q0032
+    pshufd                        m1, m0, q0032
+    paddd                         m2, m3
+    paddd                         m0, m1
+%endif
+%if notcpuflag(xop)
+    PSHUFLW                       m3, m2, q0032
+    PSHUFLW                       m1, m0, q0032
+    paddd                         m2, m3
+    paddd                         m0, m1
+%endif
+    psubd                         m2, m0
+    ; This is probably a really bad idea on atom and other machines with a
+    ; long transfer latency between GPRs and XMMs (atom). However, it does
+    ; make the clip a lot simpler...
+    movd                         eax, m2
+    add                       indexd, dst_incr_divd
+    imul                              fracd
+    idiv                              src_incrd
+    movd                          m1, eax
+    add                        fracd, dst_incr_modd
+    paddd                         m0, m1
+    psrad                         m0, 15
+    packssdw                      m0, m0
+    movd                      [dstq], m0
+
+    ; note that for imul/idiv, I need to move filter to edx/eax for each:
+    ; - 32bit: eax=r0[filter1], edx=r2[filter2]
+    ; - win64: eax=r6[filter1], edx=r1[todo]
+    ; - unix64: eax=r6[filter1], edx=r2[todo]
+%else ; float/double
+    ; val += (v2 - val) * (FELEML) frac / c->src_incr;
+%if mmsize == 32
+    vextractf128                 xm1, m0, 0x1
+    vextractf128                 xm3, m2, 0x1
+    addp%4                       xm0, xm1
+    addp%4                       xm2, xm3
+%endif
+    cvtsi2s%4                    xm1, fracd
+    subp%4                       xm2, xm0
+    mulp%4                       xm1, xm4
+    shufp%4                      xm1, xm1, q0000
+%if cpuflag(fma4) || cpuflag(fma3)
+    fmaddp%4                     xm0, xm2, xm1, xm0
+%else
+    mulp%4                       xm2, xm1
+    addp%4                       xm0, xm2
+%endif ; cpuflag
+
+    ; horizontal sum & store
+    movhlps                      xm1, xm0
+%ifidn %1, float
+    addps                        xm0, xm1
+    shufps                       xm1, xm0, xm0, q0001
+%endif
+    add                        fracd, dst_incr_modd
+    addp%4                       xm0, xm1
+    add                       indexd, dst_incr_divd
+    movs%4                    [dstq], xm0
+%endif
+    cmp                        fracd, src_incrd
+    jl .skip
+    sub                        fracd, src_incrd
+    inc                       indexd
+
+%if UNIX64
+    DEFINE_ARGS filter_alloc, dst, filter2, phase_count, index, frac, index_incr, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+    DEFINE_ARGS phase_count, filter2, src, filter_alloc, index, frac, index_incr, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, dst, dst_end, filter_bank
+%else ; x86-32
+    DEFINE_ARGS filter1, phase_count, index_incr, frac, index, dst, src
+%endif
+
+.skip:
+%if ARCH_X86_32
+    mov                 phase_countd, phase_count_stackd
+%endif
+    add                         dstq, %2
+    cmp                       indexd, phase_countd
+    jb .index_skip
+.index_while:
+    sub                       indexd, phase_countd
+    lea                         srcq, [srcq+%2]
+    cmp                       indexd, phase_countd
+    jnb .index_while
+.index_skip:
+    cmp                         dstq, dst_endq
+    jne .loop
+
+%if UNIX64
+    DEFINE_ARGS ctx, dst, filter2, phase_count, index, frac, index_incr, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, src, dst_end, filter_bank
+%elif WIN64
+    DEFINE_ARGS ctx, filter2, src, phase_count, index, frac, index_incr, \
+                dst_incr_mod, min_filter_count_x4, min_filter_len_x4, \
+                dst_incr_div, src_incr, dst, dst_end, filter_bank
+%else ; x86-32
+    DEFINE_ARGS filter1, ctx, update_context, frac, index, dst, src
+%endif
+
+    cmp  dword update_context_stackd, 0
+    jz .skip_store
+    ; strictly speaking, the function should always return the consumed
+    ; number of bytes; however, we only use the value if update_context
+    ; is true, so let's just leave it uninitialized otherwise
+    mov                         ctxq, ctx_stackq
+    movifnidn                    rax, srcq
+    mov [ctxq+ResampleContext.frac ], fracd
+    sub                          rax, src_stackq
+    mov [ctxq+ResampleContext.index], indexd
+    shr                          rax, %3
+
+.skip_store:
+%if ARCH_X86_32
+    ADD                          rsp, 0x28
+%endif
+    RET
+%endmacro
+
+INIT_XMM sse
+RESAMPLE_FNS float, 4, 2, s, pf_1
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+%if HAVE_FMA4_EXTERNAL
+INIT_XMM fma4
+RESAMPLE_FNS float, 4, 2, s, pf_1
+%endif
+
+INIT_XMM sse2
+RESAMPLE_FNS int16, 2, 1
+%if HAVE_XOP_EXTERNAL
+INIT_XMM xop
+RESAMPLE_FNS int16, 2, 1
+%endif
+
+INIT_XMM sse2
+RESAMPLE_FNS double, 8, 3, d, pdbl_1
+
+%if HAVE_AVX_EXTERNAL
+INIT_YMM avx
+RESAMPLE_FNS double, 8, 3, d, pdbl_1
+%endif
+%if HAVE_FMA3_EXTERNAL
+INIT_YMM fma3
+RESAMPLE_FNS double, 8, 3, d, pdbl_1
+%endif
diff --git a/libs/ffmpeg/libswresample/x86/resample_init.c b/libs/ffmpeg/libswresample/x86/resample_init.c
new file mode 100644
index 000000000000..3d8b3eabf126
--- /dev/null
+++ b/libs/ffmpeg/libswresample/x86/resample_init.c
@@ -0,0 +1,100 @@
+/*
+ * 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>
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "libavutil/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libswresample/resample.h"
+
+#define RESAMPLE_FUNCS(type, opt) \
+int ff_resample_common_##type##_##opt(ResampleContext *c, void *dst, \
+                                      const void *src, int sz, int upd); \
+int ff_resample_linear_##type##_##opt(ResampleContext *c, void *dst, \
+                                      const void *src, int sz, int upd)
+
+RESAMPLE_FUNCS(int16,  sse2);
+RESAMPLE_FUNCS(int16,  xop);
+RESAMPLE_FUNCS(float,  sse);
+RESAMPLE_FUNCS(float,  avx);
+RESAMPLE_FUNCS(float,  fma3);
+RESAMPLE_FUNCS(float,  fma4);
+RESAMPLE_FUNCS(double, sse2);
+RESAMPLE_FUNCS(double, avx);
+RESAMPLE_FUNCS(double, fma3);
+
+av_cold void swri_resample_dsp_x86_init(ResampleContext *c)
+{
+    av_unused int mm_flags = av_get_cpu_flags();
+
+    switch(c->format){
+    case AV_SAMPLE_FMT_S16P:
+        if (EXTERNAL_SSE2(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_int16_sse2;
+            c->dsp.resample_common = ff_resample_common_int16_sse2;
+        }
+        if (EXTERNAL_XOP(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_int16_xop;
+            c->dsp.resample_common = ff_resample_common_int16_xop;
+        }
+        break;
+    case AV_SAMPLE_FMT_FLTP:
+        if (EXTERNAL_SSE(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_float_sse;
+            c->dsp.resample_common = ff_resample_common_float_sse;
+        }
+        if (EXTERNAL_AVX_FAST(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_float_avx;
+            c->dsp.resample_common = ff_resample_common_float_avx;
+        }
+        if (EXTERNAL_FMA3_FAST(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_float_fma3;
+            c->dsp.resample_common = ff_resample_common_float_fma3;
+        }
+        if (EXTERNAL_FMA4(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_float_fma4;
+            c->dsp.resample_common = ff_resample_common_float_fma4;
+        }
+        break;
+    case AV_SAMPLE_FMT_DBLP:
+        if (EXTERNAL_SSE2(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_double_sse2;
+            c->dsp.resample_common = ff_resample_common_double_sse2;
+        }
+        if (EXTERNAL_AVX_FAST(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_double_avx;
+            c->dsp.resample_common = ff_resample_common_double_avx;
+        }
+        if (EXTERNAL_FMA3_FAST(mm_flags)) {
+            c->dsp.resample_linear = ff_resample_linear_double_fma3;
+            c->dsp.resample_common = ff_resample_common_double_fma3;
+        }
+        break;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libswscale/aarch64/asm-offsets.h b/libs/ffmpeg/libswscale/aarch64/asm-offsets.h
new file mode 100644
index 000000000000..110389c96531
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/asm-offsets.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2025 Arpad Panyik <Arpad.Panyik@arm.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 SWSCALE_AARCH64_ASM_OFFSETS_H
+#define SWSCALE_AARCH64_ASM_OFFSETS_H
+
+/* SwsLuts */
+#define SL_IN  0x00
+#define SL_OUT 0x08
+
+/* SwsColorXform */
+#define SCX_GAMMA     0x00
+#define SCX_MAT       0x10
+#define SCX_GAMMA_IN  (SCX_GAMMA + SL_IN)
+#define SCX_GAMMA_OUT (SCX_GAMMA + SL_OUT)
+#define SCX_MAT_00    SCX_MAT
+#define SCX_MAT_22    (SCX_MAT + 8 * 2)
+
+#endif /* SWSCALE_AARCH64_ASM_OFFSETS_H */
diff --git a/libs/ffmpeg/libswscale/aarch64/hscale.S b/libs/ffmpeg/libswscale/aarch64/hscale.S
new file mode 100644
index 000000000000..6c14246a42bc
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/hscale.S
@@ -0,0 +1,1406 @@
+/*
+ * Copyright (c) 2016 Clément Bœsch <clement stupeflix.com>
+ * Copyright (c) 2019-2021 Sebastian Pop <spop@amazon.com>
+ * Copyright (c) 2022 Jonathan Swinney <jswinney@amazon.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/aarch64/asm.S"
+
+/*
+;-----------------------------------------------------------------------------
+; horizontal line scaling
+;
+; void hscale<source_width>to<intermediate_nbits>_<filterSize>_<opt>
+;                               (SwsInternal *c, int{16,32}_t *dst,
+;                                int dstW, const uint{8,16}_t *src,
+;                                const int16_t *filter,
+;                                const int32_t *filterPos, int filterSize);
+;
+; Scale one horizontal line. Input is either 8-bit width or 16-bit width
+; ($source_width can be either 8, 9, 10 or 16, difference is whether we have to
+; downscale before multiplying). Filter is 14 bits. Output is either 15 bits
+; (in int16_t) or 19 bits (in int32_t), as given in $intermediate_nbits. Each
+; output pixel is generated from $filterSize input pixels, the position of
+; the first pixel is given in filterPos[nOutputPixel].
+;----------------------------------------------------------------------------- */
+
+function ff_hscale8to15_X8_neon, export=1
+        sbfiz           x7, x6, #1, #32             // filterSize*2 (*2 because int16)
+1:      ldr             w8, [x5], #4                // filterPos[idx]
+        ldr             w0, [x5], #4                // filterPos[idx + 1]
+        ldr             w11, [x5], #4               // filterPos[idx + 2]
+        ldr             w9, [x5], #4                // filterPos[idx + 3]
+        mov             x16, x4                     // filter0 = filter
+        add             x12, x16, x7                // filter1 = filter0 + filterSize*2
+        add             x13, x12, x7                // filter2 = filter1 + filterSize*2
+        add             x4, x13, x7                 // filter3 = filter2 + filterSize*2
+        movi            v0.16b, #0                  // val sum part 1 (for dst[0])
+        movi            v1.16b, #0                  // val sum part 2 (for dst[1])
+        movi            v2.16b, #0                  // val sum part 3 (for dst[2])
+        movi            v3.16b, #0                  // val sum part 4 (for dst[3])
+        add             x17, x3, w8, uxtw           // srcp + filterPos[0]
+        add             x8,  x3, w0, uxtw           // srcp + filterPos[1]
+        add             x0, x3, w11, uxtw           // srcp + filterPos[2]
+        add             x11, x3, w9, uxtw           // srcp + filterPos[3]
+        mov             w15, w6                     // filterSize counter
+2:      ld1             {v4.8b}, [x17], #8          // srcp[filterPos[0] + {0..7}]
+        ld1             {v5.8h}, [x16], #16         // load 8x16-bit filter values, part 1
+        ld1             {v6.8b}, [x8], #8           // srcp[filterPos[1] + {0..7}]
+        ld1             {v7.8h}, [x12], #16         // load 8x16-bit at filter+filterSize
+        uxtl            v4.8h, v4.8b                // unpack part 1 to 16-bit
+        smlal           v0.4s, v4.4h, v5.4h         // v0 accumulates srcp[filterPos[0] + {0..3}] * filter[{0..3}]
+        smlal2          v0.4s, v4.8h, v5.8h         // v0 accumulates srcp[filterPos[0] + {4..7}] * filter[{4..7}]
+        ld1             {v16.8b}, [x0], #8          // srcp[filterPos[2] + {0..7}]
+        ld1             {v17.8h}, [x13], #16        // load 8x16-bit at filter+2*filterSize
+        uxtl            v6.8h, v6.8b                // unpack part 2 to 16-bit
+        smlal           v1.4s, v6.4h, v7.4h         // v1 accumulates srcp[filterPos[1] + {0..3}] * filter[{0..3}]
+        uxtl            v16.8h, v16.8b              // unpack part 3 to 16-bit
+        smlal           v2.4s, v16.4h, v17.4h       // v2 accumulates srcp[filterPos[2] + {0..3}] * filter[{0..3}]
+        smlal2          v2.4s, v16.8h, v17.8h       // v2 accumulates srcp[filterPos[2] + {4..7}] * filter[{4..7}]
+        ld1             {v18.8b}, [x11], #8         // srcp[filterPos[3] + {0..7}]
+        smlal2          v1.4s, v6.8h, v7.8h         // v1 accumulates srcp[filterPos[1] + {4..7}] * filter[{4..7}]
+        ld1             {v19.8h}, [x4], #16         // load 8x16-bit at filter+3*filterSize
+        subs            w15, w15, #8                // j -= 8: processed 8/filterSize
+        uxtl            v18.8h, v18.8b              // unpack part 4 to 16-bit
+        smlal           v3.4s, v18.4h, v19.4h       // v3 accumulates srcp[filterPos[3] + {0..3}] * filter[{0..3}]
+        smlal2          v3.4s, v18.8h, v19.8h       // v3 accumulates srcp[filterPos[3] + {4..7}] * filter[{4..7}]
+        b.gt            2b                          // inner loop if filterSize not consumed completely
+        addp            v0.4s, v0.4s, v1.4s         // part01 horizontal pair adding
+        addp            v2.4s, v2.4s, v3.4s         // part23 horizontal pair adding
+        addp            v0.4s, v0.4s, v2.4s         // part0123 horizontal pair adding
+        subs            w2, w2, #4                  // dstW -= 4
+        sqshrn          v0.4h, v0.4s, #7            // shift and clip the 2x16-bit final values
+        st1             {v0.4h}, [x1], #8           // write to destination part0123
+        b.gt            1b                          // loop until end of line
+        ret
+endfunc
+
+function ff_hscale8to15_X4_neon, export=1
+// x0  SwsInternal *c (not used)
+// x1  int16_t *dst
+// w2  int dstW
+// x3  const uint8_t *src
+// x4  const int16_t *filter
+// x5  const int32_t *filterPos
+// w6  int filterSize
+
+// This function for filter sizes that are 4 mod 8. In other words, anything that's 0 mod 4 but not
+// 0 mod 8. It also assumes that dstW is 0 mod 4.
+
+        lsl             w7, w6, #1                  // w7 = filterSize * 2
+1:
+        ldp             w8, w9,  [x5]               // filterPos[idx + 0], [idx + 1]
+        ldp             w10, w11, [x5, #8]          // filterPos[idx + 2], [idx + 3]
+
+        movi            v16.16b, #0                 // initialize accumulator for idx + 0
+        movi            v17.16b, #0                 // initialize accumulator for idx + 1
+        movi            v18.16b, #0                 // initialize accumulator for idx + 2
+        movi            v19.16b, #0                 // initialize accumulator for idx + 3
+
+        mov             x12, x4                     // filter pointer for idx + 0
+        add             x13, x4, x7                 // filter pointer for idx + 1
+        add             x8, x3, w8, uxtw            // srcp + filterPos[idx + 0]
+        add             x9, x3, w9, uxtw            // srcp + filterPos[idx + 1]
+
+        add             x14, x13, x7                // filter pointer for idx + 2
+        add             x10, x3, w10, uxtw          // srcp + filterPos[idx + 2]
+        add             x11, x3, w11, uxtw          // srcp + filterPos[idx + 3]
+
+        mov             w0, w6                      // copy filterSize to a temp register, w0
+        add             x5, x5, #16                 // advance the filterPos pointer
+        add             x15, x14, x7                // filter pointer for idx + 3
+        mov             x16, xzr                    // temp register for offsetting filter pointers
+
+2:
+        // This section loops over 8-wide chunks of filter size
+        ldr             d4, [x8], #8                // load 8 bytes from srcp for idx + 0
+        ldr             q0, [x12, x16]              // load 8 values, 16 bytes from filter for idx + 0
+
+        ldr             d5, [x9], #8                // load 8 bytes from srcp for idx + 1
+        ldr             q1, [x13, x16]              // load 8 values, 16 bytes from filter for idx + 1
+
+        uxtl            v4.8h, v4.8b                // unsigned extend long for idx + 0
+        uxtl            v5.8h, v5.8b                // unsigned extend long for idx + 1
+
+        ldr             d6, [x10], #8               // load 8 bytes from srcp for idx + 2
+        ldr             q2, [x14, x16]              // load 8 values, 16 bytes from filter for idx + 2
+
+        smlal           v16.4s, v0.4h, v4.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 0
+        smlal           v17.4s, v1.4h, v5.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 1
+
+        ldr             d7, [x11], #8               // load 8 bytes from srcp for idx + 3
+        ldr             q3, [x15, x16]              // load 8 values, 16 bytes from filter for idx + 3
+
+        sub             w0, w0, #8                  // decrement the remaining filterSize counter
+        smlal2          v16.4s, v0.8h, v4.8h        // val += src[srcPos + j + 4..7] * filter[fs * i + j + 4..7], idx + 0
+        smlal2          v17.4s, v1.8h, v5.8h        // val += src[srcPos + j + 4..7] * filter[fs * i + j + 4..7], idx + 1
+        uxtl            v6.8h, v6.8b                // unsigned extend long for idx + 2
+        uxtl            v7.8h, v7.8b                // unsigned extend long for idx + 3
+        smlal           v18.4s, v2.4h, v6.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 2
+        smlal           v19.4s, v3.4h, v7.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 3
+
+        cmp             w0, #8                      // are there at least 8 more elements in filter to consume?
+        add             x16, x16, #16               // advance the offsetting register for filter values
+
+        smlal2          v18.4s, v2.8h, v6.8h        // val += src[srcPos + j + 4..7] * filter[fs * i + j + 4..7], idx + 2
+        smlal2          v19.4s, v3.8h, v7.8h        // val += src[srcPos + j + 4..7] * filter[fs * i + j + 4..7], idx + 3
+
+        b.ge            2b                          // branch back to inner loop
+
+        // complete the remaining 4 filter elements
+        sub             x17, x7, #8                 // calculate the offset of the filter pointer for the remaining 4 elements
+
+        ldr             s4, [x8]                    // load 4 bytes from srcp for idx + 0
+        ldr             d0, [x12, x17]              // load 4 values, 8 bytes from filter for idx + 0
+        ldr             s5, [x9]                    // load 4 bytes from srcp for idx + 1
+        ldr             d1, [x13, x17]              // load 4 values, 8 bytes from filter for idx + 1
+
+        uxtl            v4.8h, v4.8b                // unsigned extend long for idx + 0
+        uxtl            v5.8h, v5.8b                // unsigned extend long for idx + 1
+
+        ldr             s6, [x10]                   // load 4 bytes from srcp for idx + 2
+        ldr             d2, [x14, x17]              // load 4 values, 8 bytes from filter for idx + 2
+        smlal           v16.4s, v0.4h, v4.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 0
+        smlal           v17.4s, v1.4h, v5.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 1
+        ldr             s7, [x11]                   // load 4 bytes from srcp for idx + 3
+        ldr             d3, [x15, x17]              // load 4 values, 8 bytes from filter for idx + 3
+
+        uxtl            v6.8h, v6.8b                // unsigned extend long for idx + 2
+        uxtl            v7.8h, v7.8b                // unsigned extend long for idx + 3
+        addp            v16.4s, v16.4s, v17.4s      // horizontal pair adding for idx 0,1
+        smlal           v18.4s, v2.4h, v6.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 2
+        smlal           v19.4s, v3.4h, v7.4h        // val += src[srcPos + j + 0..3] * filter[fs * i + j + 0..3], idx + 3
+
+        addp            v18.4s, v18.4s, v19.4s      // horizontal pair adding for idx 2,3
+        addp            v16.4s, v16.4s, v18.4s      // final horizontal pair adding producing one vector with results for idx = 0..3
+
+        subs            w2, w2, #4                  // dstW -= 4
+        sqshrn          v0.4h, v16.4s, #7           // shift and clip the 2x16-bit final values
+        st1             {v0.4h}, [x1], #8           // write to destination idx 0..3
+        add             x4, x4, x7, lsl #2          // filter += (filterSize*2) * 4
+        b.gt            1b                          // loop until end of line
+        ret
+endfunc
+
+function ff_hscale8to15_4_neon, export=1
+// x0  SwsInternal *c (not used)
+// x1  int16_t *dst
+// x2  int dstW
+// x3  const uint8_t *src
+// x4  const int16_t *filter
+// x5  const int32_t *filterPos
+// x6  int filterSize
+// x8-x15 registers for gathering src data
+
+// v0      madd accumulator 4S
+// v1-v4   filter values (16 bit) 8H
+// v5      madd accumulator 4S
+// v16-v19 src values (8 bit) 8B
+
+// This implementation has 4 sections:
+//  1. Prefetch src data
+//  2. Interleaved prefetching src data and madd
+//  3. Complete madd
+//  4. Complete remaining iterations when dstW % 8 != 0
+
+        sub             sp, sp, #32                 // allocate 32 bytes on the stack
+        cmp             w2, #16                     // if dstW <16, skip to the last block used for wrapping up
+        b.lt            2f
+
+        // load 8 values from filterPos to be used as offsets into src
+        ldp             w8, w9,  [x5]               // filterPos[idx + 0], [idx + 1]
+        ldp             w10, w11, [x5, #8]          // filterPos[idx + 2], [idx + 3]
+        ldp             w12, w13, [x5, #16]         // filterPos[idx + 4], [idx + 5]
+        ldp             w14, w15, [x5, #24]         // filterPos[idx + 6], [idx + 7]
+        add             x5, x5, #32                 // advance filterPos
+
+        // gather random access data from src into contiguous memory
+        ldr             w8, [x3, w8, uxtw]          // src[filterPos[idx + 0]][0..3]
+        ldr             w9, [x3, w9, uxtw]          // src[filterPos[idx + 1]][0..3]
+        ldr             w10, [x3, w10, uxtw]        // src[filterPos[idx + 2]][0..3]
+        ldr             w11, [x3, w11, uxtw]        // src[filterPos[idx + 3]][0..3]
+        ldr             w12, [x3, w12, uxtw]        // src[filterPos[idx + 4]][0..3]
+        ldr             w13, [x3, w13, uxtw]        // src[filterPos[idx + 5]][0..3]
+        ldr             w14, [x3, w14, uxtw]        // src[filterPos[idx + 6]][0..3]
+        ldr             w15, [x3, w15, uxtw]        // src[filterPos[idx + 7]][0..3]
+        stp             w8, w9, [sp]                // *scratch_mem = { src[filterPos[idx + 0]][0..3], src[filterPos[idx + 1]][0..3] }
+        stp             w10, w11, [sp, #8]          // *scratch_mem = { src[filterPos[idx + 2]][0..3], src[filterPos[idx + 3]][0..3] }
+        stp             w12, w13, [sp, #16]         // *scratch_mem = { src[filterPos[idx + 4]][0..3], src[filterPos[idx + 5]][0..3] }
+        stp             w14, w15, [sp, #24]         // *scratch_mem = { src[filterPos[idx + 6]][0..3], src[filterPos[idx + 7]][0..3] }
+
+1:
+        ld4             {v16.8b, v17.8b, v18.8b, v19.8b}, [sp] // transpose 8 bytes each from src into 4 registers
+
+        // load 8 values from filterPos to be used as offsets into src
+        ldp             w8, w9,  [x5]               // filterPos[idx + 0][0..3], [idx + 1][0..3], next iteration
+        ldp             w10, w11, [x5, #8]          // filterPos[idx + 2][0..3], [idx + 3][0..3], next iteration
+        ldp             w12, w13, [x5, #16]         // filterPos[idx + 4][0..3], [idx + 5][0..3], next iteration
+        ldp             w14, w15, [x5, #24]         // filterPos[idx + 6][0..3], [idx + 7][0..3], next iteration
+
+        movi            v0.16b, #0                  // Clear madd accumulator for idx 0..3
+        movi            v5.16b, #0                  // Clear madd accumulator for idx 4..7
+
+        ld4             {v1.8h, v2.8h, v3.8h, v4.8h}, [x4], #64 // load filter idx + 0..7
+
+        add             x5, x5, #32                 // advance filterPos
+
+        // interleaved SIMD and prefetching intended to keep ld/st and vector pipelines busy
+        uxtl            v16.8h, v16.8b              // unsigned extend long, convert src data to 16-bit
+        uxtl            v17.8h, v17.8b              // unsigned extend long, convert src data to 16-bit
+        ldr             w8, [x3, w8, uxtw]          // src[filterPos[idx + 0]], next iteration
+        ldr             w9, [x3, w9, uxtw]          // src[filterPos[idx + 1]], next iteration
+        uxtl            v18.8h, v18.8b              // unsigned extend long, convert src data to 16-bit
+        uxtl            v19.8h, v19.8b              // unsigned extend long, convert src data to 16-bit
+        ldr             w10, [x3, w10, uxtw]        // src[filterPos[idx + 2]], next iteration
+        ldr             w11, [x3, w11, uxtw]        // src[filterPos[idx + 3]], next iteration
+
+        smlal           v0.4s, v1.4h, v16.4h        // multiply accumulate inner loop j = 0, idx = 0..3
+        smlal           v0.4s, v2.4h, v17.4h        // multiply accumulate inner loop j = 1, idx = 0..3
+        ldr             w12, [x3, w12, uxtw]        // src[filterPos[idx + 4]], next iteration
+        ldr             w13, [x3, w13, uxtw]        // src[filterPos[idx + 5]], next iteration
+        smlal           v0.4s, v3.4h, v18.4h        // multiply accumulate inner loop j = 2, idx = 0..3
+        smlal           v0.4s, v4.4h, v19.4h        // multiply accumulate inner loop j = 3, idx = 0..3
+        ldr             w14, [x3, w14, uxtw]        // src[filterPos[idx + 6]], next iteration
+        ldr             w15, [x3, w15, uxtw]        // src[filterPos[idx + 7]], next iteration
+
+        smlal2          v5.4s, v1.8h, v16.8h        // multiply accumulate inner loop j = 0, idx = 4..7
+        smlal2          v5.4s, v2.8h, v17.8h        // multiply accumulate inner loop j = 1, idx = 4..7
+        stp             w8, w9, [sp]                // *scratch_mem = { src[filterPos[idx + 0]][0..3], src[filterPos[idx + 1]][0..3] }
+        stp             w10, w11, [sp, #8]          // *scratch_mem = { src[filterPos[idx + 2]][0..3], src[filterPos[idx + 3]][0..3] }
+        smlal2          v5.4s, v3.8h, v18.8h        // multiply accumulate inner loop j = 2, idx = 4..7
+        smlal2          v5.4s, v4.8h, v19.8h        // multiply accumulate inner loop j = 3, idx = 4..7
+        stp             w12, w13, [sp, #16]         // *scratch_mem = { src[filterPos[idx + 4]][0..3], src[filterPos[idx + 5]][0..3] }
+        stp             w14, w15, [sp, #24]         // *scratch_mem = { src[filterPos[idx + 6]][0..3], src[filterPos[idx + 7]][0..3] }
+
+        sub             w2, w2, #8                  // dstW -= 8
+        sqshrn          v0.4h, v0.4s, #7            // shift and clip the 2x16-bit final values
+        sqshrn          v1.4h, v5.4s, #7            // shift and clip the 2x16-bit final values
+        st1             {v0.4h, v1.4h}, [x1], #16   // write to dst[idx + 0..7]
+        cmp             w2, #16                     // continue on main loop if there are at least 16 iterations left
+        b.ge            1b
+
+        // last full iteration
+        ld4             {v16.8b, v17.8b, v18.8b, v19.8b}, [sp]
+        ld4             {v1.8h, v2.8h, v3.8h, v4.8h}, [x4], #64 // load filter idx + 0..7
+
+        movi            v0.16b, #0                  // Clear madd accumulator for idx 0..3
+        movi            v5.16b, #0                  // Clear madd accumulator for idx 4..7
+
+        uxtl            v16.8h, v16.8b              // unsigned extend long, convert src data to 16-bit
+        uxtl            v17.8h, v17.8b              // unsigned extend long, convert src data to 16-bit
+        uxtl            v18.8h, v18.8b              // unsigned extend long, convert src data to 16-bit
+        uxtl            v19.8h, v19.8b              // unsigned extend long, convert src data to 16-bit
+
+        smlal           v0.4s, v1.4h, v16.4h        // multiply accumulate inner loop j = 0, idx = 0..3
+        smlal           v0.4s, v2.4h, v17.4h        // multiply accumulate inner loop j = 1, idx = 0..3
+        smlal           v0.4s, v3.4h, v18.4h        // multiply accumulate inner loop j = 2, idx = 0..3
+        smlal           v0.4s, v4.4h, v19.4h        // multiply accumulate inner loop j = 3, idx = 0..3
+
+        smlal2          v5.4s, v1.8h, v16.8h        // multiply accumulate inner loop j = 0, idx = 4..7
+        smlal2          v5.4s, v2.8h, v17.8h        // multiply accumulate inner loop j = 1, idx = 4..7
+        smlal2          v5.4s, v3.8h, v18.8h        // multiply accumulate inner loop j = 2, idx = 4..7
+        smlal2          v5.4s, v4.8h, v19.8h        // multiply accumulate inner loop j = 3, idx = 4..7
+
+        subs            w2, w2, #8                  // dstW -= 8
+        sqshrn          v0.4h, v0.4s, #7            // shift and clip the 2x16-bit final values
+        sqshrn          v1.4h, v5.4s, #7            // shift and clip the 2x16-bit final values
+        st1             {v0.4h, v1.4h}, [x1], #16   // write to dst[idx + 0..7]
+
+        cbnz            w2, 2f                      // if >0 iterations remain, jump to the wrap up section
+
+        add             sp, sp, #32                 // clean up stack
+        ret
+
+        // finish up when dstW % 8 != 0 or dstW < 16
+2:
+        // load src
+        ldr             w8, [x5], #4                // filterPos[i]
+        add             x9, x3, w8, uxtw            // calculate the address for src load
+        ld1             {v5.s}[0], [x9]             // src[filterPos[i] + 0..3]
+        // load filter
+        ld1             {v6.4h}, [x4], #8           // filter[filterSize * i + 0..3]
+
+        uxtl            v5.8h, v5.8b                // unsigned extend long, convert src data to 16-bit
+        smull           v0.4s, v5.4h, v6.4h         // 4 iterations of src[...] * filter[...]
+        addv            s0, v0.4s                   // add up products of src and filter values
+        sqshrn          h0, s0, #7                  // shift and clip the 2x16-bit final value
+        st1             {v0.h}[0], [x1], #2         // dst[i] = ...
+        sub             w2, w2, #1                  // dstW--
+        cbnz            w2, 2b
+
+        add             sp, sp, #32                 // clean up stack
+        ret
+endfunc
+
+function ff_hscale8to19_4_neon, export=1
+        // x0               SwsInternal *c (unused)
+        // x1               int32_t *dst
+        // w2               int dstW
+        // x3               const uint8_t *src // treat it as uint16_t *src
+        // x4               const uint16_t *filter
+        // x5               const int32_t *filterPos
+        // w6               int filterSize
+
+        movi            v18.4s, #1
+        movi            v17.4s, #1
+        shl             v18.4s, v18.4s, #19
+        sub             v18.4s, v18.4s, v17.4s      // max allowed value
+
+        cmp             w2, #16
+        b.lt            2f // move to last block
+
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        add             x5, x5, #32
+
+        // load data from
+        ldr             w8, [x3, w8, uxtw]
+        ldr             w9, [x3, w9, uxtw]
+        ldr             w10, [x3, w10, uxtw]
+        ldr             w11, [x3, w11, uxtw]
+        ldr             w12, [x3, w12, uxtw]
+        ldr             w13, [x3, w13, uxtw]
+        ldr             w14, [x3, w14, uxtw]
+        ldr             w15, [x3, w15, uxtw]
+
+        sub             sp, sp, #32
+
+        stp             w8, w9, [sp]
+        stp             w10, w11, [sp, #8]
+        stp             w12, w13, [sp, #16]
+        stp             w14, w15, [sp, #24]
+
+1:
+        ld4             {v0.8b, v1.8b, v2.8b, v3.8b}, [sp]
+        ld4             {v28.8h, v29.8h, v30.8h, v31.8h}, [x4], #64 // filter[0..7]
+        // load filterPositions into registers for next iteration
+
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        add             x5, x5, #32
+        uxtl            v0.8h, v0.8b
+        ldr             w8, [x3, w8, uxtw]
+        smull           v5.4s, v0.4h, v28.4h        // multiply first column of src
+        ldr             w9, [x3, w9, uxtw]
+        smull2          v6.4s, v0.8h, v28.8h
+        stp             w8, w9, [sp]
+
+        uxtl            v1.8h, v1.8b
+        ldr             w10, [x3, w10, uxtw]
+        smlal           v5.4s, v1.4h, v29.4h        // multiply second column of src
+        ldr             w11, [x3, w11, uxtw]
+        smlal2          v6.4s, v1.8h, v29.8h
+        stp             w10, w11, [sp, #8]
+
+        uxtl            v2.8h, v2.8b
+        ldr             w12, [x3, w12, uxtw]
+        smlal           v5.4s, v2.4h, v30.4h        // multiply third column of src
+        ldr             w13, [x3, w13, uxtw]
+        smlal2          v6.4s, v2.8h, v30.8h
+        stp             w12, w13, [sp, #16]
+
+        uxtl            v3.8h, v3.8b
+        ldr             w14, [x3, w14, uxtw]
+        smlal           v5.4s, v3.4h, v31.4h        // multiply fourth column of src
+        ldr             w15, [x3, w15, uxtw]
+        smlal2          v6.4s, v3.8h, v31.8h
+        stp             w14, w15, [sp, #24]
+
+        sub             w2, w2, #8
+        sshr            v5.4s, v5.4s, #3
+        sshr            v6.4s, v6.4s, #3
+        smin            v5.4s, v5.4s, v18.4s
+        smin            v6.4s, v6.4s, v18.4s
+
+        st1             {v5.4s, v6.4s}, [x1], #32
+        cmp             w2, #16
+        b.ge            1b
+
+        // here we make last iteration, without updating the registers
+        ld4             {v0.8b, v1.8b, v2.8b, v3.8b}, [sp]
+        ld4             {v28.8h, v29.8h, v30.8h, v31.8h}, [x4], #64 // filter[0..7]
+
+        uxtl            v0.8h, v0.8b
+        uxtl            v1.8h, v1.8b
+        smull           v5.4s, v0.4h, v28.4h
+        smull2          v6.4s, v0.8h, v28.8h
+        uxtl            v2.8h, v2.8b
+        smlal           v5.4s, v1.4h, v29.4h
+        smlal2          v6.4s, v1.8h, v29.8h
+        uxtl            v3.8h, v3.8b
+        smlal           v5.4s, v2.4h, v30.4h
+        smlal2          v6.4s, v2.8h, v30.8h
+        smlal           v5.4s, v3.4h, v31.4h
+        smlal2          v6.4s, v3.8h, v31.8h
+
+        sshr            v5.4s, v5.4s, #3
+        sshr            v6.4s, v6.4s, #3
+
+        smin            v5.4s, v5.4s, v18.4s
+        smin            v6.4s, v6.4s, v18.4s
+
+        sub             w2, w2, #8
+        st1             {v5.4s, v6.4s}, [x1], #32
+        add             sp, sp, #32 // restore stack
+        cbnz            w2, 2f
+
+        ret
+
+2:
+        ldr             w8, [x5], #4 // load filterPos
+        add             x9, x3, w8, uxtw // src + filterPos
+        ld1             {v0.s}[0], [x9] // load 4 * uint8_t* into one single
+        ld1             {v31.4h}, [x4], #8
+        uxtl            v0.8h, v0.8b
+        smull           v5.4s, v0.4h, v31.4h
+        saddlv          d0, v5.4s
+        sqshrn          s0, d0, #3
+        smin            v0.4s, v0.4s, v18.4s
+        st1             {v0.s}[0], [x1], #4
+        sub             w2, w2, #1
+        cbnz            w2, 2b // if iterations remain jump to beginning
+
+        ret
+endfunc
+
+function ff_hscale8to19_X8_neon, export=1
+        movi            v20.4s, #1
+        movi            v17.4s, #1
+        shl             v20.4s, v20.4s, #19
+        sub             v20.4s, v20.4s, v17.4s
+
+        sbfiz           x7, x6, #1, #32             // filterSize*2 (*2 because int16)
+1:
+        mov             x16, x4                     // filter0 = filter
+        ldr             w8, [x5], #4                // filterPos[idx]
+        add             x12, x16, x7                // filter1 = filter0 + filterSize*2
+        ldr             w0, [x5], #4                // filterPos[idx + 1]
+        add             x13, x12, x7                // filter2 = filter1 + filterSize*2
+        ldr             w11, [x5], #4               // filterPos[idx + 2]
+        add             x4, x13, x7                 // filter3 = filter2 + filterSize*2
+        ldr             w9, [x5], #4                // filterPos[idx + 3]
+        movi            v0.16b, #0                  // val sum part 1 (for dst[0])
+        movi            v1.16b, #0                  // val sum part 2 (for dst[1])
+        movi            v2.16b, #0                  // val sum part 3 (for dst[2])
+        movi            v3.16b, #0                  // val sum part 4 (for dst[3])
+        add             x17, x3, w8, uxtw           // srcp + filterPos[0]
+        add             x8,  x3, w0, uxtw           // srcp + filterPos[1]
+        add             x0, x3, w11, uxtw           // srcp + filterPos[2]
+        add             x11, x3, w9, uxtw           // srcp + filterPos[3]
+        mov             w15, w6                     // filterSize counter
+2:      ld1             {v4.8b}, [x17], #8          // srcp[filterPos[0] + {0..7}]
+        ld1             {v5.8h}, [x16], #16         // load 8x16-bit filter values, part 1
+        uxtl            v4.8h, v4.8b                // unpack part 1 to 16-bit
+        smlal           v0.4s, v4.4h, v5.4h         // v0 accumulates srcp[filterPos[0] + {0..3}] * filter[{0..3}]
+        ld1             {v6.8b}, [x8], #8           // srcp[filterPos[1] + {0..7}]
+        smlal2          v0.4s, v4.8h, v5.8h         // v0 accumulates srcp[filterPos[0] + {4..7}] * filter[{4..7}]
+        ld1             {v7.8h}, [x12], #16         // load 8x16-bit at filter+filterSize
+        ld1             {v16.8b}, [x0], #8          // srcp[filterPos[2] + {0..7}]
+        uxtl            v6.8h, v6.8b                // unpack part 2 to 16-bit
+        ld1             {v17.8h}, [x13], #16        // load 8x16-bit at filter+2*filterSize
+        uxtl            v16.8h, v16.8b              // unpack part 3 to 16-bit
+        smlal           v1.4s, v6.4h, v7.4h         // v1 accumulates srcp[filterPos[1] + {0..3}] * filter[{0..3}]
+        ld1             {v18.8b}, [x11], #8         // srcp[filterPos[3] + {0..7}]
+        smlal           v2.4s, v16.4h, v17.4h       // v2 accumulates srcp[filterPos[2] + {0..3}] * filter[{0..3}]
+        ld1             {v19.8h}, [x4], #16         // load 8x16-bit at filter+3*filterSize
+        smlal2          v2.4s, v16.8h, v17.8h       // v2 accumulates srcp[filterPos[2] + {4..7}] * filter[{4..7}]
+        uxtl            v18.8h, v18.8b              // unpack part 4 to 16-bit
+        smlal2          v1.4s, v6.8h, v7.8h         // v1 accumulates srcp[filterPos[1] + {4..7}] * filter[{4..7}]
+        smlal           v3.4s, v18.4h, v19.4h       // v3 accumulates srcp[filterPos[3] + {0..3}] * filter[{0..3}]
+        subs            w15, w15, #8                // j -= 8: processed 8/filterSize
+        smlal2          v3.4s, v18.8h, v19.8h       // v3 accumulates srcp[filterPos[3] + {4..7}] * filter[{4..7}]
+        b.gt            2b                          // inner loop if filterSize not consumed completely
+        addp            v0.4s, v0.4s, v1.4s         // part01 horizontal pair adding
+        addp            v2.4s, v2.4s, v3.4s         // part23 horizontal pair adding
+        addp            v0.4s, v0.4s, v2.4s         // part0123 horizontal pair adding
+        subs            w2, w2, #4                  // dstW -= 4
+        sshr            v0.4s, v0.4s, #3            // shift and clip the 2x16-bit final values
+        smin            v0.4s, v0.4s, v20.4s
+        st1             {v0.4s}, [x1], #16           // write to destination part0123
+        b.gt            1b                          // loop until end of line
+        ret
+endfunc
+
+function ff_hscale8to19_X4_neon, export=1
+        // x0  SwsInternal *c (not used)
+        // x1  int16_t *dst
+        // w2  int dstW
+        // x3  const uint8_t *src
+        // x4  const int16_t *filter
+        // x5  const int32_t *filterPos
+        // w6  int filterSize
+
+        movi            v20.4s, #1
+        movi            v17.4s, #1
+        shl             v20.4s, v20.4s, #19
+        sub             v20.4s, v20.4s, v17.4s
+
+        lsl             w7, w6, #1
+1:
+        ldp             w8, w9, [x5]
+        ldp             w10, w11, [x5, #8]
+
+        movi            v16.16b, #0                 // initialize accumulator for idx + 0
+        movi            v17.16b, #0                 // initialize accumulator for idx + 1
+        movi            v18.16b, #0                 // initialize accumulator for idx + 2
+        movi            v19.16b, #0                 // initialize accumulator for idx + 3
+
+        mov             x12, x4                     // filter + 0
+        add             x13, x4, x7                 // filter + 1
+        add             x8, x3, w8, uxtw            // srcp + filterPos 0
+        add             x14, x13, x7                // filter + 2
+        add             x9, x3, w9, uxtw            // srcp + filterPos 1
+        add             x15, x14, x7                // filter + 3
+        add             x10, x3, w10, uxtw          // srcp + filterPos 2
+        mov             w0, w6                      // save the filterSize to temporary variable
+        add             x11, x3, w11, uxtw          // srcp + filterPos 3
+        add             x5, x5, #16                 // advance filter position
+        mov             x16, xzr                    // clear the register x16 used for offsetting the filter values
+
+2:
+        ldr             d4, [x8], #8                // load src values for idx 0
+        ldr             q31, [x12, x16]             // load filter values for idx 0
+        uxtl            v4.8h, v4.8b                // extend type to match the filter' size
+        ldr             d5, [x9], #8                // load src values for idx 1
+        smlal           v16.4s, v4.4h, v31.4h       // multiplication of lower half for idx 0
+        uxtl            v5.8h, v5.8b                // extend type to match the filter' size
+        ldr             q30, [x13, x16]             // load filter values for idx 1
+        smlal2          v16.4s, v4.8h, v31.8h       // multiplication of upper half for idx 0
+        ldr             d6, [x10], #8               // load src values for idx 2
+        ldr             q29, [x14, x16]             // load filter values for idx 2
+        smlal           v17.4s, v5.4h, v30.4h       // multiplication of lower half for idx 1
+        ldr             d7, [x11], #8               // load src values for idx 3
+        smlal2          v17.4s, v5.8h, v30.8h       // multiplication of upper half for idx 1
+        uxtl            v6.8h, v6.8b                // extend tpye to matchi the filter's size
+        ldr             q28, [x15, x16]             // load filter values for idx 3
+        smlal           v18.4s, v6.4h, v29.4h       // multiplication of lower half for idx 2
+        uxtl            v7.8h, v7.8b
+        smlal2          v18.4s, v6.8h, v29.8h       // multiplication of upper half for idx 2
+        sub             w0, w0, #8
+        smlal           v19.4s, v7.4h, v28.4h       // multiplication of lower half for idx 3
+        cmp             w0, #8
+        smlal2          v19.4s, v7.8h, v28.8h       // multiplication of upper half for idx 3
+        add             x16, x16, #16                // advance filter values indexing
+
+        b.ge            2b
+
+
+        // 4 iterations left
+
+        sub             x17, x7, #8                 // step back to wrap up the filter pos for last 4 elements
+
+        ldr             s4, [x8]                    // load src values for idx 0
+        ldr             d31, [x12, x17]             // load filter values for idx 0
+        uxtl            v4.8h, v4.8b                // extend type to match the filter' size
+        ldr             s5, [x9]                    // load src values for idx 1
+        smlal           v16.4s, v4.4h, v31.4h
+        ldr             d30, [x13, x17]             // load filter values for idx 1
+        uxtl            v5.8h, v5.8b                // extend type to match the filter' size
+        ldr             s6, [x10]                   // load src values for idx 2
+        smlal           v17.4s, v5.4h, v30.4h
+        uxtl            v6.8h, v6.8b                // extend type to match the filter's size
+        ldr             d29, [x14, x17]             // load filter values for idx 2
+        ldr             s7, [x11]                   // load src values for idx 3
+        addp            v16.4s, v16.4s, v17.4s
+        uxtl            v7.8h, v7.8b
+        ldr             d28, [x15, x17]             // load filter values for idx 3
+        smlal           v18.4s, v6.4h, v29.4h
+        smlal           v19.4s, v7.4h, v28.4h
+        subs            w2, w2, #4
+        addp            v18.4s, v18.4s, v19.4s
+        addp            v16.4s, v16.4s, v18.4s
+        sshr            v16.4s, v16.4s, #3
+        smin            v16.4s, v16.4s, v20.4s
+
+        st1             {v16.4s}, [x1], #16
+        add             x4, x4, x7, lsl #2
+        b.gt            1b
+        ret
+endfunc
+
+
+.macro hscale_iter src, src2, filter, dst1, dst2
+        uxtl            \src\().4s, \src\().4h
+        sxtl            v19.4s, \filter\().4h
+        mul             \dst1\().4s, \src\().4s, v19.4s
+        uxtl            \src2\().4s, \src2\().4h
+        sxtl2           \filter\().4s, \filter\().8h
+        mul             \dst2\().4s, \src2\().4s, \filter\().4s
+.endm
+
+function ff_hscale16to15_4_neon_asm, export=1
+        // w0               int shift
+        // x1               int32_t *dst
+        // w2               int dstW
+        // x3               const uint8_t *src // treat it as uint16_t *src
+        // x4               const uint16_t *filter
+        // x5               const int32_t *filterPos
+        // w6               int filterSize
+
+        movi            v18.4s, #1
+        movi            v17.4s, #1
+        shl             v18.4s, v18.4s, #15
+        sub             v18.4s, v18.4s, v17.4s      // max allowed value
+        dup             v17.4s, w0                  // read shift
+        neg             v17.4s, v17.4s              // negate it, so it can be used in sshl (effectively shift right)
+
+        cmp             w2, #16
+        b.lt            2f // move to last block
+
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        add             x5, x5, #32
+
+        // shift all filterPos left by one, as uint16_t will be read
+        ld1             {v28.8h, v29.8h, v30.8h, v31.8h}, [x4], #64 // filter[0..7]
+        lsl             x8, x8, #1
+        lsl             x9, x9, #1
+        lsl             x10, x10, #1
+        lsl             x11, x11, #1
+        lsl             x12, x12, #1
+        lsl             x13, x13, #1
+        lsl             x14, x14, #1
+        lsl             x15, x15, #1
+
+        // load src with given offset
+        ldr             d0, [x3, w8,  uxtw]
+        ldr             d1, [x3, w9,  uxtw]
+        ldr             d2, [x3, w10, uxtw]
+        ldr             d3, [x3, w11, uxtw]
+        ldr             d4, [x3, w12, uxtw]
+        ldr             d5, [x3, w13, uxtw]
+        ldr             d6, [x3, w14, uxtw]
+        ldr             d7, [x3, w15, uxtw]
+
+1:
+
+        // load filterPositions into registers for next iteration
+
+        hscale_iter     v0, v1, v28, v20, v21
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        hscale_iter     v2, v3, v29, v22, v23
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        hscale_iter     v4, v5, v30, v24, v25
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        hscale_iter     v6, v7, v31, v26, v27
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        subs            w2, w2, #8
+        add             x5, x5, #32
+
+        ldp             q28, q29, [x4], #32 // filter[0..7]
+        lsl             x8, x8, #1
+        lsl             x9, x9, #1
+        lsl             x10, x10, #1
+        lsl             x11, x11, #1
+        ldp             q30, q31, [x4], #32 // filter[0..7]
+        lsl             x12, x12, #1
+        lsl             x13, x13, #1
+        lsl             x14, x14, #1
+        lsl             x15, x15, #1
+
+        addp            v20.4s, v20.4s, v21.4s
+        ldr             d0, [x3, w8,  uxtw]
+        addp            v22.4s, v22.4s, v23.4s
+        ldr             d1, [x3, w9,  uxtw]
+        addp            v24.4s, v24.4s, v25.4s
+        ldr             d2, [x3, w10, uxtw]
+        addp            v26.4s, v26.4s, v27.4s
+        ldr             d3, [x3, w11, uxtw]
+        addp            v20.4s, v20.4s, v22.4s
+        ldr             d4, [x3, w12, uxtw]
+        addp            v21.4s, v24.4s, v26.4s
+        ldr             d5, [x3, w13, uxtw]
+        cmp             w2, #16
+
+        sshl            v20.4s, v20.4s, v17.4s
+        ldr             d6, [x3, w14, uxtw]
+        sshl            v21.4s, v21.4s, v17.4s
+        ldr             d7, [x3, w15, uxtw]
+        smin            v20.4s, v20.4s, v18.4s
+        smin            v21.4s, v21.4s, v18.4s
+        xtn             v20.4h, v20.4s
+        xtn2            v20.8h, v21.4s
+
+        st1             {v20.8h}, [x1], #16
+
+        b.ge            1b
+
+        // here we make last iteration, without updating the registers
+
+        hscale_iter     v0, v1, v28, v20, v21
+        hscale_iter     v2, v3, v29, v22, v23
+        hscale_iter     v4, v5, v30, v24, v25
+        hscale_iter     v6, v7, v31, v26, v27
+        subs            w2, w2, #8
+
+        addp            v20.4s, v20.4s, v21.4s
+        addp            v22.4s, v22.4s, v23.4s
+        addp            v24.4s, v24.4s, v25.4s
+        addp            v26.4s, v26.4s, v27.4s
+        addp            v0.4s, v20.4s, v22.4s
+        addp            v1.4s, v24.4s, v26.4s
+
+        sshl            v0.4s, v0.4s, v17.4s
+        sshl            v1.4s, v1.4s, v17.4s
+        smin            v0.4s, v0.4s, v18.4s
+        smin            v1.4s, v1.4s, v18.4s
+        xtn             v0.4h, v0.4s
+        xtn2            v0.8h, v1.4s
+
+        st1             {v0.8h}, [x1], #16
+        cbnz            w2, 2f
+
+        ret
+
+2:
+        ldr             w8, [x5], #4                // load filterPos
+        add             x9, x3, w8, uxtw #1         // src + filterPos
+        ld1             {v0.4h}, [x9]               // load 4 * uint16_t
+        ld1             {v31.4h}, [x4], #8
+        sub             w2, w2, #1
+
+        uxtl            v0.4s, v0.4h
+        sxtl            v31.4s, v31.4h
+        mul             v5.4s, v0.4s, v31.4s
+        addv            s0, v5.4s
+        sshl            v0.4s, v0.4s, v17.4s
+        smin            v0.4s, v0.4s, v18.4s
+        st1             {v0.h}[0], [x1], #2
+        cbnz            w2, 2b                      // if iterations remain jump to beginning
+
+        ret
+endfunc
+
+function ff_hscale16to15_X8_neon_asm, export=1
+        // w0               int shift
+        // x1               int32_t *dst
+        // w2               int dstW
+        // x3               const uint8_t *src // treat it as uint16_t *src
+        // x4               const uint16_t *filter
+        // x5               const int32_t *filterPos
+        // w6               int filterSize
+
+        movi            v20.4s, #1
+        movi            v21.4s, #1
+        shl             v20.4s, v20.4s, #15
+        sub             v20.4s, v20.4s, v21.4s
+        dup             v21.4s, w0
+        neg             v21.4s, v21.4s
+
+        sbfiz           x7, x6, #1, #32             // filterSize*2 (*2 because int16)
+1:      ldr             w8, [x5], #4                // filterPos[idx]
+        lsl             w8, w8, #1
+        ldr             w10, [x5], #4               // filterPos[idx + 1]
+        lsl             w10, w10, #1
+        ldr             w11, [x5], #4               // filterPos[idx + 2]
+        lsl             w11, w11, #1
+        ldr             w9, [x5], #4                // filterPos[idx + 3]
+        lsl             w9, w9, #1
+        mov             x16, x4                     // filter0 = filter
+        add             x12, x16, x7                // filter1 = filter0 + filterSize*2
+        add             x13, x12, x7                // filter2 = filter1 + filterSize*2
+        add             x4, x13, x7                 // filter3 = filter2 + filterSize*2
+        movi            v0.16b, #0                  // val sum part 1 (for dst[0])
+        movi            v1.16b, #0                  // val sum part 2 (for dst[1])
+        movi            v2.16b, #0                  // val sum part 3 (for dst[2])
+        movi            v3.16b, #0                  // val sum part 4 (for dst[3])
+        add             x17, x3, w8, uxtw           // srcp + filterPos[0]
+        add             x8,  x3, w10, uxtw          // srcp + filterPos[1]
+        add             x10, x3, w11, uxtw          // srcp + filterPos[2]
+        add             x11, x3, w9, uxtw           // srcp + filterPos[3]
+        mov             w15, w6                     // filterSize counter
+2:      ld1             {v4.8h}, [x17], #16         // srcp[filterPos[0] + {0..7}]
+        ld1             {v5.8h}, [x16], #16         // load 8x16-bit filter values, part 1
+        ld1             {v6.8h}, [x8], #16          // srcp[filterPos[1] + {0..7}]
+        ld1             {v7.8h}, [x12], #16         // load 8x16-bit at filter+filterSize
+        uxtl            v24.4s, v4.4h               // extend srcp lower half to 32 bits to preserve sign
+        sxtl            v25.4s, v5.4h               // extend filter lower half to 32 bits to match srcp size
+        uxtl2           v4.4s, v4.8h                // extend srcp upper half to 32 bits
+        mla             v0.4s, v24.4s, v25.4s       // multiply accumulate lower half of v4 * v5
+        sxtl2           v5.4s, v5.8h                // extend filter upper half to 32 bits
+        uxtl            v26.4s, v6.4h               // extend srcp lower half to 32 bits
+        mla             v0.4s, v4.4s, v5.4s         // multiply accumulate upper half of v4 * v5
+        sxtl            v27.4s, v7.4h               // extend filter lower half
+        uxtl2           v6.4s, v6.8h                // extend srcp upper half
+        sxtl2           v7.4s, v7.8h                // extend filter upper half
+        ld1             {v16.8h}, [x10], #16        // srcp[filterPos[2] + {0..7}]
+        mla             v1.4s, v26.4s, v27.4s       // v1 accumulates srcp[filterPos[1] + {0..3}] * filter[{0..3}]
+        ld1             {v17.8h}, [x13], #16        // load 8x16-bit at filter+2*filterSize
+        uxtl            v22.4s, v16.4h              // extend srcp lower half
+        sxtl            v23.4s, v17.4h              // extend filter lower half
+        uxtl2           v16.4s, v16.8h              // extend srcp upper half
+        sxtl2           v17.4s, v17.8h              // extend filter upper half
+        mla             v2.4s, v22.4s, v23.4s       // v2 accumulates srcp[filterPos[2] + {0..3}] * filter[{0..3}]
+        mla             v2.4s, v16.4s, v17.4s       // v2 accumulates srcp[filterPos[2] + {4..7}] * filter[{4..7}]
+        ld1             {v18.8h}, [x11], #16        // srcp[filterPos[3] + {0..7}]
+        mla             v1.4s, v6.4s, v7.4s         // v1 accumulates srcp[filterPos[1] + {4..7}] * filter[{4..7}]
+        ld1             {v19.8h}, [x4], #16         // load 8x16-bit at filter+3*filterSize
+        subs            w15, w15, #8                // j -= 8: processed 8/filterSize
+        uxtl            v28.4s, v18.4h              // extend srcp lower half
+        sxtl            v29.4s, v19.4h              // extend filter lower half
+        uxtl2           v18.4s, v18.8h              // extend srcp upper half
+        sxtl2           v19.4s, v19.8h              // extend filter upper half
+        mla             v3.4s, v28.4s, v29.4s       // v3 accumulates srcp[filterPos[3] + {0..3}] * filter[{0..3}]
+        mla             v3.4s, v18.4s, v19.4s       // v3 accumulates srcp[filterPos[3] + {4..7}] * filter[{4..7}]
+        b.gt            2b                          // inner loop if filterSize not consumed completely
+        addp            v0.4s, v0.4s, v1.4s         // part01 horizontal pair adding
+        addp            v2.4s, v2.4s, v3.4s         // part23 horizontal pair adding
+        addp            v0.4s, v0.4s, v2.4s         // part0123 horizontal pair adding
+        subs            w2, w2, #4                  // dstW -= 4
+        sshl            v0.4s, v0.4s, v21.4s        // shift right (effectively right, as shift is negative); overflow expected
+        smin            v0.4s, v0.4s, v20.4s        // apply min (do not use sqshl)
+        xtn             v0.4h, v0.4s                // narrow down to 16 bits
+
+        st1             {v0.4h}, [x1], #8           // write to destination part0123
+        b.gt            1b                          // loop until end of line
+        ret
+endfunc
+
+function ff_hscale16to15_X4_neon_asm, export=1
+        // w0  int shift
+        // x1  int16_t *dst
+        // w2  int dstW
+        // x3  const uint8_t *src
+        // x4  const int16_t *filter
+        // x5  const int32_t *filterPos
+        // w6  int filterSize
+
+        stp             d8, d9, [sp, #-0x20]!
+        stp             d10, d11, [sp, #0x10]
+
+        movi            v18.4s, #1
+        movi            v17.4s, #1
+        shl             v18.4s, v18.4s, #15
+        sub             v21.4s, v18.4s, v17.4s      // max allowed value
+        dup             v17.4s, w0                  // read shift
+        neg             v20.4s, v17.4s              // negate it, so it can be used in sshl (effectively shift right)
+
+        lsl             w7, w6, #1
+1:
+        ldp             w8, w9, [x5]
+        ldp             w10, w11, [x5, #8]
+
+        movi            v16.16b, #0                 // initialize accumulator for idx + 0
+        movi            v17.16b, #0                 // initialize accumulator for idx + 1
+        movi            v18.16b, #0                 // initialize accumulator for idx + 2
+        movi            v19.16b, #0                 // initialize accumulator for idx + 3
+
+        mov             x12, x4                     // filter + 0
+        add             x13, x4, x7                 // filter + 1
+        add             x8, x3, x8, lsl #1          // srcp + filterPos 0
+        add             x14, x13, x7                // filter + 2
+        add             x9, x3, x9, lsl #1          // srcp + filterPos 1
+        add             x15, x14, x7                // filter + 3
+        add             x10, x3, x10, lsl #1        // srcp + filterPos 2
+        mov             w0, w6                      // save the filterSize to temporary variable
+        add             x11, x3, x11, lsl #1        // srcp + filterPos 3
+        add             x5, x5, #16                 // advance filter position
+        mov             x16, xzr                    // clear the register x16 used for offsetting the filter values
+
+2:
+        ldr             q4, [x8], #16               // load src values for idx 0
+        ldr             q5, [x9], #16               // load src values for idx 1
+        uxtl            v26.4s, v4.4h
+        uxtl2           v4.4s, v4.8h
+        ldr             q31, [x12, x16]             // load filter values for idx 0
+        ldr             q6, [x10], #16              // load src values for idx 2
+        sxtl            v22.4s, v31.4h
+        sxtl2           v31.4s, v31.8h
+        mla             v16.4s, v26.4s, v22.4s      // multiplication of lower half for idx 0
+        uxtl            v25.4s, v5.4h
+        uxtl2           v5.4s, v5.8h
+        ldr             q30, [x13, x16]             // load filter values for idx 1
+        ldr             q7, [x11], #16              // load src values for idx 3
+        mla             v16.4s, v4.4s, v31.4s       // multiplication of upper half for idx 0
+        uxtl            v24.4s, v6.4h
+        sxtl            v8.4s, v30.4h
+        sxtl2           v30.4s, v30.8h
+        mla             v17.4s, v25.4s, v8.4s       // multiplication of lower half for idx 1
+        ldr             q29, [x14, x16]             // load filter values for idx 2
+        uxtl2           v6.4s, v6.8h
+        sxtl            v9.4s, v29.4h
+        sxtl2           v29.4s, v29.8h
+        mla             v17.4s, v5.4s, v30.4s       // multiplication of upper half for idx 1
+        mla             v18.4s, v24.4s, v9.4s       // multiplication of lower half for idx 2
+        ldr             q28, [x15, x16]             // load filter values for idx 3
+        uxtl            v23.4s, v7.4h
+        sxtl            v10.4s, v28.4h
+        mla             v18.4s, v6.4s, v29.4s       // multiplication of upper half for idx 2
+        uxtl2           v7.4s, v7.8h
+        sxtl2           v28.4s, v28.8h
+        mla             v19.4s, v23.4s, v10.4s      // multiplication of lower half for idx 3
+        sub             w0, w0, #8
+        cmp             w0, #8
+        mla             v19.4s, v7.4s, v28.4s       // multiplication of upper half for idx 3
+
+        add             x16, x16, #16               // advance filter values indexing
+
+        b.ge            2b
+
+        // 4 iterations left
+
+        sub             x17, x7, #8                 // step back to wrap up the filter pos for last 4 elements
+
+        ldr             d4, [x8]                    // load src values for idx 0
+        ldr             d31, [x12, x17]             // load filter values for idx 0
+        uxtl            v4.4s, v4.4h
+        sxtl            v31.4s, v31.4h
+        ldr             d5, [x9]                    // load src values for idx 1
+        mla             v16.4s, v4.4s, v31.4s       // multiplication of upper half for idx 0
+        ldr             d30, [x13, x17]             // load filter values for idx 1
+        uxtl            v5.4s, v5.4h
+        sxtl            v30.4s, v30.4h
+        ldr             d6, [x10]                   // load src values for idx 2
+        mla             v17.4s, v5.4s, v30.4s       // multiplication of upper half for idx 1
+        ldr             d29, [x14, x17]             // load filter values for idx 2
+        uxtl            v6.4s, v6.4h
+        sxtl            v29.4s, v29.4h
+        ldr             d7, [x11]                   // load src values for idx 3
+        ldr             d28, [x15, x17]             // load filter values for idx 3
+        mla             v18.4s, v6.4s, v29.4s       // multiplication of upper half for idx 2
+        uxtl            v7.4s, v7.4h
+        sxtl            v28.4s, v28.4h
+        addp            v16.4s, v16.4s, v17.4s
+        mla             v19.4s, v7.4s, v28.4s       // multiplication of upper half for idx 3
+        subs            w2, w2, #4
+        addp            v18.4s, v18.4s, v19.4s
+        addp            v16.4s, v16.4s, v18.4s
+        sshl            v16.4s, v16.4s, v20.4s
+        smin            v16.4s, v16.4s, v21.4s
+        xtn             v16.4h, v16.4s
+
+        st1             {v16.4h}, [x1], #8
+        add             x4, x4, x7, lsl #2
+        b.gt            1b
+
+        ldp             d8, d9, [sp]
+        ldp             d10, d11, [sp, #0x10]
+
+        add             sp, sp, #0x20
+
+        ret
+endfunc
+
+function ff_hscale16to19_4_neon_asm, export=1
+        // w0               int shift
+        // x1               int32_t *dst
+        // w2               int dstW
+        // x3               const uint8_t *src // treat it as uint16_t *src
+        // x4               const uint16_t *filter
+        // x5               const int32_t *filterPos
+        // w6               int filterSize
+
+        movi            v18.4s, #1
+        movi            v17.4s, #1
+        shl             v18.4s, v18.4s, #19
+        sub             v18.4s, v18.4s, v17.4s      // max allowed value
+        dup             v17.4s, w0                  // read shift
+        neg             v17.4s, v17.4s              // negate it, so it can be used in sshl (effectively shift right)
+
+        cmp             w2, #16
+        b.lt            2f // move to last block
+
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        add             x5, x5, #32
+
+        // shift all filterPos left by one, as uint16_t will be read
+        lsl             x8, x8, #1
+        lsl             x9, x9, #1
+        lsl             x10, x10, #1
+        lsl             x11, x11, #1
+        lsl             x12, x12, #1
+        lsl             x13, x13, #1
+        lsl             x14, x14, #1
+        lsl             x15, x15, #1
+
+        // load src with given offset
+        ldr             x8,  [x3, w8,  uxtw]
+        ldr             x9,  [x3, w9,  uxtw]
+        ldr             x10, [x3, w10, uxtw]
+        ldr             x11, [x3, w11, uxtw]
+        ldr             x12, [x3, w12, uxtw]
+        ldr             x13, [x3, w13, uxtw]
+        ldr             x14, [x3, w14, uxtw]
+        ldr             x15, [x3, w15, uxtw]
+
+        sub             sp, sp, #64
+        // push src on stack so it can be loaded into vectors later
+        stp             x8, x9, [sp]
+        stp             x10, x11, [sp, #16]
+        stp             x12, x13, [sp, #32]
+        stp             x14, x15, [sp, #48]
+
+1:
+        ld4             {v0.8h, v1.8h, v2.8h, v3.8h}, [sp]
+        ld4             {v28.8h, v29.8h, v30.8h, v31.8h}, [x4], #64 // filter[0..7]
+
+        // Each of blocks does the following:
+        // Extend src and filter to 32 bits with uxtl and sxtl
+        // multiply or multiply and accumulate results
+        // Extending to 32 bits is necessary, as unit16_t values can't
+        // be represented as int16_t without type promotion.
+        uxtl            v26.4s, v0.4h
+        sxtl            v27.4s, v28.4h
+        uxtl2           v0.4s, v0.8h
+        mul             v5.4s, v26.4s, v27.4s
+        sxtl2           v28.4s, v28.8h
+        uxtl            v26.4s, v1.4h
+        mul             v6.4s, v0.4s, v28.4s
+
+        sxtl            v27.4s, v29.4h
+        uxtl2           v0.4s, v1.8h
+        mla             v5.4s, v27.4s, v26.4s
+        sxtl2           v28.4s, v29.8h
+        uxtl            v26.4s, v2.4h
+        mla             v6.4s, v28.4s, v0.4s
+
+        sxtl            v27.4s, v30.4h
+        uxtl2           v0.4s, v2.8h
+        mla             v5.4s, v27.4s, v26.4s
+        sxtl2           v28.4s, v30.8h
+        uxtl            v26.4s, v3.4h
+        mla             v6.4s, v28.4s, v0.4s
+
+        sxtl            v27.4s, v31.4h
+        uxtl2           v0.4s, v3.8h
+        mla             v5.4s, v27.4s, v26.4s
+        sxtl2           v28.4s, v31.8h
+        sub             w2, w2, #8
+        mla             v6.4s, v28.4s, v0.4s
+
+        sshl            v5.4s, v5.4s, v17.4s
+        sshl            v6.4s, v6.4s, v17.4s
+        smin            v5.4s, v5.4s, v18.4s
+        smin            v6.4s, v6.4s, v18.4s
+
+        st1             {v5.4s, v6.4s}, [x1], #32
+        cmp             w2, #16
+
+        // load filterPositions into registers for next iteration
+        ldp             w8, w9, [x5]                // filterPos[0], filterPos[1]
+        ldp             w10, w11, [x5, #8]          // filterPos[2], filterPos[3]
+        ldp             w12, w13, [x5, #16]         // filterPos[4], filterPos[5]
+        ldp             w14, w15, [x5, #24]         // filterPos[6], filterPos[7]
+        add             x5, x5, #32
+
+        lsl             x8, x8, #1
+        lsl             x9, x9, #1
+        lsl             x10, x10, #1
+        lsl             x11, x11, #1
+        lsl             x12, x12, #1
+        lsl             x13, x13, #1
+        lsl             x14, x14, #1
+        lsl             x15, x15, #1
+
+        ldr             x8,  [x3, w8,  uxtw]
+        ldr             x9,  [x3, w9,  uxtw]
+        ldr             x10, [x3, w10, uxtw]
+        ldr             x11, [x3, w11, uxtw]
+        ldr             x12, [x3, w12, uxtw]
+        ldr             x13, [x3, w13, uxtw]
+        ldr             x14, [x3, w14, uxtw]
+        ldr             x15, [x3, w15, uxtw]
+
+        stp             x8, x9, [sp]
+        stp             x10, x11, [sp, #16]
+        stp             x12, x13, [sp, #32]
+        stp             x14, x15, [sp, #48]
+
+        b.ge            1b
+
+        // here we make last iteration, without updating the registers
+        ld4             {v0.8h, v1.8h, v2.8h, v3.8h}, [sp]
+        ld4             {v28.8h, v29.8h, v30.8h, v31.8h}, [x4], #64
+
+        uxtl            v26.4s, v0.4h
+        sxtl            v27.4s, v28.4h
+        uxtl2           v0.4s, v0.8h
+        mul             v5.4s, v26.4s, v27.4s
+        sxtl2           v28.4s, v28.8h
+        uxtl            v26.4s, v1.4h
+        mul             v6.4s, v0.4s, v28.4s
+
+        sxtl            v27.4s, v29.4h
+        uxtl2           v0.4s, v1.8h
+        mla             v5.4s, v26.4s, v27.4s
+        sxtl2           v28.4s, v29.8h
+        uxtl            v26.4s, v2.4h
+        mla             v6.4s, v0.4s, v28.4s
+
+        sxtl            v27.4s, v30.4h
+        uxtl2           v0.4s, v2.8h
+        mla             v5.4s, v26.4s, v27.4s
+        sxtl2           v28.4s, v30.8h
+        uxtl            v26.4s, v3.4h
+        mla             v6.4s, v0.4s, v28.4s
+
+        sxtl            v27.4s, v31.4h
+        uxtl2           v0.4s, v3.8h
+        mla             v5.4s, v26.4s, v27.4s
+        sxtl2           v28.4s, v31.8h
+        subs            w2, w2, #8
+        mla             v6.4s, v0.4s, v28.4s
+
+        sshl            v5.4s, v5.4s, v17.4s
+        sshl            v6.4s, v6.4s, v17.4s
+
+        smin            v5.4s, v5.4s, v18.4s
+        smin            v6.4s, v6.4s, v18.4s
+
+        st1             {v5.4s, v6.4s}, [x1], #32
+        add             sp, sp, #64                 // restore stack
+        cbnz            w2, 2f
+
+        ret
+
+2:
+        ldr             w8, [x5], #4                // load filterPos
+        lsl             w8, w8, #1
+        add             x9, x3, w8, uxtw            // src + filterPos
+        ld1             {v0.4h}, [x9]               // load 4 * uint16_t
+        ld1             {v31.4h}, [x4], #8
+
+        uxtl            v0.4s, v0.4h
+        sxtl            v31.4s, v31.4h
+        subs            w2, w2, #1
+        mul             v5.4s, v0.4s, v31.4s
+        addv            s0, v5.4s
+        sshl            v0.4s, v0.4s, v17.4s
+        smin            v0.4s, v0.4s, v18.4s
+        st1             {v0.s}[0], [x1], #4
+        cbnz            w2, 2b                      // if iterations remain jump to beginning
+
+        ret
+endfunc
+
+function ff_hscale16to19_X8_neon_asm, export=1
+        // w0               int shift
+        // x1               int32_t *dst
+        // w2               int dstW
+        // x3               const uint8_t *src // treat it as uint16_t *src
+        // x4               const uint16_t *filter
+        // x5               const int32_t *filterPos
+        // w6               int filterSize
+
+        movi            v20.4s, #1
+        movi            v21.4s, #1
+        shl             v20.4s, v20.4s, #19
+        sub             v20.4s, v20.4s, v21.4s
+        dup             v21.4s, w0
+        neg             v21.4s, v21.4s
+
+        sbfiz           x7, x6, #1, #32             // filterSize*2 (*2 because int16)
+1:      ldr             w8, [x5], #4                // filterPos[idx]
+        ldr             w10, [x5], #4               // filterPos[idx + 1]
+        lsl             w8, w8, #1
+        ldr             w11, [x5], #4               // filterPos[idx + 2]
+        ldr             w9, [x5], #4                // filterPos[idx + 3]
+        mov             x16, x4                     // filter0 = filter
+        lsl             w11, w11, #1
+        add             x12, x16, x7                // filter1 = filter0 + filterSize*2
+        lsl             w9, w9, #1
+        add             x13, x12, x7                // filter2 = filter1 + filterSize*2
+        lsl             w10, w10, #1
+        add             x4, x13, x7                 // filter3 = filter2 + filterSize*2
+        movi            v0.16b, #0                  // val sum part 1 (for dst[0])
+        movi            v1.16b, #0                  // val sum part 2 (for dst[1])
+        movi            v2.16b, #0                  // val sum part 3 (for dst[2])
+        movi            v3.16b, #0                  // val sum part 4 (for dst[3])
+        add             x17, x3, w8, uxtw           // srcp + filterPos[0]
+        add             x8,  x3, w10, uxtw          // srcp + filterPos[1]
+        add             x10, x3, w11, uxtw          // srcp + filterPos[2]
+        add             x11, x3, w9, uxtw           // srcp + filterPos[3]
+        mov             w15, w6                     // filterSize counter
+2:      ld1             {v4.8h}, [x17], #16         // srcp[filterPos[0] + {0..7}]
+        ld1             {v5.8h}, [x16], #16         // load 8x16-bit filter values, part 1
+        ld1             {v6.8h}, [x8], #16          // srcp[filterPos[1] + {0..7}]
+        ld1             {v7.8h}, [x12], #16         // load 8x16-bit at filter+filterSize
+        uxtl            v24.4s, v4.4h               // extend srcp lower half to 32 bits to preserve sign
+        sxtl            v25.4s, v5.4h               // extend filter lower half to 32 bits to match srcp size
+        uxtl2           v4.4s, v4.8h                // extend srcp upper half to 32 bits
+        mla             v0.4s, v24.4s, v25.4s       // multiply accumulate lower half of v4 * v5
+        sxtl2           v5.4s, v5.8h                // extend filter upper half to 32 bits
+        uxtl            v26.4s, v6.4h               // extend srcp lower half to 32 bits
+        mla             v0.4s, v4.4s, v5.4s         // multiply accumulate upper half of v4 * v5
+        sxtl            v27.4s, v7.4h               // extend filter lower half
+        uxtl2           v6.4s, v6.8h                // extend srcp upper half
+        sxtl2           v7.4s, v7.8h                // extend filter upper half
+        ld1             {v16.8h}, [x10], #16        // srcp[filterPos[2] + {0..7}]
+        mla             v1.4s, v26.4s, v27.4s       // v1 accumulates srcp[filterPos[1] + {0..3}] * filter[{0..3}]
+        ld1             {v17.8h}, [x13], #16        // load 8x16-bit at filter+2*filterSize
+        uxtl            v22.4s, v16.4h              // extend srcp lower half
+        sxtl            v23.4s, v17.4h              // extend filter lower half
+        uxtl2           v16.4s, v16.8h              // extend srcp upper half
+        sxtl2           v17.4s, v17.8h              // extend filter upper half
+        mla             v2.4s, v22.4s, v23.4s       // v2 accumulates srcp[filterPos[2] + {0..3}] * filter[{0..3}]
+        mla             v2.4s, v16.4s, v17.4s       // v2 accumulates srcp[filterPos[2] + {4..7}] * filter[{4..7}]
+        ld1             {v18.8h}, [x11], #16        // srcp[filterPos[3] + {0..7}]
+        mla             v1.4s, v6.4s, v7.4s         // v1 accumulates srcp[filterPos[1] + {4..7}] * filter[{4..7}]
+        ld1             {v19.8h}, [x4], #16         // load 8x16-bit at filter+3*filterSize
+        subs            w15, w15, #8                // j -= 8: processed 8/filterSize
+        uxtl            v28.4s, v18.4h              // extend srcp lower half
+        sxtl            v29.4s, v19.4h              // extend filter lower half
+        uxtl2           v18.4s, v18.8h              // extend srcp upper half
+        sxtl2           v19.4s, v19.8h              // extend filter upper half
+        mla             v3.4s, v28.4s, v29.4s       // v3 accumulates srcp[filterPos[3] + {0..3}] * filter[{0..3}]
+        mla             v3.4s, v18.4s, v19.4s       // v3 accumulates srcp[filterPos[3] + {4..7}] * filter[{4..7}]
+        b.gt            2b                          // inner loop if filterSize not consumed completely
+        addp            v0.4s, v0.4s, v1.4s         // part01 horizontal pair adding
+        addp            v2.4s, v2.4s, v3.4s         // part23 horizontal pair adding
+        addp            v0.4s, v0.4s, v2.4s         // part0123 horizontal pair adding
+        subs            w2, w2, #4                  // dstW -= 4
+        sshl            v0.4s, v0.4s, v21.4s        // shift right (effectively right, as shift is negative); overflow expected
+        smin            v0.4s, v0.4s, v20.4s        // apply min (do not use sqshl)
+        st1             {v0.4s}, [x1], #16          // write to destination part0123
+        b.gt            1b                          // loop until end of line
+        ret
+endfunc
+
+function ff_hscale16to19_X4_neon_asm, export=1
+        // w0  int shift
+        // x1  int16_t *dst
+        // w2  int dstW
+        // x3  const uint8_t *src
+        // x4  const int16_t *filter
+        // x5  const int32_t *filterPos
+        // w6  int filterSize
+
+        stp             d8, d9, [sp, #-0x20]!
+        stp             d10, d11, [sp, #0x10]
+
+        movi            v18.4s, #1
+        movi            v17.4s, #1
+        shl             v18.4s, v18.4s, #19
+        sub             v21.4s, v18.4s, v17.4s      // max allowed value
+        dup             v17.4s, w0                  // read shift
+        neg             v20.4s, v17.4s              // negate it, so it can be used in sshl (effectively shift right)
+
+        lsl             w7, w6, #1
+1:
+        ldp             w8, w9, [x5]
+        ldp             w10, w11, [x5, #8]
+
+        movi            v16.16b, #0                 // initialize accumulator for idx + 0
+        movi            v17.16b, #0                 // initialize accumulator for idx + 1
+        movi            v18.16b, #0                 // initialize accumulator for idx + 2
+        movi            v19.16b, #0                 // initialize accumulator for idx + 3
+
+        mov             x12, x4                     // filter + 0
+        add             x13, x4, x7                 // filter + 1
+        add             x8, x3, x8, lsl #1          // srcp + filterPos 0
+        add             x14, x13, x7                // filter + 2
+        add             x9, x3, x9, lsl #1          // srcp + filterPos 1
+        add             x15, x14, x7                // filter + 3
+        add             x10, x3, x10, lsl #1        // srcp + filterPos 2
+        mov             w0, w6                      // save the filterSize to temporary variable
+        add             x11, x3, x11, lsl #1        // srcp + filterPos 3
+        add             x5, x5, #16                 // advance filter position
+        mov             x16, xzr                    // clear the register x16 used for offsetting the filter values
+
+2:
+        ldr             q4, [x8], #16               // load src values for idx 0
+        ldr             q5, [x9], #16               // load src values for idx 1
+        uxtl            v26.4s, v4.4h
+        uxtl2           v4.4s, v4.8h
+        ldr             q31, [x12, x16]             // load filter values for idx 0
+        ldr             q6, [x10], #16              // load src values for idx 2
+        sxtl            v22.4s, v31.4h
+        sxtl2           v31.4s, v31.8h
+        mla             v16.4s, v26.4s, v22.4s      // multiplication of lower half for idx 0
+        uxtl            v25.4s, v5.4h
+        uxtl2           v5.4s, v5.8h
+        ldr             q30, [x13, x16]             // load filter values for idx 1
+        ldr             q7, [x11], #16              // load src values for idx 3
+        mla             v16.4s, v4.4s, v31.4s       // multiplication of upper half for idx 0
+        uxtl            v24.4s, v6.4h
+        sxtl            v8.4s, v30.4h
+        sxtl2           v30.4s, v30.8h
+        mla             v17.4s, v25.4s, v8.4s       // multiplication of lower half for idx 1
+        ldr             q29, [x14, x16]             // load filter values for idx 2
+        uxtl2           v6.4s, v6.8h
+        sxtl            v9.4s, v29.4h
+        sxtl2           v29.4s, v29.8h
+        mla             v17.4s, v5.4s, v30.4s       // multiplication of upper half for idx 1
+        ldr             q28, [x15, x16]             // load filter values for idx 3
+        mla             v18.4s, v24.4s, v9.4s       // multiplication of lower half for idx 2
+        uxtl            v23.4s, v7.4h
+        sxtl            v10.4s, v28.4h
+        mla             v18.4s, v6.4s, v29.4s       // multiplication of upper half for idx 2
+        uxtl2           v7.4s, v7.8h
+        sxtl2           v28.4s, v28.8h
+        mla             v19.4s, v23.4s, v10.4s      // multiplication of lower half for idx 3
+        sub             w0, w0, #8
+        cmp             w0, #8
+        mla             v19.4s, v7.4s, v28.4s       // multiplication of upper half for idx 3
+
+        add             x16, x16, #16               // advance filter values indexing
+
+        b.ge            2b
+
+        // 4 iterations left
+
+        sub             x17, x7, #8                 // step back to wrap up the filter pos for last 4 elements
+
+        ldr             d4, [x8]                    // load src values for idx 0
+        ldr             d31, [x12, x17]             // load filter values for idx 0
+        uxtl            v4.4s, v4.4h
+        sxtl            v31.4s, v31.4h
+        ldr             d5, [x9]                    // load src values for idx 1
+        mla             v16.4s, v4.4s, v31.4s       // multiplication of upper half for idx 0
+        ldr             d30, [x13, x17]             // load filter values for idx 1
+        uxtl            v5.4s, v5.4h
+        sxtl            v30.4s, v30.4h
+        ldr             d6, [x10]                   // load src values for idx 2
+        mla             v17.4s, v5.4s, v30.4s       // multiplication of upper half for idx 1
+        ldr             d29, [x14, x17]             // load filter values for idx 2
+        uxtl            v6.4s, v6.4h
+        sxtl            v29.4s, v29.4h
+        ldr             d7, [x11]                   // load src values for idx 3
+        ldr             d28, [x15, x17]             // load filter values for idx 3
+        mla             v18.4s, v6.4s, v29.4s       // multiplication of upper half for idx 2
+        uxtl            v7.4s, v7.4h
+        sxtl            v28.4s, v28.4h
+        addp            v16.4s, v16.4s, v17.4s
+        mla             v19.4s, v7.4s, v28.4s       // multiplication of upper half for idx 3
+        subs            w2, w2, #4
+        addp            v18.4s, v18.4s, v19.4s
+        addp            v16.4s, v16.4s, v18.4s
+        sshl            v16.4s, v16.4s, v20.4s
+        smin            v16.4s, v16.4s, v21.4s
+
+        st1             {v16.4s}, [x1], #16
+        add             x4, x4, x7, lsl #2
+        b.gt            1b
+
+        ldp             d8, d9, [sp]
+        ldp             d10, d11, [sp, #0x10]
+
+        add             sp, sp, #0x20
+
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswscale/aarch64/input.S b/libs/ffmpeg/libswscale/aarch64/input.S
new file mode 100644
index 000000000000..c1c0adffc83a
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/input.S
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2024 Zhao Zhili <quinkblack@foxmail.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/aarch64/asm.S"
+
+.macro rgb_to_yuv_load_rgb src, element=3
+    .if \element == 3
+        ld3             { v16.16b, v17.16b, v18.16b }, [\src]
+    .else
+        ld4             { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
+    .endif
+        uxtl            v19.8h, v16.8b             // v19: r
+        uxtl            v20.8h, v17.8b             // v20: g
+        uxtl            v21.8h, v18.8b             // v21: b
+        uxtl2           v22.8h, v16.16b            // v22: r
+        uxtl2           v23.8h, v17.16b            // v23: g
+        uxtl2           v24.8h, v18.16b            // v24: b
+.endm
+
+.macro argb_to_yuv_load_rgb src
+        ld4             { v16.16b, v17.16b, v18.16b, v19.16b }, [\src]
+        uxtl            v21.8h, v19.8b             // v21: b
+        uxtl2           v24.8h, v19.16b            // v24: b
+        uxtl            v19.8h, v17.8b             // v19: r
+        uxtl            v20.8h, v18.8b             // v20: g
+        uxtl2           v22.8h, v17.16b            // v22: r
+        uxtl2           v23.8h, v18.16b            // v23: g
+.endm
+
+.macro rgb_to_yuv_product r, g, b, dst1, dst2, dst, coef0, coef1, coef2, right_shift
+        mov             \dst1\().16b, v6.16b                    // dst1 = const_offset
+        mov             \dst2\().16b, v6.16b                    // dst2 = const_offset
+        smlal           \dst1\().4s, \coef0\().4h, \r\().4h     // dst1 += rx * r
+        smlal           \dst1\().4s, \coef1\().4h, \g\().4h     // dst1 += gx * g
+        smlal           \dst1\().4s, \coef2\().4h, \b\().4h     // dst1 += bx * b
+        smlal2          \dst2\().4s, \coef0\().8h, \r\().8h     // dst2 += rx * r
+        smlal2          \dst2\().4s, \coef1\().8h, \g\().8h     // dst2 += gx * g
+        smlal2          \dst2\().4s, \coef2\().8h, \b\().8h     // dst2 += bx * b
+        sqshrn          \dst\().4h, \dst1\().4s, \right_shift   // dst_lower_half = dst1 >> right_shift
+        sqshrn2         \dst\().8h, \dst2\().4s, \right_shift   // dst_higher_half = dst2 >> right_shift
+.endm
+
+.macro rgbToY_neon fmt_bgr, fmt_rgb, element, alpha_first=0
+function ff_\fmt_bgr\()ToY_neon, export=1
+        cmp             w4, #0                  // check width > 0
+        ldp             w12, w11, [x5]          // w12: ry, w11: gy
+        ldr             w10, [x5, #8]           // w10: by
+        b.gt            4f
+        ret
+endfunc
+
+function ff_\fmt_rgb\()ToY_neon, export=1
+        cmp             w4, #0                  // check width > 0
+        ldp             w10, w11, [x5]          // w10: ry, w11: gy
+        ldr             w12, [x5, #8]           // w12: by
+        b.le            3f
+4:
+        mov             w9, #256                // w9 = 1 << (RGB2YUV_SHIFT - 7)
+        movk            w9, #8, lsl #16         // w9 += 32 << (RGB2YUV_SHIFT - 1)
+        dup             v6.4s, w9               // w9: const_offset
+
+        cmp             w4, #16
+        dup             v0.8h, w10
+        dup             v1.8h, w11
+        dup             v2.8h, w12
+        b.lt            2f
+1:
+    .if \alpha_first
+        argb_to_yuv_load_rgb x1
+    .else
+        rgb_to_yuv_load_rgb x1, \element
+    .endif
+        rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
+        rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
+        sub             w4, w4, #16             // width -= 16
+        add             x1, x1, #(16*\element)
+        cmp             w4, #16                 // width >= 16 ?
+        stp             q16, q17, [x0], #32     // store to dst
+        b.ge            1b
+        cbz             x4, 3f
+2:
+    .if \alpha_first
+        ldrb            w13, [x1, #1]           // w13: r
+        ldrb            w14, [x1, #2]           // w14: g
+        ldrb            w15, [x1, #3]           // w15: b
+    .else
+        ldrb            w13, [x1]               // w13: r
+        ldrb            w14, [x1, #1]           // w14: g
+        ldrb            w15, [x1, #2]           // w15: b
+    .endif
+
+        smaddl          x13, w13, w10, x9       // x13 = ry * r + const_offset
+        smaddl          x13, w14, w11, x13      // x13 += gy * g
+        smaddl          x13, w15, w12, x13      // x13 += by * b
+        asr             w13, w13, #9            // x13 >>= 9
+        sub             w4, w4, #1              // width--
+        add             x1, x1, #\element
+        strh            w13, [x0], #2           // store to dst
+        cbnz            w4, 2b
+3:
+        ret
+endfunc
+.endm
+
+rgbToY_neon bgr24, rgb24, element=3
+
+rgbToY_neon bgra32, rgba32, element=4
+
+rgbToY_neon abgr32, argb32, element=4, alpha_first=1
+
+.macro rgb_set_uv_coeff half
+    .if \half
+        mov             w9, #512
+        movk            w9, #128, lsl #16       // w9: const_offset
+    .else
+        mov             w9, #256
+        movk            w9, #64, lsl #16        // w9: const_offset
+    .endif
+        dup             v0.8h, w10
+        dup             v1.8h, w11
+        dup             v2.8h, w12
+        dup             v3.8h, w13
+        dup             v4.8h, w14
+        dup             v5.8h, w15
+        dup             v6.4s, w9
+.endm
+
+.macro rgb_load_add_half off_r1, off_r2, off_g1, off_g2, off_b1, off_b2
+        ldrb            w2, [x3, #\off_r1]     // w2: r1
+        ldrb            w4, [x3, #\off_r2]     // w4: r2
+        add             w2, w2, w4             // w2 = r1 + r2
+
+        ldrb            w4, [x3, #\off_g1]     // w4: g1
+        ldrb            w7, [x3, #\off_g2]     // w7: g2
+        add             w4, w4, w7             // w4 = g1 + g2
+
+        ldrb            w7, [x3, #\off_b1]     // w7: b1
+        ldrb            w8, [x3, #\off_b2]     // w8: b2
+        add             w7, w7, w8             // w7 = b1 + b2
+.endm
+
+.macro rgbToUV_half_neon fmt_bgr, fmt_rgb, element, alpha_first=0
+function ff_\fmt_bgr\()ToUV_half_neon, export=1
+        cmp             w5, #0          // check width > 0
+        b.le            3f
+
+        ldp             w12, w11, [x6, #12]
+        ldp             w10, w15, [x6, #20]
+        ldp             w14, w13, [x6, #28]
+        b               4f
+endfunc
+
+function ff_\fmt_rgb\()ToUV_half_neon, export=1
+        cmp             w5, #0          // check width > 0
+        b.le            3f
+
+        ldp             w10, w11, [x6, #12]     // w10: ru, w11: gu
+        ldp             w12, w13, [x6, #20]     // w12: bu, w13: rv
+        ldp             w14, w15, [x6, #28]     // w14: gv, w15: bv
+4:
+        cmp             w5, #8
+        rgb_set_uv_coeff half=1
+        b.lt            2f
+1:
+    .if \element == 3
+        ld3             { v16.16b, v17.16b, v18.16b }, [x3]
+    .else
+        ld4             { v16.16b, v17.16b, v18.16b, v19.16b }, [x3]
+    .endif
+    .if \alpha_first
+        uaddlp          v21.8h, v19.16b
+        uaddlp          v20.8h, v18.16b
+        uaddlp          v19.8h, v17.16b
+    .else
+        uaddlp          v19.8h, v16.16b         // v19: r
+        uaddlp          v20.8h, v17.16b         // v20: g
+        uaddlp          v21.8h, v18.16b         // v21: b
+    .endif
+
+        rgb_to_yuv_product v19, v20, v21, v22, v23, v16, v0, v1, v2, #10
+        rgb_to_yuv_product v19, v20, v21, v24, v25, v17, v3, v4, v5, #10
+        sub             w5, w5, #8              // width -= 8
+        add             x3, x3, #(16*\element)
+        cmp             w5, #8                  // width >= 8 ?
+        str             q16, [x0], #16          // store dst_u
+        str             q17, [x1], #16          // store dst_v
+        b.ge            1b
+        cbz             w5, 3f
+2:
+.if \alpha_first
+        rgb_load_add_half 1, 5, 2, 6, 3, 7
+.else
+    .if \element == 3
+        rgb_load_add_half 0, 3, 1, 4, 2, 5
+    .else
+        rgb_load_add_half 0, 4, 1, 5, 2, 6
+    .endif
+.endif
+
+        smaddl          x8, w2, w10, x9         // dst_u = ru * r + const_offset
+        smaddl          x8, w4, w11, x8         // dst_u += gu * g
+        smaddl          x8, w7, w12, x8         // dst_u += bu * b
+        asr             x8, x8, #10             // dst_u >>= 10
+        strh            w8, [x0], #2            // store dst_u
+
+        smaddl          x8, w2, w13, x9         // dst_v = rv * r + const_offset
+        smaddl          x8, w4, w14, x8         // dst_v += gv * g
+        smaddl          x8, w7, w15, x8         // dst_v += bv * b
+        asr             x8, x8, #10             // dst_v >>= 10
+        sub             w5, w5, #1
+        add             x3, x3, #(2*\element)
+        strh            w8, [x1], #2            // store dst_v
+        cbnz            w5, 2b
+3:
+        ret
+endfunc
+.endm
+
+rgbToUV_half_neon bgr24, rgb24, element=3
+
+rgbToUV_half_neon bgra32, rgba32, element=4
+
+rgbToUV_half_neon abgr32, argb32, element=4, alpha_first=1
+
+.macro rgbToUV_neon fmt_bgr, fmt_rgb, element, alpha_first=0
+function ff_\fmt_bgr\()ToUV_neon, export=1
+        cmp             w5, #0                  // check width > 0
+        b.le            3f
+
+        ldp             w12, w11, [x6, #12]
+        ldp             w10, w15, [x6, #20]
+        ldp             w14, w13, [x6, #28]
+        b               4f
+endfunc
+
+function ff_\fmt_rgb\()ToUV_neon, export=1
+        cmp             w5, #0                  // check width > 0
+        b.le            3f
+
+        ldp             w10, w11, [x6, #12]     // w10: ru, w11: gu
+        ldp             w12, w13, [x6, #20]     // w12: bu, w13: rv
+        ldp             w14, w15, [x6, #28]     // w14: gv, w15: bv
+4:
+        cmp             w5, #16
+        rgb_set_uv_coeff half=0
+        b.lt            2f
+1:
+    .if \alpha_first
+        argb_to_yuv_load_rgb x3
+    .else
+        rgb_to_yuv_load_rgb x3, \element
+    .endif
+        rgb_to_yuv_product v19, v20, v21, v25, v26, v16, v0, v1, v2, #9
+        rgb_to_yuv_product v22, v23, v24, v27, v28, v17, v0, v1, v2, #9
+        rgb_to_yuv_product v19, v20, v21, v25, v26, v18, v3, v4, v5, #9
+        rgb_to_yuv_product v22, v23, v24, v27, v28, v19, v3, v4, v5, #9
+        sub             w5, w5, #16
+        add             x3, x3, #(16*\element)
+        cmp             w5, #16
+        stp             q16, q17, [x0], #32     // store to dst_u
+        stp             q18, q19, [x1], #32     // store to dst_v
+        b.ge            1b
+        cbz             w5, 3f
+2:
+    .if \alpha_first
+        ldrb            w16, [x3, #1]           // w16: r
+        ldrb            w17, [x3, #2]           // w17: g
+        ldrb            w4, [x3, #3]            // w4: b
+    .else
+        ldrb            w16, [x3]               // w16: r
+        ldrb            w17, [x3, #1]           // w17: g
+        ldrb            w4, [x3, #2]            // w4: b
+    .endif
+
+        smaddl          x8, w16, w10, x9        // x8 = ru * r + const_offset
+        smaddl          x8, w17, w11, x8        // x8 += gu * g
+        smaddl          x8, w4, w12, x8         // x8 += bu * b
+        asr             w8, w8, #9              // x8 >>= 9
+        strh            w8, [x0], #2            // store to dst_u
+
+        smaddl          x8, w16, w13, x9        // x8 = rv * r + const_offset
+        smaddl          x8, w17, w14, x8        // x8 += gv * g
+        smaddl          x8, w4, w15, x8         // x8 += bv * b
+        asr             w8, w8, #9              // x8 >>= 9
+        sub             w5, w5, #1              // width--
+        add             x3, x3, #\element
+        strh            w8, [x1], #2            // store to dst_v
+        cbnz            w5, 2b
+3:
+        ret
+endfunc
+.endm
+
+rgbToUV_neon bgr24, rgb24, element=3
+
+rgbToUV_neon bgra32, rgba32, element=4
+
+rgbToUV_neon abgr32, argb32, element=4, alpha_first=1
+
+#if HAVE_DOTPROD
+ENABLE_DOTPROD
+
+function ff_bgra32ToY_neon_dotprod, export=1
+        cmp             w4, #0                  // check width > 0
+        ldp             w12, w11, [x5]          // w12: ry, w11: gy
+        ldr             w10, [x5, #8]           // w10: by
+        b.gt            4f
+        ret
+endfunc
+
+function ff_rgba32ToY_neon_dotprod, export=1
+        cmp             w4, #0                  // check width > 0
+        ldp             w10, w11, [x5]          // w10: ry, w11: gy
+        ldr             w12, [x5, #8]           // w12: by
+        b.le            3f
+4:
+        mov             w9, #256                // w9 = 1 << (RGB2YUV_SHIFT - 7)
+        movk            w9, #8, lsl #16         // w9 += 32 << (RGB2YUV_SHIFT - 1)
+        dup             v6.4s, w9               // w9: const_offset
+
+        cmp             w4, #16
+        mov             w7, w10
+        bfi             w7, w11, 8, 8           // the bfi instructions are used to assemble
+        bfi             w7, w12, 16, 8          // 4 byte r,g,b,0 mask to be then used by udot.
+        dup             v0.4s, w7               // v0 holds the lower byte of each coefficient
+
+        lsr             w6, w10, #8
+        lsr             w7, w11, #8
+        lsr             w8, w12, #8
+
+        bfi             w6, w7, 8, 8
+        bfi             w6, w8, 16, 8
+        dup             v1.4s, w6               // v1 holds the upper byte of each coefficient
+        b.lt            2f
+1:
+        ld1             { v16.16b, v17.16b, v18.16b, v19.16b }, [x1], #64
+        sub             w4, w4, #16             // width -= 16
+
+        mov             v2.16b, v6.16b
+        mov             v3.16b, v6.16b
+        mov             v4.16b, v6.16b
+        mov             v5.16b, v6.16b
+        cmp             w4, #16                 // width >= 16 ?
+
+        udot            v2.4s, v16.16b, v0.16b
+        udot            v3.4s, v17.16b, v0.16b
+        udot            v4.4s, v18.16b, v0.16b
+        udot            v5.4s, v19.16b, v0.16b
+
+        ushr            v2.4s, v2.4s, #8
+        ushr            v3.4s, v3.4s, #8
+        ushr            v4.4s, v4.4s, #8
+        ushr            v5.4s, v5.4s, #8
+
+        udot            v2.4s, v16.16b, v1.16b
+        udot            v3.4s, v17.16b, v1.16b
+        udot            v4.4s, v18.16b, v1.16b
+        udot            v5.4s, v19.16b, v1.16b
+
+        sqshrn          v16.4h, v2.4s, #1
+        sqshrn2         v16.8h, v3.4s, #1
+        sqshrn          v17.4h, v4.4s, #1
+        sqshrn2         v17.8h, v5.4s, #1
+
+        stp             q16, q17, [x0], #32     // store to dst
+        b.ge            1b
+        cbz             x4, 3f
+2:
+        ldrb            w13, [x1]               // w13: r
+        ldrb            w14, [x1, #1]           // w14: g
+        ldrb            w15, [x1, #2]           // w15: b
+
+        smaddl          x13, w13, w10, x9       // x13 = ry * r + const_offset
+        smaddl          x13, w14, w11, x13      // x13 += gy * g
+        smaddl          x13, w15, w12, x13      // x13 += by * b
+        asr             w13, w13, #9            // x13 >>= 9
+        sub             w4, w4, #1              // width--
+        add             x1, x1, #4
+        strh            w13, [x0], #2           // store to dst
+        cbnz            w4, 2b
+3:
+        ret
+endfunc
+
+DISABLE_DOTPROD
+#endif
diff --git a/libs/ffmpeg/libswscale/aarch64/output.S b/libs/ffmpeg/libswscale/aarch64/output.S
new file mode 100644
index 000000000000..a650d72f54cf
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/output.S
@@ -0,0 +1,631 @@
+/*
+ * Copyright (c) 2016 Clément Bœsch <clement stupeflix.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/aarch64/asm.S"
+
+function ff_yuv2planeX_10_neon, export=1
+// x0 = filter (int16_t*)
+// w1 = filterSize
+// x2 = src (int16_t**)
+// x3 = dest (uint16_t*)
+// w4 = dstW
+// w5 = big_endian
+// w6 = output_bits
+
+        mov             w8, #27
+        sub             w8, w8, w6                      // shift = 11 + 16 - output_bits
+
+        sub             w9, w8, #1
+        mov             w10, #1
+        lsl             w9, w10, w9                     // val = 1 << (shift - 1)
+
+        dup             v1.4s, w9
+        dup             v2.4s, w9                       // Create vectors with val
+
+        neg             w16, w8
+        dup             v20.4s, w16                     // Create (-shift) vector for right shift
+
+        mov             w10, #1
+        lsl             w10, w10, w6
+        sub             w10, w10, #1                    // (1U << output_bits) - 1
+        dup             v21.4s, w10                     // Create Clip vector for upper bound
+        dup             v27.8h, w10
+
+        mov             x7, #0                          // i = 0
+
+1:
+        cmp             w4, #16                         // Process 16-pixels if available
+        blt             4f
+
+        mov             v3.16b, v1.16b
+        mov             v4.16b, v2.16b
+        mov             v5.16b, v1.16b
+        mov             v6.16b, v2.16b
+
+        mov             w11, w1                         // tmpfilterSize = filterSize
+        mov             x12, x2                         // srcp = src
+        mov             x13, x0                         // filterp = filter
+
+2:                                                      // Filter loop
+        ldp             x14, x15, [x12], #16            // get 2 pointers: src[j] and src[j+1]
+        ldr             s7, [x13], #4                   // load filter coefficients
+        add             x14, x14, x7, lsl #1
+        add             x15, x15, x7, lsl #1
+        ld1             {v16.8h, v17.8h}, [x14]
+        ld1             {v18.8h, v19.8h}, [x15]
+
+        subs            w11, w11, #2                    // tmpfilterSize -= 2
+
+        smlal           v3.4s,  v16.4h, v7.h[0]         // Multiply-accumulate
+        smlal2          v4.4s,  v16.8h, v7.h[0]
+        smlal           v5.4s,  v17.4h, v7.h[0]
+        smlal2          v6.4s,  v17.8h, v7.h[0]
+
+        smlal           v3.4s,  v18.4h, v7.h[1]
+        smlal2          v4.4s,  v18.8h, v7.h[1]
+        smlal           v5.4s,  v19.4h, v7.h[1]
+        smlal2          v6.4s,  v19.8h, v7.h[1]
+
+        b.gt            2b                              // continue filter loop
+
+        sshl            v3.4s,  v3.4s, v20.4s           // Shift results
+        sshl            v4.4s,  v4.4s, v20.4s
+        sshl            v5.4s,  v5.4s, v20.4s
+        sshl            v6.4s,  v6.4s, v20.4s
+
+        sqxtun          v23.4h, v3.4s                   // Narrow and clamp to 0
+        sqxtun2         v23.8h, v4.4s
+        sqxtun          v24.4h, v5.4s
+        sqxtun2         v24.8h, v6.4s
+
+        umin            v23.8h, v23.8h, v27.8h
+        umin            v24.8h, v24.8h, v27.8h
+
+        cbz             w5, 3f                          // Check if big endian
+        rev16           v23.16b, v23.16b
+        rev16           v24.16b, v24.16b                // Swap bits for big endian
+3:
+        st1             {v23.8h, v24.8h}, [x3], #32
+
+        subs            w4, w4, #16                     // dstW = dstW - 16
+        add             x7, x7, #16                     // i = i + 16
+        b               1b                              // Continue loop
+
+4:
+        cmp             w4, #8                          // Process 8-pixels if available
+        blt             8f
+5:
+        mov             v3.16b, v1.16b
+        mov             v4.16b, v2.16b
+
+        mov             w11, w1                         // tmpfilterSize = filterSize
+        mov             x12, x2                         // srcp = src
+        mov             x13, x0                         // filterp = filter
+
+6:                                                      // Filter loop
+        ldp             x14, x15, [x12], #16
+        ldr             s7, [x13], #4
+        add             x14, x14, x7, lsl #1
+        add             x15, x15, x7, lsl #1
+        ld1             {v5.8h}, [x14]
+        ld1             {v6.8h}, [x15]
+
+        subs            w11, w11, #2                    // tmpfilterSize -= 2
+
+        smlal           v3.4s, v5.4h, v7.h[0]           // Multiply-accumulate
+        smlal2          v4.4s, v5.8h, v7.h[0]
+        smlal           v3.4s, v6.4h, v7.h[1]
+        smlal2          v4.4s, v6.8h, v7.h[1]
+
+        b.gt            6b                              // loop until filterSize consumed
+
+        sshl            v3.4s, v3.4s, v20.4s            // Shift results
+        sshl            v4.4s, v4.4s, v20.4s
+
+        sqxtun          v25.4h, v3.4s                   // Narrow and clamp to 0
+        sqxtun2         v25.8h, v4.4s
+
+        umin            v25.8h, v25.8h, v27.8h
+
+        cbz             w5, 7f                          // Check if big endian
+        rev16           v25.16b, v25.16b
+
+7:
+        st1             {v25.8h}, [x3], #16             // Store 8 pixels
+
+        subs            w4, w4, #8                      // dstW = dstW - 8
+        add             x7, x7, #8                      // i = i + 8
+8:
+        cbz             w4, 12f                         // Scalar loop for remaining pixels
+9:
+        mov             w11, w1                         // tmpfilterSize = filterSize
+        mov             x12, x2                         // srcp = src
+        mov             x13, x0                         // filterp = filter
+        sxtw            x9, w9
+        mov             x17, x9
+
+10:                                                     // Filter loop
+        ldr             x14, [x12], #8                  // Load src pointer
+        ldrsh           w15, [x13], #2                  // Load filter coefficient
+        add             x14, x14, x7, lsl #1            // Add pixel offset
+        ldrh            w16, [x14]
+
+        sxtw            x16, w16
+        sxtw            x15, w15
+        madd            x17, x16, x15, x17
+
+        subs            w11, w11, #1                    // tmpfilterSize -= 1
+        b.gt            10b                             // loop until filterSize consumed
+
+        sxtw            x8, w8
+        asr             x17, x17, x8
+        cmp             x17, #0
+        csel            x17, x17, xzr, ge               // Clamp to 0 if negative
+
+        sxtw            x10, w10
+        cmp             x17, x10
+        csel            x17, x10, x17, gt               // Clamp to max if greater than max
+
+        cbz             w5, 11f                         // Check if big endian
+        rev16           x17, x17                        // Swap bits for big endian
+11:
+        strh            w17, [x3], #2
+
+        subs            w4, w4, #1                      // dstW = dstW - 1
+        add             x7, x7, #1                      // i = i + 1
+        b.gt            9b                              // Loop if more pixels
+
+12:
+        ret
+endfunc
+
+function ff_yuv2planeX_8_neon, export=1
+// x0 - const int16_t *filter,
+// x1 - int filterSize,
+// x2 - const int16_t **src,
+// x3 - uint8_t *dest,
+// w4 - int dstW,
+// x5 - const uint8_t *dither,
+// w6 - int offset
+
+        ld1             {v0.8b}, [x5]                   // load 8x8-bit dither
+        and             w6, w6, #7
+        cbz             w6, 1f                          // check if offsetting present
+        ext             v0.8b, v0.8b, v0.8b, #3         // honor offsetting which can be 0 or 3 only
+1:      uxtl            v0.8h, v0.8b                    // extend dither to 16-bit
+        ushll           v1.4s, v0.4h, #12               // extend dither to 32-bit with left shift by 12 (part 1)
+        ushll2          v2.4s, v0.8h, #12               // extend dither to 32-bit with left shift by 12 (part 2)
+        cmp             w1, #8                          // if filterSize == 8, branch to specialized version
+        b.eq            6f
+        cmp             w1, #4                          // if filterSize == 4, branch to specialized version
+        b.eq            8f
+        cmp             w1, #2                          // if filterSize == 2, branch to specialized version
+        b.eq            10f
+
+// The filter size does not match of the of specialized implementations. It is either even or odd. If it is even
+// then use the first section below.
+        mov             x7, #0                          // i = 0
+        tbnz            w1, #0, 4f                      // if filterSize % 2 != 0 branch to specialized version
+// fs % 2 == 0
+2:      mov             v3.16b, v1.16b                  // initialize accumulator part 1 with dithering value
+        mov             v4.16b, v2.16b                  // initialize accumulator part 2 with dithering value
+        mov             w8, w1                          // tmpfilterSize = filterSize
+        mov             x9, x2                          // srcp    = src
+        mov             x10, x0                         // filterp = filter
+3:      ldp             x11, x12, [x9], #16             // get 2 pointers: src[j] and src[j+1]
+        ldr             s7, [x10], #4                   // read 2x16-bit coeff X and Y at filter[j] and filter[j+1]
+        add             x11, x11, x7, lsl #1            // &src[j  ][i]
+        add             x12, x12, x7, lsl #1            // &src[j+1][i]
+        ld1             {v5.8h}, [x11]                  // read 8x16-bit @ src[j  ][i + {0..7}]: A,B,C,D,E,F,G,H
+        ld1             {v6.8h}, [x12]                  // read 8x16-bit @ src[j+1][i + {0..7}]: I,J,K,L,M,N,O,P
+        smlal           v3.4s, v5.4h, v7.h[0]           // val0 += {A,B,C,D} * X
+        smlal2          v4.4s, v5.8h, v7.h[0]           // val1 += {E,F,G,H} * X
+        smlal           v3.4s, v6.4h, v7.h[1]           // val0 += {I,J,K,L} * Y
+        smlal2          v4.4s, v6.8h, v7.h[1]           // val1 += {M,N,O,P} * Y
+        subs            w8, w8, #2                      // tmpfilterSize -= 2
+        b.gt            3b                              // loop until filterSize consumed
+
+        sqshrun         v3.4h, v3.4s, #16               // clip16(val0>>16)
+        sqshrun2        v3.8h, v4.4s, #16               // clip16(val1>>16)
+        uqshrn          v3.8b, v3.8h, #3                // clip8(val>>19)
+        st1             {v3.8b}, [x3], #8               // write to destination
+        subs            w4, w4, #8                      // dstW -= 8
+        add             x7, x7, #8                      // i += 8
+        b.gt            2b                              // loop until width consumed
+        ret
+
+// If filter size is odd (most likely == 1), then use this section.
+// fs % 2 != 0
+4:      mov             v3.16b, v1.16b                  // initialize accumulator part 1 with dithering value
+        mov             v4.16b, v2.16b                  // initialize accumulator part 2 with dithering value
+        mov             w8, w1                          // tmpfilterSize = filterSize
+        mov             x9, x2                          // srcp    = src
+        mov             x10, x0                         // filterp = filter
+5:      ldr             x11, [x9], #8                   // get 1 pointer: src[j]
+        ldr             h6, [x10], #2                   // read 1 16 bit coeff X at filter[j]
+        add             x11, x11, x7, lsl #1            // &src[j  ][i]
+        ld1             {v5.8h}, [x11]                  // read 8x16-bit @ src[j  ][i + {0..7}]: A,B,C,D,E,F,G,H
+        smlal           v3.4s, v5.4h, v6.h[0]           // val0 += {A,B,C,D} * X
+        smlal2          v4.4s, v5.8h, v6.h[0]           // val1 += {E,F,G,H} * X
+        subs            w8, w8, #1                      // tmpfilterSize -= 2
+        b.gt            5b                              // loop until filterSize consumed
+
+        sqshrun         v3.4h, v3.4s, #16               // clip16(val0>>16)
+        sqshrun2        v3.8h, v4.4s, #16               // clip16(val1>>16)
+        uqshrn          v3.8b, v3.8h, #3                // clip8(val>>19)
+        st1             {v3.8b}, [x3], #8               // write to destination
+        subs            w4, w4, #8                      // dstW -= 8
+        add             x7, x7, #8                      // i += 8
+        b.gt            4b                              // loop until width consumed
+        ret
+
+6:      // fs=8
+        ldp             x5, x6, [x2]                    // load 2 pointers: src[j  ] and src[j+1]
+        ldp             x7, x9, [x2, #16]               // load 2 pointers: src[j+2] and src[j+3]
+        ldp             x10, x11, [x2, #32]             // load 2 pointers: src[j+4] and src[j+5]
+        ldp             x12, x13, [x2, #48]             // load 2 pointers: src[j+6] and src[j+7]
+
+        // load 8x16-bit values for filter[j], where j=0..7
+        ld1             {v6.8h}, [x0]
+7:
+        mov             v3.16b, v1.16b                  // initialize accumulator part 1 with dithering value
+        mov             v4.16b, v2.16b                  // initialize accumulator part 2 with dithering value
+
+        ld1             {v24.8h}, [x5], #16             // load 8x16-bit values for src[j + 0][i + {0..7}]
+        ld1             {v25.8h}, [x6], #16             // load 8x16-bit values for src[j + 1][i + {0..7}]
+        ld1             {v26.8h}, [x7], #16             // load 8x16-bit values for src[j + 2][i + {0..7}]
+        ld1             {v27.8h}, [x9], #16             // load 8x16-bit values for src[j + 3][i + {0..7}]
+        ld1             {v28.8h}, [x10], #16            // load 8x16-bit values for src[j + 4][i + {0..7}]
+        ld1             {v29.8h}, [x11], #16            // load 8x16-bit values for src[j + 5][i + {0..7}]
+        ld1             {v30.8h}, [x12], #16            // load 8x16-bit values for src[j + 6][i + {0..7}]
+        ld1             {v31.8h}, [x13], #16            // load 8x16-bit values for src[j + 7][i + {0..7}]
+
+        smlal           v3.4s, v24.4h, v6.h[0]          // val0 += src[0][i + {0..3}] * filter[0]
+        smlal2          v4.4s, v24.8h, v6.h[0]          // val1 += src[0][i + {4..7}] * filter[0]
+        smlal           v3.4s, v25.4h, v6.h[1]          // val0 += src[1][i + {0..3}] * filter[1]
+        smlal2          v4.4s, v25.8h, v6.h[1]          // val1 += src[1][i + {4..7}] * filter[1]
+        smlal           v3.4s, v26.4h, v6.h[2]          // val0 += src[2][i + {0..3}] * filter[2]
+        smlal2          v4.4s, v26.8h, v6.h[2]          // val1 += src[2][i + {4..7}] * filter[2]
+        smlal           v3.4s, v27.4h, v6.h[3]          // val0 += src[3][i + {0..3}] * filter[3]
+        smlal2          v4.4s, v27.8h, v6.h[3]          // val1 += src[3][i + {4..7}] * filter[3]
+        smlal           v3.4s, v28.4h, v6.h[4]          // val0 += src[4][i + {0..3}] * filter[4]
+        smlal2          v4.4s, v28.8h, v6.h[4]          // val1 += src[4][i + {4..7}] * filter[4]
+        smlal           v3.4s, v29.4h, v6.h[5]          // val0 += src[5][i + {0..3}] * filter[5]
+        smlal2          v4.4s, v29.8h, v6.h[5]          // val1 += src[5][i + {4..7}] * filter[5]
+        smlal           v3.4s, v30.4h, v6.h[6]          // val0 += src[6][i + {0..3}] * filter[6]
+        smlal2          v4.4s, v30.8h, v6.h[6]          // val1 += src[6][i + {4..7}] * filter[6]
+        smlal           v3.4s, v31.4h, v6.h[7]          // val0 += src[7][i + {0..3}] * filter[7]
+        smlal2          v4.4s, v31.8h, v6.h[7]          // val1 += src[7][i + {4..7}] * filter[7]
+
+        sqshrun         v3.4h, v3.4s, #16               // clip16(val0>>16)
+        sqshrun2        v3.8h, v4.4s, #16               // clip16(val1>>16)
+        uqshrn          v3.8b, v3.8h, #3                // clip8(val>>19)
+        subs            w4, w4, #8                      // dstW -= 8
+        st1             {v3.8b}, [x3], #8               // write to destination
+        b.gt            7b                              // loop until width consumed
+        ret
+
+8:      // fs=4
+        ldp             x5, x6, [x2]                    // load 2 pointers: src[j  ] and src[j+1]
+        ldp             x7, x9, [x2, #16]               // load 2 pointers: src[j+2] and src[j+3]
+
+        // load 4x16-bit values for filter[j], where j=0..3 and replicated across lanes
+        ld1             {v6.4h}, [x0]
+9:
+        mov             v3.16b, v1.16b                  // initialize accumulator part 1 with dithering value
+        mov             v4.16b, v2.16b                  // initialize accumulator part 2 with dithering value
+
+        ld1             {v24.8h}, [x5], #16             // load 8x16-bit values for src[j + 0][i + {0..7}]
+        ld1             {v25.8h}, [x6], #16             // load 8x16-bit values for src[j + 1][i + {0..7}]
+        ld1             {v26.8h}, [x7], #16             // load 8x16-bit values for src[j + 2][i + {0..7}]
+        ld1             {v27.8h}, [x9], #16             // load 8x16-bit values for src[j + 3][i + {0..7}]
+
+        smlal           v3.4s, v24.4h, v6.h[0]          // val0 += src[0][i + {0..3}] * filter[0]
+        smlal2          v4.4s, v24.8h, v6.h[0]          // val1 += src[0][i + {4..7}] * filter[0]
+        smlal           v3.4s, v25.4h, v6.h[1]          // val0 += src[1][i + {0..3}] * filter[1]
+        smlal2          v4.4s, v25.8h, v6.h[1]          // val1 += src[1][i + {4..7}] * filter[1]
+        smlal           v3.4s, v26.4h, v6.h[2]          // val0 += src[2][i + {0..3}] * filter[2]
+        smlal2          v4.4s, v26.8h, v6.h[2]          // val1 += src[2][i + {4..7}] * filter[2]
+        smlal           v3.4s, v27.4h, v6.h[3]          // val0 += src[3][i + {0..3}] * filter[3]
+        smlal2          v4.4s, v27.8h, v6.h[3]          // val1 += src[3][i + {4..7}] * filter[3]
+
+        sqshrun         v3.4h, v3.4s, #16               // clip16(val0>>16)
+        sqshrun2        v3.8h, v4.4s, #16               // clip16(val1>>16)
+        uqshrn          v3.8b, v3.8h, #3                // clip8(val>>19)
+        st1             {v3.8b}, [x3], #8               // write to destination
+        subs            w4, w4, #8                      // dstW -= 8
+        b.gt            9b                              // loop until width consumed
+        ret
+
+10:     // fs=2
+        ldp             x5, x6, [x2]                    // load 2 pointers: src[j  ] and src[j+1]
+
+        // load 2x16-bit values for filter[j], where j=0..1 and replicated across lanes
+        ldr             s6, [x0]
+11:
+        mov             v3.16b, v1.16b                  // initialize accumulator part 1 with dithering value
+        mov             v4.16b, v2.16b                  // initialize accumulator part 2 with dithering value
+
+        ld1             {v24.8h}, [x5], #16             // load 8x16-bit values for src[j + 0][i + {0..7}]
+        ld1             {v25.8h}, [x6], #16             // load 8x16-bit values for src[j + 1][i + {0..7}]
+
+        smlal           v3.4s, v24.4h, v6.h[0]          // val0 += src[0][i + {0..3}] * filter[0]
+        smlal2          v4.4s, v24.8h, v6.h[0]          // val1 += src[0][i + {4..7}] * filter[0]
+        smlal           v3.4s, v25.4h, v6.h[1]          // val0 += src[1][i + {0..3}] * filter[1]
+        smlal2          v4.4s, v25.8h, v6.h[1]          // val1 += src[1][i + {4..7}] * filter[1]
+
+        sqshrun         v3.4h, v3.4s, #16               // clip16(val0>>16)
+        sqshrun2        v3.8h, v4.4s, #16               // clip16(val1>>16)
+        uqshrn          v3.8b, v3.8h, #3                // clip8(val>>19)
+        st1             {v3.8b}, [x3], #8               // write to destination
+        subs            w4, w4, #8                      // dstW -= 8
+        b.gt            11b                             // loop until width consumed
+        ret
+endfunc
+
+function ff_yuv2plane1_8_neon, export=1
+// x0 - const int16_t *src,
+// x1 - uint8_t *dest,
+// w2 - int dstW,
+// x3 - const uint8_t *dither,
+// w4 - int offset
+        ld1             {v0.8b}, [x3]                   // load 8x8-bit dither
+        and             w4, w4, #7
+        cbz             w4, 1f                          // check if offsetting present
+        ext             v0.8b, v0.8b, v0.8b, #3         // honor offsetting which can be 0 or 3 only
+1:
+        uxtl            v0.8h, v0.8b                    // extend dither to 32-bit
+2:
+        ld1             {v3.8h}, [x0], #16              // read 8x16-bit @ src[j  ][i + {0..7}]: A,B,C,D,E,F,G,H
+        subs            w2, w2, #8                      // dstW -= 8
+        shadd           v1.8h, v0.8h, v3.8h             // v1 = (v0 + v3) >> 1
+        sqshrun         v2.8b, v1.8h, #6                // clip_uint8(v1 >> 6)
+
+        st1             {v2.8b}, [x1], #8               // write to destination
+        b.gt            2b                              // loop until width consumed
+        ret
+endfunc
+
+function ff_yuv2nv12cX_neon_asm, export=1
+// w0 - isSwapped
+// x1 - uint8_t *chrDither
+// x2 - int16_t *chrFilter
+// x3 - int chrFilterSize
+// x4 - int16_t **chrUSrc
+// x5 - int16_t **chrVSrc
+// x6 - uint8_t *dest
+// x7 - int chrDstW
+
+        stp             x19, x20, [sp, #-32]!
+        stp             x21, x22, [sp, #16]
+
+        ld1             {v0.8b}, [x1]                   // chrDither[0..7]
+        ext             v1.8b, v0.8b, v0.8b, #3         // Rotate for V: (i+3)&7
+
+        uxtl            v0.8h, v0.8b
+        uxtl            v1.8h, v1.8b
+
+        ushll           v2.4s, v0.4h, #12               // U dither low
+        ushll2          v3.4s, v0.8h, #12               // U dither high
+        ushll           v4.4s, v1.4h, #12               // V dither low
+        ushll2          v5.4s, v1.8h, #12               // V dither high
+
+        mov             x8, #0                          // i = 0
+1:
+        cmp             w7, #16
+        blt             5f
+
+        mov             v16.16b, v2.16b                 // U acc low
+        mov             v17.16b, v3.16b                 // U acc high
+        mov             v18.16b, v4.16b                 // V acc low
+        mov             v19.16b, v5.16b                 // V acc high
+
+        mov             v20.16b, v2.16b
+        mov             v21.16b, v3.16b
+        mov             v22.16b, v4.16b
+        mov             v23.16b, v5.16b
+
+        mov             w9, w3                          // chrFilterSize counter
+        mov             x10, x2                         // chrFilter pointer
+        mov             x11, x4                         // chrUSrc base
+        mov             x12, x5                         // chrVSrc base
+
+2:
+        ldr             h6, [x10], #2                   // Load filter coefficient
+
+        ldr             x13, [x11], #8                  // chrUSrc[j]
+        ldr             x14, [x12], #8                  // chrVSrc[j]
+        add             x13, x13, x8, lsl #1            // &chrUSrc[j][i]
+        add             x14, x14, x8, lsl #1            // &chrVSrc[j][i]
+        add             x15, x13, #16
+        add             x16, x14, #16
+
+        ld1             {v24.8h}, [x13]                 // U samples 0-7
+        ld1             {v25.8h}, [x14]                 // V samples 0-7
+
+        ld1             {v26.8h}, [x15]                 // U samples 8-15
+        ld1             {v27.8h}, [x16]                 // V samples 8-15
+        subs            w9, w9, #1
+
+        smlal           v16.4s, v24.4h, v6.h[0]
+        smlal2          v17.4s, v24.8h, v6.h[0]
+        smlal           v18.4s, v25.4h, v6.h[0]
+        smlal2          v19.4s, v25.8h, v6.h[0]
+
+        smlal           v20.4s, v26.4h, v6.h[0]
+        smlal2          v21.4s, v26.8h, v6.h[0]
+        smlal           v22.4s, v27.4h, v6.h[0]
+        smlal2          v23.4s, v27.8h, v6.h[0]
+
+        b.gt            2b
+
+        sqshrun         v24.4h, v16.4s, #16             // Process and store first 8 pixels
+        sqshrun2        v24.8h, v17.4s, #16
+        sqshrun         v25.4h, v18.4s, #16
+        sqshrun2        v25.8h, v19.4s, #16
+
+        sqshrun         v26.4h, v20.4s, #16             // Process and store next 8 pixels
+        sqshrun2        v26.8h, v21.4s, #16
+        sqshrun         v27.4h, v22.4s, #16
+        sqshrun2        v27.8h, v23.4s, #16
+
+        cbz             w0, 3f
+
+        uqshrn          v28.8b, v24.8h, #3              // Storing U
+        uqshrn2         v28.16b, v26.8h, #3
+        uqshrn          v29.8b, v25.8h, #3              // Storing V
+        uqshrn2         v29.16b, v27.8h, #3
+
+        st2             {v28.16b, v29.16b}, [x6], #32
+        b               4f
+3:
+        uqshrn          v28.8b, v25.8h, #3              // Storing V
+        uqshrn2         v28.16b, v27.8h, #3
+        uqshrn          v29.8b, v24.8h, #3              // Storing U
+        uqshrn2         v29.16b, v26.8h, #3
+
+        st2             {v28.16b, v29.16b}, [x6], #32
+4:
+        subs            w7, w7, #16
+        add             x8, x8, #16
+        b.gt            1b
+
+5:
+        cmp             w7, #8
+        blt             10f
+6:
+        mov             v16.16b, v2.16b                 // U acc low
+        mov             v17.16b, v3.16b                 // U acc high
+        mov             v18.16b, v4.16b                 // V acc low
+        mov             v19.16b, v5.16b                 // V acc high
+
+        mov             w9, w3                          // chrFilterSize counter
+        mov             x10, x2                         // chrFilter pointer
+        mov             x11, x4                         // chrUSrc base
+        mov             x12, x5                         // chrVSrc base
+
+7:
+        ldr             h6, [x10], #2                   // Load filter coefficient
+
+        ldr             x13, [x11], #8                  // chrUSrc[j]
+        ldr             x14, [x12], #8                  // chrVSrc[j]
+        add             x13, x13, x8, lsl #1            // &chrUSrc[j][i]
+        add             x14, x14, x8, lsl #1            // &chrVSrc[j][i]
+
+        ld1             {v20.8h}, [x13]                 // U samples
+        ld1             {v21.8h}, [x14]                 // V samples
+        subs            w9, w9, #1
+
+        smlal           v16.4s, v20.4h, v6.h[0]
+        smlal2          v17.4s, v20.8h, v6.h[0]
+        smlal           v18.4s, v21.4h, v6.h[0]
+        smlal2          v19.4s, v21.8h, v6.h[0]
+
+        b.gt            7b
+
+        sqshrun         v26.4h, v16.4s, #16             // Final processing and store
+        sqshrun2        v26.8h, v17.4s, #16
+        sqshrun         v27.4h, v18.4s, #16
+        sqshrun2        v27.8h, v19.4s, #16
+
+        cbz             w0, 8f
+        uqshrn          v28.8b, v26.8h, #3              // Storing U
+        uqshrn          v29.8b, v27.8h, #3              // Storing V
+        st2             {v28.8b, v29.8b}, [x6], #16
+        b               9f
+8:
+        uqshrn          v28.8b, v27.8h, #3              // Storing V
+        uqshrn          v29.8b, v26.8h, #3              // Storing U
+        st2             {v28.8b, v29.8b}, [x6], #16
+9:
+        subs            w7, w7, #8
+        add             x8, x8, #8
+
+10:
+        cbz             w7, 15f                         // Scalar loop
+
+11:
+        and             x15, x8, #7
+        ldrb            w9, [x1, x15]
+        sxtw            x9, w9
+        lsl             x9, x9, #12                     // u = chrDither[i & 7] << 12;
+
+        add             x15, x8, #3
+        and             x15, x15, #7
+        ldrb            w10, [x1, x15]
+        sxtw            x10, w10
+        lsl             x10, x10, #12                   // v = chrDither[(i + 3) & 7] << 12;
+
+        mov             w11, w3                         // chrFilterSize counter
+        mov             x12, x2                         // chrFilter pointer
+        mov             x13, x4                         // chrUSrc base
+        mov             x14, x5                         // chrVSrc base
+
+12:
+        ldrsh           x16, [x12], #2
+
+        ldr             x17, [x13], #8                  // chrUSrc[j]
+        ldr             x19, [x14], #8                  // chrVSrc[j]
+        add             x17, x17, x8, lsl #1            // &chrUSrc[j][i]
+        add             x19, x19, x8, lsl #1            // &chrVSrc[j][i]
+
+        ldrsh           x20, [x17]
+        ldrsh           x21, [x19]
+
+        madd            x9, x16, x20, x9
+        madd            x10, x16, x21, x10
+
+        subs            w11, w11, #1
+        b.gt            12b
+
+        asr             x9, x9, #19                     // Process and store U and V
+        asr             x10, x10, #19
+
+        cmp             x9, #0
+        csel            x9, x9, xzr, ge
+        cmp             x10, #0
+        csel            x10, x10, xzr, ge
+
+        mov             x22, #1
+        lsl             x22, x22, #8
+        sub             x22, x22, #1
+
+        cmp             x9, x22
+        csel            x9, x22, x9, gt
+        cmp             x10, x22
+        csel            x10, x22, x10, gt
+
+        cbz             w0, 13f
+        strb            w9, [x6], #1                    // Storing U
+        strb            w10, [x6], #1                   // Storing V
+        b               14f
+13:
+        strb            w10, [x6], #1                   // Storing V
+        strb            w9, [x6], #1                    // Storing U
+
+14:
+        subs            w7, w7, #1
+        add             x8, x8, #1
+        b.gt            11b
+15:
+        ldp             x21, x22, [sp, #16]
+        ldp             x19, x20, [sp], #32
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswscale/aarch64/range_convert_neon.S b/libs/ffmpeg/libswscale/aarch64/range_convert_neon.S
new file mode 100644
index 000000000000..c0eb7143339c
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/range_convert_neon.S
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2024 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/aarch64/asm.S"
+
+.macro lumConvertRange fromto, bit_depth
+function ff_lumRange\fromto\()Jpeg\bit_depth\()_neon, export=1
+// x0  int16_t *dst
+// w1  int width
+// w2  uint32_t coeff
+// x3  int64_t offset
+.if \bit_depth == 16
+.ifc \fromto, To
+        movi            v25.4s, #1
+        movi            v24.4s, #1<<3, lsl #16
+        sub             v24.4s, v24.4s, v25.4s
+.endif
+        dup             v25.4s, w2
+        dup             v26.2d, x3
+1:
+        ld1             {v0.4s, v1.4s}, [x0]
+        mov             v16.16b, v26.16b
+        mov             v17.16b, v26.16b
+        mov             v18.16b, v26.16b
+        mov             v19.16b, v26.16b
+        smlal           v16.2d, v0.2s, v25.2s
+        smlal2          v17.2d, v0.4s, v25.4s
+        smlal           v18.2d, v1.2s, v25.2s
+        smlal2          v19.2d, v1.4s, v25.4s
+        shrn            v0.2s, v16.2d, 18
+        shrn2           v0.4s, v17.2d, 18
+        shrn            v1.2s, v18.2d, 18
+        shrn2           v1.4s, v19.2d, 18
+        subs            w1, w1, #8
+.ifc \fromto, To
+        smin            v0.4s, v0.4s, v24.4s
+        smin            v1.4s, v1.4s, v24.4s
+.endif
+        st1             {v0.4s, v1.4s}, [x0], #32
+        b.gt            1b
+.else
+        dup             v25.4s, w2
+        dup             v26.4s, w3
+1:
+        ld1             {v0.8h}, [x0]
+        mov             v16.16b, v26.16b
+        mov             v18.16b, v26.16b
+        sxtl            v20.4s, v0.4h
+        sxtl2           v22.4s, v0.8h
+        mla             v16.4s, v20.4s, v25.4s
+        mla             v18.4s, v22.4s, v25.4s
+.ifc \fromto, To
+        sqshrn          v0.4h, v16.4s, 14
+        sqshrn2         v0.8h, v18.4s, 14
+.else
+        shrn            v0.4h, v16.4s, 14
+        shrn2           v0.8h, v18.4s, 14
+.endif
+        subs            w1, w1, #8
+        st1             {v0.8h}, [x0], #16
+        b.gt            1b
+.endif
+        ret
+endfunc
+.endm
+
+.macro chrConvertRange fromto, bit_depth
+function ff_chrRange\fromto\()Jpeg\bit_depth\()_neon, export=1
+// x0  int16_t *dstU
+// x1  int16_t *dstV
+// w2  int width
+// w3  uint32_t coeff
+// x4  int64_t offset
+.if \bit_depth == 16
+.ifc \fromto, To
+        movi            v25.4s, #1
+        movi            v24.4s, #1<<3, lsl #16
+        sub             v24.4s, v24.4s, v25.4s
+.endif
+        dup             v25.4s, w3
+        dup             v26.2d, x4
+1:
+        ld1             {v0.4s, v1.4s}, [x0]
+        ld1             {v2.4s, v3.4s}, [x1]
+        mov             v16.16b, v26.16b
+        mov             v17.16b, v26.16b
+        mov             v18.16b, v26.16b
+        mov             v19.16b, v26.16b
+        mov             v20.16b, v26.16b
+        mov             v21.16b, v26.16b
+        mov             v22.16b, v26.16b
+        mov             v23.16b, v26.16b
+        smlal           v16.2d, v0.2s, v25.2s
+        smlal2          v17.2d, v0.4s, v25.4s
+        smlal           v18.2d, v1.2s, v25.2s
+        smlal2          v19.2d, v1.4s, v25.4s
+        smlal           v20.2d, v2.2s, v25.2s
+        smlal2          v21.2d, v2.4s, v25.4s
+        smlal           v22.2d, v3.2s, v25.2s
+        smlal2          v23.2d, v3.4s, v25.4s
+        shrn            v0.2s, v16.2d, 18
+        shrn2           v0.4s, v17.2d, 18
+        shrn            v1.2s, v18.2d, 18
+        shrn2           v1.4s, v19.2d, 18
+        shrn            v2.2s, v20.2d, 18
+        shrn2           v2.4s, v21.2d, 18
+        shrn            v3.2s, v22.2d, 18
+        shrn2           v3.4s, v23.2d, 18
+        subs            w2, w2, #8
+.ifc \fromto, To
+        smin            v0.4s, v0.4s, v24.4s
+        smin            v1.4s, v1.4s, v24.4s
+        smin            v2.4s, v2.4s, v24.4s
+        smin            v3.4s, v3.4s, v24.4s
+.endif
+        st1             {v0.4s, v1.4s}, [x0], #32
+        st1             {v2.4s, v3.4s}, [x1], #32
+        b.gt            1b
+.else
+        dup             v25.4s, w3
+        dup             v26.4s, w4
+1:
+        ld1             {v0.8h}, [x0]
+        ld1             {v1.8h}, [x1]
+        mov             v16.16b, v26.16b
+        mov             v17.16b, v26.16b
+        mov             v18.16b, v26.16b
+        mov             v19.16b, v26.16b
+        sxtl            v20.4s, v0.4h
+        sxtl            v21.4s, v1.4h
+        sxtl2           v22.4s, v0.8h
+        sxtl2           v23.4s, v1.8h
+        mla             v16.4s, v20.4s, v25.4s
+        mla             v17.4s, v21.4s, v25.4s
+        mla             v18.4s, v22.4s, v25.4s
+        mla             v19.4s, v23.4s, v25.4s
+.ifc \fromto, To
+        sqshrn          v0.4h, v16.4s, 14
+        sqshrn          v1.4h, v17.4s, 14
+        sqshrn2         v0.8h, v18.4s, 14
+        sqshrn2         v1.8h, v19.4s, 14
+.else
+        shrn            v0.4h, v16.4s, 14
+        shrn            v1.4h, v17.4s, 14
+        shrn2           v0.8h, v18.4s, 14
+        shrn2           v1.8h, v19.4s, 14
+.endif
+        subs            w2, w2, #8
+        st1             {v0.8h}, [x0], #16
+        st1             {v1.8h}, [x1], #16
+        b.gt            1b
+.endif
+        ret
+endfunc
+.endm
+
+lumConvertRange To,    8
+lumConvertRange To,   16
+chrConvertRange To,    8
+chrConvertRange To,   16
+lumConvertRange From,  8
+lumConvertRange From, 16
+chrConvertRange From,  8
+chrConvertRange From, 16
diff --git a/libs/ffmpeg/libswscale/aarch64/rgb2rgb.c b/libs/ffmpeg/libswscale/aarch64/rgb2rgb.c
new file mode 100644
index 000000000000..b9d8aa4dc2d4
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/rgb2rgb.c
@@ -0,0 +1,111 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "config.h"
+#include "libavutil/attributes.h"
+#include "libavutil/aarch64/cpu.h"
+#include "libavutil/cpu.h"
+#include "libavutil/bswap.h"
+#include "libswscale/rgb2rgb.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+
+// Only handle width aligned to 16
+void ff_rgb24toyv12_neon(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);
+
+static void 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)
+{
+    int width_align = width & (~15);
+
+    if (width_align > 0)
+        ff_rgb24toyv12_neon(src, ydst, udst, vdst, width_align, height,
+                lumStride, chromStride, srcStride, rgb2yuv);
+    if (width_align < width) {
+        src += width_align * 3;
+        ydst += width_align;
+        udst += width_align / 2;
+        vdst += width_align / 2;
+        ff_rgb24toyv12_c(src, ydst, udst, vdst, width - width_align, height,
+                lumStride, chromStride, srcStride, rgb2yuv);
+    }
+}
+
+void ff_rgb24tobgr24_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_rgb32tobgr24_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_rgb24tobgr32_neon(const uint8_t *src, uint8_t *dst, int src_size);
+
+void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
+                              uint8_t *dest, int width, int height,
+                              int src1Stride, int src2Stride, int dstStride);
+void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
+                                int width, int height, int srcStride,
+                                int dst1Stride, int dst2Stride);
+void ff_shuffle_bytes_0321_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2103_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1230_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3012_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3210_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3102_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2013_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2130_neon(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1203_neon(const uint8_t *src, uint8_t *dst, int src_size);
+
+void ff_uyvytoyuv422_neon(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_uyvytoyuv420_neon(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_yuyvtoyuv420_neon(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_yuyvtoyuv422_neon(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
+                          const uint8_t *src, int width, int height,
+                          int lumStride, int chromStride, int srcStride);
+av_cold void rgb2rgb_init_aarch64(void)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_neon(cpu_flags)) {
+        ff_rgb24toyv12  = rgb24toyv12;
+        rgb24tobgr24    = ff_rgb24tobgr24_neon;
+        rgb32tobgr24    = ff_rgb32tobgr24_neon;
+        rgb24tobgr32    = ff_rgb24tobgr32_neon;
+        interleaveBytes = ff_interleave_bytes_neon;
+        deinterleaveBytes = ff_deinterleave_bytes_neon;
+        shuffle_bytes_0321 = ff_shuffle_bytes_0321_neon;
+        shuffle_bytes_1230 = ff_shuffle_bytes_1230_neon;
+        shuffle_bytes_2103 = ff_shuffle_bytes_2103_neon;
+        shuffle_bytes_3012 = ff_shuffle_bytes_3012_neon;
+        shuffle_bytes_3210 = ff_shuffle_bytes_3210_neon;
+        shuffle_bytes_3102 = ff_shuffle_bytes_3102_neon;
+        shuffle_bytes_2013 = ff_shuffle_bytes_2013_neon;
+        shuffle_bytes_2130 = ff_shuffle_bytes_2130_neon;
+        shuffle_bytes_1203 = ff_shuffle_bytes_1203_neon;
+        uyvytoyuv422       = ff_uyvytoyuv422_neon;
+        uyvytoyuv420       = ff_uyvytoyuv420_neon;
+        yuyvtoyuv422       = ff_yuyvtoyuv422_neon;
+        yuyvtoyuv420       = ff_yuyvtoyuv420_neon;
+    }
+}
diff --git a/libs/ffmpeg/libswscale/aarch64/rgb2rgb_neon.S b/libs/ffmpeg/libswscale/aarch64/rgb2rgb_neon.S
new file mode 100644
index 000000000000..665aa4496b5a
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/rgb2rgb_neon.S
@@ -0,0 +1,873 @@
+/*
+ * Copyright (c) 2020 Martin Storsjo
+ * Copyright (c) 2024 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/aarch64/asm.S"
+
+#define RGB2YUV_COEFFS 16*4+16*32
+#define BY v0.h[0]
+#define GY v0.h[1]
+#define RY v0.h[2]
+#define BU v1.h[0]
+#define GU v1.h[1]
+#define RU v1.h[2]
+#define BV v2.h[0]
+#define GV v2.h[1]
+#define RV v2.h[2]
+#define Y_OFFSET  v22
+#define UV_OFFSET v23
+
+const shuf_0321_tbl, align=4
+        .byte  0,  3,  2,  1
+        .byte  4,  7,  6,  5
+        .byte  8,  11, 10, 9
+        .byte  12, 15, 14, 13
+endconst
+
+const shuf_1230_tbl, align=4
+        .byte  1,  2,  3,  0
+        .byte  5,  6,  7,  4
+        .byte  9,  10, 11, 8
+        .byte  13, 14, 15, 12
+endconst
+
+const shuf_2103_tbl, align=4
+        .byte  2,  1,  0,  3
+        .byte  6,  5,  4,  7
+        .byte  10, 9,  8,  11
+        .byte  14, 13, 12, 15
+endconst
+
+const shuf_3012_tbl, align=4
+        .byte  3,  0,  1,  2
+        .byte  7,  4,  5,  6
+        .byte  11, 8,  9,  10
+        .byte  15, 12, 13, 14
+endconst
+
+const shuf_3210_tbl, align=4
+        .byte  3,  2,  1,  0
+        .byte  7,  6,  5,  4
+        .byte  11, 10, 9,  8
+        .byte  15, 14, 13, 12
+endconst
+
+const shuf_3102_tbl, align=4
+        .byte  3,  1,  0,  2
+        .byte  7,  5,  4,  6
+        .byte  11, 9,  8,  10
+        .byte  15, 13, 12, 14
+endconst
+
+const shuf_2013_tbl, align=4
+        .byte  2,  0,  1,  3
+        .byte  6,  4,  5,  7
+        .byte  10, 8,  9,  11
+        .byte  14, 12, 13, 15
+endconst
+
+const shuf_1203_tbl, align=4
+        .byte  1,  2,  0,  3
+        .byte  5,  6,  4,  7
+        .byte  9,  10, 8,  11
+        .byte  13, 14, 12, 15
+endconst
+
+const shuf_2130_tbl, align=4
+        .byte  2,  1,  3,  0
+        .byte  6,  5,  7,  4
+        .byte  10, 9,  11, 8
+        .byte  14, 13, 15, 12
+endconst
+
+// rgb32tobgr24: tbl indices for 2-register sliding window (ldp+tbl+stp approach)
+// Converts 16 BGRA pixels (64 bytes) to 16 BGR pixels (48 bytes) by dropping alpha.
+// Each 16-byte output register selects 3-of-4 bytes from a {Vn, Vn+1} pair.
+const rgb32tobgr24_tbl, align=4
+        // out0 from {v0,v1}: pixels 0-5⅓ → B0 G0 R0 B1 G1 R1 B2 G2 R2 B3 G3 R3 B4 G4 R4 B5
+        .byte  0,  1,  2,  4,  5,  6,  8,  9, 10, 12, 13, 14, 16, 17, 18, 20
+        // out1 from {v1,v2}: pixels 5⅓-10⅔ → G5 R5 B6 G6 R6 B7 G7 R7 B8 G8 R8 B9 G9 R9 B10 G10
+        .byte  5,  6,  8,  9, 10, 12, 13, 14, 16, 17, 18, 20, 21, 22, 24, 25
+        // out2 from {v2,v3}: pixels 10⅔-15 → R10 B11 G11 R11 B12 G12 R12 B13 G13 R13 B14 G14 R14 B15 G15 R15
+        .byte 10, 12, 13, 14, 16, 17, 18, 20, 21, 22, 24, 25, 26, 28, 29, 30
+endconst
+
+// rgb24tobgr32: tbl indices for sliding window (ldp+tbl+orr+stp approach)
+// Converts 16 BGR pixels (48 bytes) to 16 BGRA pixels (64 bytes) by inserting alpha=255.
+// Out-of-range index 128 produces 0 from tbl; orr with alpha mask fills in 0xFF.
+const rgb24tobgr32_tbl, align=4
+        // out0 from {v0}: pixels 0-3 → B0 G0 R0 _ B1 G1 R1 _ B2 G2 R2 _ B3 G3 R3 _
+        .byte  0,  1,  2, 128,  3,  4,  5, 128,  6,  7,  8, 128,  9, 10, 11, 128
+        // out1 from {v0,v1}: pixels 4-7 → B4 G4 R4 _ B5 G5 R5 _ B6 G6 R6 _ B7 G7 R7 _
+        .byte 12, 13, 14, 128, 15, 16, 17, 128, 18, 19, 20, 128, 21, 22, 23, 128
+        // out2 from {v1,v2}: pixels 8-11 → B8 G8 R8 _ B9 G9 R9 _ B10 G10 R10 _ B11 G11 R11 _
+        .byte  8,  9, 10, 128, 11, 12, 13, 128, 14, 15, 16, 128, 17, 18, 19, 128
+        // out3 from {v2}: pixels 12-15 → B12 G12 R12 _ B13 G13 R13 _ B14 G14 R14 _ B15 G15 R15 _
+        .byte  4,  5,  6, 128,  7,  8,  9, 128, 10, 11, 12, 128, 13, 14, 15, 128
+endconst
+
+// convert rgb to 16-bit y, u, or v
+// uses v3 and v4
+
+.macro rgbconv16 dst, b, g, r, bc, gc, rc, shr_bits
+        smull           v3.4s, \b\().4h, \bc
+        smlal           v3.4s, \g\().4h, \gc
+        smlal           v3.4s, \r\().4h, \rc
+        smull2          v4.4s, \b\().8h, \bc
+        smlal2          v4.4s, \g\().8h, \gc
+        smlal2          v4.4s, \r\().8h, \rc        // v3:v4 = b * bc + g * gc + r * rc (32-bit)
+        shrn            \dst\().4h, v3.4s, \shr_bits
+        shrn2           \dst\().8h, v4.4s, \shr_bits       // dst = b * bc + g * gc + r * rc (16-bit)
+.endm
+
+// void ff_rgb24toyv12_neon(const uint8_t *src, uint8_t *ydst, uint8_t *udst,
+//                          uint8_t *vdst, int width, int height, int lumStride,
+//                          int chromStride, int srcStride, int32_t *rgb2yuv);
+function ff_rgb24toyv12_neon, export=1
+// x0  const uint8_t *src
+// x1  uint8_t *ydst
+// x2  uint8_t *udst
+// x3  uint8_t *vdst
+// w4  int width
+// w5  int height
+// w6  int lumStride
+// w7  int chromStride
+        ldrsw           x14, [sp]
+        ldr             x15, [sp, #8]
+// x14 int srcStride
+// x15 int32_t *rgb2yuv
+
+        // extend width and stride parameters
+        uxtw            x4, w4
+        sxtw            x6, w6
+        sxtw            x7, w7
+
+        // src1 = x0
+        // src2 = x10
+        add             x10, x0,  x14               // x10 = src + srcStride
+        lsl             x14, x14, #1                // srcStride *= 2
+        add             x11, x4,  x4, lsl #1        // x11 = 3 * width
+        sub             x14, x14, x11               // srcPadding = (2 * srcStride) - (3 * width)
+
+        // ydst1 = x1
+        // ydst2 = x11
+        add             x11, x1,  x6                // x11 = ydst + lumStride
+        lsl             x6,  x6,  #1                // lumStride *= 2
+        sub             x6,  x6,  x4                // lumPadding = (2 * lumStride) - width
+
+        sub             x7,  x7,  x4, lsr #1        // chromPadding = chromStride - (width / 2)
+
+        // load rgb2yuv coefficients into v0, v1, and v2
+        add             x15, x15, #RGB2YUV_COEFFS
+        ld1             {v0.8h-v2.8h}, [x15]        // load 24 values
+
+        // load offset constants
+        movi            Y_OFFSET.8h,  #0x10, lsl #8
+        movi            UV_OFFSET.8h, #0x80, lsl #8
+
+1:
+        mov             w15, w4                     // w15 = width
+
+2:
+        // load first line
+        ld3             {v26.16b, v27.16b, v28.16b}, [x0], #48
+
+        // widen first line to 16-bit
+        uxtl            v16.8h, v26.8b              // v16 = B11
+        uxtl            v17.8h, v27.8b              // v17 = G11
+        uxtl            v18.8h, v28.8b              // v18 = R11
+        uxtl2           v19.8h, v26.16b             // v19 = B12
+        uxtl2           v20.8h, v27.16b             // v20 = G12
+        uxtl2           v21.8h, v28.16b             // v21 = R12
+
+        // calculate Y values for first line
+        rgbconv16       v24, v16, v17, v18, BY, GY, RY, #7 // v24 = Y11
+        rgbconv16       v25, v19, v20, v21, BY, GY, RY, #7 // v25 = Y12
+
+        // load second line
+        ld3             {v26.16b, v27.16b, v28.16b}, [x10], #48
+
+        // pairwise add and save rgb values to calculate average
+        addp            v5.8h, v16.8h, v19.8h
+        addp            v6.8h, v17.8h, v20.8h
+        addp            v7.8h, v18.8h, v21.8h
+
+        // widen second line to 16-bit
+        uxtl            v16.8h, v26.8b              // v16 = B21
+        uxtl            v17.8h, v27.8b              // v17 = G21
+        uxtl            v18.8h, v28.8b              // v18 = R21
+        uxtl2           v19.8h, v26.16b             // v19 = B22
+        uxtl2           v20.8h, v27.16b             // v20 = G22
+        uxtl2           v21.8h, v28.16b             // v21 = R22
+
+        // calculate Y values for second line
+        rgbconv16       v26, v16, v17, v18, BY, GY, RY, #7 // v26 = Y21
+        rgbconv16       v27, v19, v20, v21, BY, GY, RY, #7 // v27 = Y22
+
+        // pairwise add rgb values to calculate average
+        addp            v16.8h, v16.8h, v19.8h
+        addp            v17.8h, v17.8h, v20.8h
+        addp            v18.8h, v18.8h, v21.8h
+
+        // calculate sum of r, g, b components in 2x2 blocks
+        add             v16.8h, v16.8h, v5.8h
+        add             v17.8h, v17.8h, v6.8h
+        add             v18.8h, v18.8h, v7.8h
+
+        // calculate U and V values
+        rgbconv16       v28, v16, v17, v18, BU, GU, RU, #9 // v28 = U
+        rgbconv16       v29, v16, v17, v18, BV, GV, RV, #9 // v29 = V
+
+        // add offsets and narrow all values
+        addhn           v24.8b, v24.8h, Y_OFFSET.8h
+        addhn           v25.8b, v25.8h, Y_OFFSET.8h
+        addhn           v26.8b, v26.8h, Y_OFFSET.8h
+        addhn           v27.8b, v27.8h, Y_OFFSET.8h
+        addhn           v28.8b, v28.8h, UV_OFFSET.8h
+        addhn           v29.8b, v29.8h, UV_OFFSET.8h
+
+        subs            w15, w15, #16
+
+        // store output
+        st1             {v24.8b, v25.8b}, [x1], #16 // store ydst1
+        st1             {v26.8b, v27.8b}, [x11], #16 // store ydst2
+        st1             {v28.8b}, [x2], #8          // store udst
+        st1             {v29.8b}, [x3], #8          // store vdst
+
+        b.gt            2b
+
+        subs            w5,  w5,  #2
+
+        // row += 2
+        add             x0,  x0,  x14               // src1  += srcPadding
+        add             x10, x10, x14               // src2  += srcPadding
+        add             x1,  x1,  x6                // ydst1 += lumPadding
+        add             x11, x11, x6                // ydst2 += lumPadding
+        add             x2,  x2,  x7                // udst  += chromPadding
+        add             x3,  x3,  x7                // vdst  += chromPadding
+        b.gt            1b
+
+        ret
+endfunc
+
+// void ff_rgb24tobgr24_neon(const uint8_t *src, uint8_t *dst, int src_size);
+function ff_rgb24tobgr24_neon, export=1
+        // x0 = src, x1 = dst, w2 = src_size (bytes)
+
+        // Fast path: 48 bytes (16 pixels) per iteration
+        subs            w2, w2, #48
+        b.lt            2f
+1:
+        ld3             {v0.16b, v1.16b, v2.16b}, [x0], #48
+        subs            w2, w2, #48
+        mov             v3.16b, v0.16b
+        mov             v0.16b, v2.16b
+        mov             v2.16b, v3.16b
+        st3             {v0.16b, v1.16b, v2.16b}, [x1], #48
+        b.ge            1b
+2:
+        add             w2, w2, #48
+        // Medium path: 24 bytes (8 pixels)
+        cmp             w2, #24
+        b.lt            3f
+        ld3             {v0.8b, v1.8b, v2.8b}, [x0], #24
+        sub             w2, w2, #24
+        mov             v3.8b, v0.8b
+        mov             v0.8b, v2.8b
+        mov             v2.8b, v3.8b
+        st3             {v0.8b, v1.8b, v2.8b}, [x1], #24
+3:
+        // Scalar tail: 3 bytes (1 pixel) at a time
+        cmp             w2, #3
+        b.lt            4f
+5:
+        ldrb            w4, [x0, #1]
+        ldrb            w5, [x0, #2]
+        ldrb            w3, [x0], #3
+        subs            w2, w2, #3
+        strb            w4, [x1, #1]
+        strb            w3, [x1, #2]
+        strb            w5, [x1], #3
+        b.gt            5b
+4:
+        ret
+endfunc
+
+// void ff_rgb32tobgr24_neon(const uint8_t *src, uint8_t *dst, int src_size);
+function ff_rgb32tobgr24_neon, export=1
+        // x0 = src (BGRA), x1 = dst (BGR), w2 = src_size (bytes)
+
+        // Load 3 tbl permutation masks for 2-register sliding window
+        movrel          x3, rgb32tobgr24_tbl
+        ld1             {v16.16b, v17.16b, v18.16b}, [x3]
+
+        // Fast path: 64 bytes input (16 pixels) → 48 bytes output
+        // Uses ldp+tbl(2-reg sliding window)+stp to avoid expensive ld4/st3.
+        // Post-indexed addressing eliminates pointer-advance instructions.
+        // subs placed between loads and tbl to fill load-latency gap on
+        // in-order cores (A55).
+        subs            w2, w2, #64
+        b.lt            2f
+1:
+        ldp             q0, q1, [x0], #64
+        ldp             q2, q3, [x0, #-32]
+        subs            w2, w2, #64
+        tbl             v4.16b, {v0.16b, v1.16b}, v16.16b
+        tbl             v5.16b, {v1.16b, v2.16b}, v17.16b
+        tbl             v6.16b, {v2.16b, v3.16b}, v18.16b
+        stp             q4, q5, [x1], #48
+        str             q6, [x1, #-16]
+        b.ge            1b
+2:
+        add             w2, w2, #64
+        // Medium path: 32 bytes input (8 pixels) → 24 bytes output
+        cmp             w2, #32
+        b.lt            3f
+        ld4             {v0.8b, v1.8b, v2.8b, v3.8b}, [x0], #32
+        sub             w2, w2, #32
+        st3             {v0.8b, v1.8b, v2.8b}, [x1], #24
+3:
+        // Scalar tail: 4 bytes → 3 bytes at a time
+        // Uses word load + halfword/byte stores to reduce instructions.
+        // On LE: ldr gives A<<24|R<<16|G<<8|B; strh stores [B,G]; lsr+strb stores R.
+        // subs and lsr fill load-use latency. lsr uses a fresh register so
+        // strh and strb can issue independently; add advances x1 off critical path.
+        cmp             w2, #4
+        b.lt            4f
+5:
+        ldr             w3, [x0], #4
+        subs            w2, w2, #4
+        lsr             w4, w3, #16
+        strh            w3, [x1]
+        strb            w4, [x1, #2]
+        add             x1, x1, #3
+        b.gt            5b
+4:
+        ret
+endfunc
+
+// void ff_rgb24tobgr32_neon(const uint8_t *src, uint8_t *dst, int src_size);
+function ff_rgb24tobgr32_neon, export=1
+        // x0 = src (BGR), x1 = dst (BGRA), w2 = src_size (bytes)
+
+        // Load tbl permutation indices and alpha mask for the fast path
+        movrel          x3, rgb24tobgr32_tbl
+        ld1             {v16.16b, v17.16b, v18.16b, v19.16b}, [x3]
+        movi            v20.4s, #255, lsl #24             // Alpha mask: 00 00 00 FF per pixel
+
+        // Fast path: 48 bytes input (16 pixels) → 64 bytes output
+        // Uses ldp+tbl+orr+stp to avoid expensive ld3/st4 structure load/stores.
+        // tbl produces 0 for alpha positions; orr fills in 0xFF.
+        // Post-indexed addressing eliminates pointer-advance instructions.
+        // tbl/orr interleaved so each orr starts as soon as its tbl result
+        // is ready, hiding latency on narrow in-order cores (A55).
+        subs            w2, w2, #48
+        b.lt            2f
+1:
+        ldp             q0, q1, [x0], #48
+        ldr             q2, [x0, #-16]
+        subs            w2, w2, #48
+        tbl             v4.16b, {v0.16b}, v16.16b
+        tbl             v5.16b, {v0.16b, v1.16b}, v17.16b
+        orr             v4.16b, v4.16b, v20.16b
+        tbl             v6.16b, {v1.16b, v2.16b}, v18.16b
+        orr             v5.16b, v5.16b, v20.16b
+        tbl             v7.16b, {v2.16b}, v19.16b
+        orr             v6.16b, v6.16b, v20.16b
+        stp             q4, q5, [x1], #64
+        orr             v7.16b, v7.16b, v20.16b
+        stp             q6, q7, [x1, #-32]
+        b.ge            1b
+2:
+        add             w2, w2, #48
+        // Medium path: 24 bytes input (8 pixels) → 32 bytes output
+        cmp             w2, #24
+        b.lt            3f
+        movi            v3.8b, #255
+        ld3             {v0.8b, v1.8b, v2.8b}, [x0], #24
+        sub             w2, w2, #24
+        st4             {v0.8b, v1.8b, v2.8b, v3.8b}, [x1], #32
+3:
+        // Scalar tail: 3 bytes → 4 bytes at a time
+        // Uses halfword+byte loads, orr to combine with alpha, word store.
+        // On LE: ldrh gives G<<8|B, ldrb gives R; orr assembles 0xFF<<24|R<<16|G<<8|B;
+        // str stores [B,G,R,0xFF]. subs and add placed between loads and first
+        // orr to fill load-use latency on A55.
+        cmp             w2, #3
+        b.lt            4f
+5:
+        ldrh            w4, [x0]
+        ldrb            w5, [x0, #2]
+        add             x0, x0, #3
+        subs            w2, w2, #3
+        orr             w4, w4, w5, lsl #16
+        orr             w4, w4, #0xFF000000
+        str             w4, [x1], #4
+        b.gt            5b
+4:
+        ret
+endfunc
+
+// void ff_interleave_bytes_neon(const uint8_t *src1, const uint8_t *src2,
+//                               uint8_t *dest, int width, int height,
+//                               int src1Stride, int src2Stride, int dstStride);
+function ff_interleave_bytes_neon, export=1
+        sub             w5,  w5,  w3
+        sub             w6,  w6,  w3
+        sub             w7,  w7,  w3, lsl #1
+1:
+        ands            w8,  w3,  #0xfffffff0 // & ~15
+        b.eq            3f
+2:
+        ld1             {v0.16b}, [x0], #16
+        ld1             {v1.16b}, [x1], #16
+        subs            w8,  w8,  #16
+        st2             {v0.16b, v1.16b}, [x2], #32
+        b.gt            2b
+
+        tst             w3,  #15
+        b.eq            9f
+
+3:
+        tst             w3,  #8
+        b.eq            4f
+        ld1             {v0.8b}, [x0], #8
+        ld1             {v1.8b}, [x1], #8
+        st2             {v0.8b, v1.8b}, [x2], #16
+4:
+        tst             w3,  #4
+        b.eq            5f
+
+        ld1             {v0.s}[0], [x0], #4
+        ld1             {v1.s}[0], [x1], #4
+        zip1            v0.8b,   v0.8b,   v1.8b
+        st1             {v0.8b}, [x2], #8
+
+5:
+        ands            w8,  w3,  #3
+        b.eq            9f
+6:
+        ldrb            w9,  [x0], #1
+        ldrb            w10, [x1], #1
+        subs            w8,  w8,  #1
+        bfi             w9,  w10, #8,  #8
+        strh            w9,  [x2], #2
+        b.gt            6b
+
+9:
+        subs            w4,  w4,  #1
+        b.eq            0f
+        add             x0,  x0,  w5, sxtw
+        add             x1,  x1,  w6, sxtw
+        add             x2,  x2,  w7, sxtw
+        b               1b
+
+0:
+        ret
+endfunc
+
+// void ff_deinterleave_bytes_neon(const uint8_t *src, uint8_t *dst1, uint8_t *dst2,
+//                                 int width, int height, int srcStride,
+//                                 int dst1Stride, int dst2Stride);
+function ff_deinterleave_bytes_neon, export=1
+        sub             w5,  w5,  w3, lsl #1
+        sub             w6,  w6,  w3
+        sub             w7,  w7,  w3
+1:
+        ands            w8,  w3,  #0xfffffff0 // & ~15
+        b.eq            3f
+2:
+        ld2             {v0.16b, v1.16b}, [x0], #32
+        subs            w8,  w8,  #16
+        st1             {v0.16b}, [x1], #16
+        st1             {v1.16b}, [x2], #16
+        b.gt            2b
+
+        tst             w3,  #15
+        b.eq            9f
+
+3:
+        tst             w3,  #8
+        b.eq            4f
+        ld2             {v0.8b, v1.8b}, [x0], #16
+        st1             {v0.8b}, [x1], #8
+        st1             {v1.8b}, [x2], #8
+4:
+        tst             w3,  #4
+        b.eq            5f
+
+        ld1             {v0.8b}, [x0], #8
+        shrn            v1.8b,   v0.8h, #8
+        xtn             v0.8b,   v0.8h
+        st1             {v0.s}[0], [x1], #4
+        st1             {v1.s}[0], [x2], #4
+
+5:
+        ands            w8,  w3,  #3
+        b.eq            9f
+6:
+        ldrh            w9,  [x0], #2
+        subs            w8,  w8,  #1
+        ubfx            w10, w9,  #8,  #8
+        strb            w9,  [x1], #1
+        strb            w10, [x2], #1
+        b.gt            6b
+
+9:
+        subs            w4,  w4,  #1
+        b.eq            0f
+        add             x0,  x0,  w5, sxtw
+        add             x1,  x1,  w6, sxtw
+        add             x2,  x2,  w7, sxtw
+        b               1b
+
+0:
+        ret
+endfunc
+
+.macro neon_shuf shuf
+function ff_shuffle_bytes_\shuf\()_neon, export=1
+        movrel          x9, shuf_\shuf\()_tbl
+        ld1             {v1.16b}, [x9]
+        and             w5, w2, #~15
+        and             w3, w2, #8
+        and             w4, w2, #4
+        cbz             w5, 2f
+1:
+        ld1             {v0.16b}, [x0], #16
+        subs            w5, w5, #16
+        tbl             v0.16b, {v0.16b}, v1.16b
+        st1             {v0.16b}, [x1], #16
+        b.gt            1b
+2:
+        cbz             w3, 3f
+        ld1             {v0.8b}, [x0], #8
+        tbl             v0.8b, {v0.16b}, v1.8b
+        st1             {v0.8b}, [x1], #8
+3:
+        cbz             w4, 4f
+.if \shuf == 0321
+        ldr             w5, [x0]
+        rev             w5, w5
+        ror             w5, w5, #24
+        str             w5, [x1]
+.endif
+.if \shuf == 1230
+        ldr             w5, [x0]
+        ror             w5, w5, #8
+        str             w5, [x1]
+.endif
+.if \shuf == 2103
+        ldr             w5, [x0]
+        rev             w5, w5
+        ror             w5, w5, #8
+        str             w5, [x1]
+.endif
+.if \shuf == 3012
+        ldr             w5, [x0]
+        ror             w5, w5, #24
+        str             w5, [x1]
+.endif
+.if \shuf == 3210
+        ldr             w5, [x0]
+        rev             w5, w5
+        str             w5, [x1]
+.endif
+.if \shuf == 3102 || \shuf == 2013 || \shuf == 1203 || \shuf == 2130
+        ld1             {v0.s}[0], [x0]
+        tbl             v0.8b, {v0.16b}, v1.8b
+        st1             {v0.s}[0], [x1]
+.endif
+4:
+        ret
+endfunc
+.endm
+
+neon_shuf 0321
+neon_shuf 1230
+neon_shuf 2103
+neon_shuf 3012
+neon_shuf 3102
+neon_shuf 2013
+neon_shuf 1203
+neon_shuf 2130
+neon_shuf 3210
+
+/*
+v0-v7 - two consecutive lines
+x0 - upper Y destination
+x1 - U destination
+x2 - V destination
+x3 - upper src line
+w5 - width/iteration counter - count of line pairs for yuv420, of single lines for 422
+x6 - lum padding
+x7 - chrom padding
+x8 - src padding
+w9 - number of bytes remaining in the tail
+x10 - lower Y destination
+w12 - tmp
+x13 - lower src line
+w14 - tmp
+w17 - set to 1 if last line has to be handled separately (odd height)
+*/
+
+// one fast path iteration processes 16 uyvy tuples
+// is_line_tail is set to 1 when final 16 tuples are being processed
+// skip_storing_chroma is set to 1 when final line is processed and the height is odd
+.macro fastpath_iteration src_fmt, dst_fmt, is_line_tail, skip_storing_chroma
+        ld4             {v0.16b - v3.16b}, [x3], #64
+.if ! \is_line_tail
+        subs            w14, w14, #32
+.endif
+
+.if ! \skip_storing_chroma
+.ifc \dst_fmt, yuv420
+        ld4             {v4.16b - v7.16b}, [x13], #64
+.endif
+
+.ifc \dst_fmt, yuv420                                    // store UV
+.ifc \src_fmt, uyvy
+        uhadd           v0.16b, v4.16b, v0.16b            // halving sum of U
+        uhadd           v2.16b, v6.16b, v2.16b            // halving sum of V
+.else
+        uhadd           v1.16b, v5.16b, v1.16b            // halving sum of U
+        uhadd           v3.16b, v7.16b, v3.16b            // halving sum of V
+.endif
+.endif
+
+.ifc \src_fmt, uyvy
+        st1             {v2.16b}, [x2], #16
+        st1             {v0.16b}, [x1], #16
+.else
+        st1             {v3.16b}, [x2], #16
+        st1             {v1.16b}, [x1], #16
+.endif
+
+.ifc \dst_fmt, yuv420                                    // store_y
+.ifc \src_fmt, uyvy
+        mov             v6.16b, v5.16b
+        st2             {v6.16b,v7.16b}, [x10], #32
+.else
+        mov             v5.16b, v4.16b
+        st2             {v5.16b,v6.16b}, [x10], #32
+.endif
+.endif
+
+.endif // ! \skip_storing_chroma
+
+.ifc \src_fmt, uyvy
+        mov             v2.16b, v1.16b
+        st2             {v2.16b,v3.16b}, [x0], #32
+.else
+        mov             v1.16b, v0.16b
+        st2             {v1.16b,v2.16b}, [x0], #32
+.endif
+.endm
+
+// shift pointers back to width - 32 to process the tail of the line
+// if the height is odd, processing the final line is simplified
+.macro fastpath_shift_back_pointers src_fmt, dst_fmt, is_final_odd_line
+        add             x3, x3, w9, sxtw #1
+        sub             x3, x3, #64
+.if ! \is_final_odd_line
+.ifc \dst_fmt, yuv420
+        add             x13, x13, w9, sxtw #1
+        sub             x13, x13, #64
+        add             x10, x10, w9, sxtw
+        sub             x10, x10, #32
+.endif
+.endif
+        add             x0, x0, w9, sxtw
+        sub             x0, x0, #32
+.if ! \is_final_odd_line
+        asr             w14, w9, #1
+        add             x1, x1, w14, sxtw
+        sub             x1, x1, #16
+        add             x2, x2, w14, sxtw
+        sub             x2, x2, #16
+.endif
+.endm
+
+.macro slowpath_iteration src_fmt, dst_fmt, skip_storing_chroma
+.ifc \dst_fmt, yuv422
+.ifc \src_fmt, uyvy
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x3], #1
+        strb            w12, [x1], #1
+        strb            w14, [x0], #1
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x3], #1
+        strb            w12, [x2], #1
+        strb            w14, [x0], #1
+.else
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x3], #1
+        strb            w12, [x0], #1
+        strb            w14, [x1], #1
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x3], #1
+        strb            w12, [x0], #1
+        strb            w14, [x2], #1
+.endif
+.endif
+.ifc \dst_fmt, yuv420
+.ifc \src_fmt, uyvy
+.if \skip_storing_chroma
+        ldrb            w12, [x3], #2
+        ldrb            w14, [x3], #2
+        strb            w12, [x0], #1
+        strb            w14, [x0], #1
+.else
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x13], #1
+        add             w12, w12, w14
+        lsr             w12, w12, #1
+        strb            w12, [x1], #1
+        ldrb            w14, [x3], #1
+        ldrb            w12, [x13], #1
+        strb            w14, [x0], #1
+        strb            w12, [x10], #1
+        ldrb            w14, [x13], #1
+        ldrb            w12, [x3], #1
+        add             w12, w12, w14
+        lsr             w12, w12, #1
+        strb            w12, [x2], #1
+        ldrb            w14, [x3], #1
+        ldrb            w12, [x13], #1
+        strb            w14, [x0], #1
+        strb            w12, [x10], #1
+.endif
+.else
+.if \skip_storing_chroma
+        ldrb            w12, [x3], #2
+        ldrb            w14, [x3], #2
+        strb            w12, [x0], #1
+        strb            w14, [x0], #1
+.else
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x13], #1
+        strb            w12, [x0], #1
+        strb            w14, [x10], #1
+        ldrb            w12, [x3], #1
+        ldrb            w14, [x13], #1
+        add             w12, w12, w14
+        lsr             w12, w12, #1
+        strb            w12, [x1], #1
+        ldrb            w14, [x3], #1
+        ldrb            w12, [x13], #1
+        strb            w14, [x0], #1
+        strb            w12, [x10], #1
+        ldrb            w14, [x13], #1
+        ldrb            w12, [x3], #1
+        add             w12, w12, w14
+        lsr             w12, w12, #1
+        strb            w12, [x2], #1
+.endif
+.endif
+.endif
+.endm
+
+.macro move_pointers_to_next_line src_fmt, dst_fmt, is_final_odd_line
+        add             x3, x3, x8
+        add             x0, x0, x6
+.ifc \dst_fmt, yuv420
+        add             x13, x13, x8
+        add             x10, x10, x6
+.endif
+        add             x1, x1, x7
+        add             x2, x2, x7
+.endm
+
+.macro interleaved_yuv_to_planar src_fmt, dst_fmt
+function ff_\src_fmt\()to\dst_fmt\()_neon, export=1
+        sxtw            x6, w6
+        sxtw            x7, w7
+        ldrsw           x8, [sp]
+        ands            w11, w4, #~31                     // choose between fast and slow path
+
+.ifc \dst_fmt, yuv420
+        add             x10, x0, x6
+        add             x13, x3, x8
+        add             x8, x8, x8
+        add             x6, x6, x6
+        and             w17, w5, #1
+        asr             w5, w5, #1
+.endif
+        asr             w9, w4, #1
+        sub             x8, x8, w4, sxtw #1               // src offset
+        sub             x6, x6, w4, sxtw                  // lum offset
+        sub             x7, x7, x9                        // chr offset
+
+        b.eq            6f
+
+1:                                                        // fast path - the width is at least 32
+        and             w14, w4, #~31                     // w14 is the main loop counter
+        and             w9, w4, #31                       // w9 holds the remaining width, 0 to 31
+2:
+        fastpath_iteration \src_fmt, \dst_fmt, 0, 0
+        b.ne            2b
+        fastpath_shift_back_pointers \src_fmt, \dst_fmt, 0
+        fastpath_iteration \src_fmt, \dst_fmt, 0, 0
+        subs            w5, w5, #1
+        move_pointers_to_next_line \src_fmt, \dst_fmt
+        b.ne            1b
+
+.ifc \dst_fmt, yuv420                                    // handle the last line in case the height is odd
+        cbz             w17, 3f
+        and             w14, w4, #~31
+4:
+        fastpath_iteration \src_fmt, \dst_fmt, 0, 1
+        b.ne            4b
+        fastpath_shift_back_pointers \src_fmt, \dst_fmt, 1
+        fastpath_iteration \src_fmt, \dst_fmt, 1, 1
+3:
+.endif
+        ret
+
+6:                                                        // slow path - width is at most 31
+        and             w9, w4, #31
+7:
+        subs            w9, w9, #2
+        slowpath_iteration \src_fmt, \dst_fmt, 0
+        b.ne            7b
+        subs            w5, w5, #1
+        move_pointers_to_next_line \src_fmt, \dst_fmt
+        b.ne            6b
+
+.ifc \dst_fmt, yuv420
+        cbz             w17, 8f
+        and             w9, w4, #31
+.ifc \src_fmt, uyvy
+        add             x3, x3, #1
+.endif
+5:
+        subs            w9, w9, #2
+        slowpath_iteration \src_fmt, \dst_fmt, 1
+        b.ne            5b
+8:
+.endif
+        ret
+endfunc
+.endm
+
+interleaved_yuv_to_planar uyvy, yuv422
+interleaved_yuv_to_planar uyvy, yuv420
+interleaved_yuv_to_planar yuyv, yuv422
+interleaved_yuv_to_planar yuyv, yuv420
diff --git a/libs/ffmpeg/libswscale/aarch64/swscale.c b/libs/ffmpeg/libswscale/aarch64/swscale.c
new file mode 100644
index 000000000000..4f86364f4bac
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/swscale.c
@@ -0,0 +1,436 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "libavutil/attributes.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/aarch64/cpu.h"
+#include "asm-offsets.h"
+
+#define SIZEOF_MEMBER(type, member) \
+    sizeof(((type*)0)->member)
+
+static_assert(offsetof(SwsLuts, in)  == SL_IN,  "struct layout mismatch");
+static_assert(offsetof(SwsLuts, out) == SL_OUT, "struct layout mismatch");
+
+static_assert(offsetof(SwsColorXform, gamma) == SCX_GAMMA,
+              "struct layout mismatch");
+static_assert(offsetof(SwsColorXform, mat) == SCX_MAT,
+              "struct layout mismatch");
+
+static_assert(offsetof(SwsColorXform, mat) +
+              2 * SIZEOF_MEMBER(SwsColorXform, mat[0]) +
+              2 * SIZEOF_MEMBER(SwsColorXform, mat[0][0]) == SCX_MAT_22,
+              "struct layout mismatch");
+
+void ff_xyz12Torgb48le_neon_asm(const SwsColorXform *c, uint8_t *dst,
+                                int dst_stride, const uint8_t *src,
+                                int src_stride, int w, int h);
+
+static void xyz12Torgb48le_neon(const SwsInternal *c, uint8_t *dst,
+                                int dst_stride, const uint8_t *src,
+                                int src_stride, int w, int h)
+{
+    ff_xyz12Torgb48le_neon_asm(&c->xyz2rgb, dst, dst_stride, src, src_stride,
+                               w, h);
+}
+
+void ff_hscale16to15_4_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+void ff_hscale16to15_X8_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+void ff_hscale16to15_X4_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+void ff_hscale16to19_4_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+void ff_hscale16to19_X8_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+void ff_hscale16to19_X4_neon_asm(int shift, int16_t *_dst, int dstW,
+                      const uint8_t *_src, const int16_t *filter,
+                      const int32_t *filterPos, int filterSize);
+
+static void ff_hscale16to15_4_neon(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 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;
+    }
+    ff_hscale16to15_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+
+}
+
+static void ff_hscale16to15_X8_neon(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 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;
+    }
+    ff_hscale16to15_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+
+}
+
+static void ff_hscale16to15_X4_neon(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 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;
+    }
+    ff_hscale16to15_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+}
+
+static void ff_hscale16to19_4_neon(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 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;
+    }
+
+    ff_hscale16to19_4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+
+}
+
+static void ff_hscale16to19_X8_neon(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 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;
+    }
+
+    ff_hscale16to19_X8_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+
+}
+
+static void ff_hscale16to19_X4_neon(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 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;
+    }
+
+    ff_hscale16to19_X4_neon_asm(sh, _dst, dstW, _src, filter, filterPos, filterSize);
+
+}
+
+#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
+void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
+                                                SwsInternal *c, int16_t *data, \
+                                                int dstW, const uint8_t *src, \
+                                                const int16_t *filter, \
+                                                const int32_t *filterPos, int filterSize)
+#define SCALE_FUNCS(filter_n, opt) \
+    SCALE_FUNC(filter_n, 8, 15, opt); \
+    SCALE_FUNC(filter_n, 8, 19, opt);
+#define ALL_SCALE_FUNCS(opt) \
+    SCALE_FUNCS(4, opt); \
+    SCALE_FUNCS(X8, opt); \
+    SCALE_FUNCS(X4, opt)
+
+ALL_SCALE_FUNCS(neon);
+
+void ff_yuv2planeX_10_neon(const int16_t *filter, int filterSize,
+                           const int16_t **src, uint16_t *dest, int dstW,
+                           int big_endian, int output_bits);
+
+#define yuv2NBPS(bits, BE_LE, is_be, template_size, typeX_t)                                    \
+static void yuv2planeX_ ## bits ## BE_LE ## _neon(const int16_t *filter, int filterSize,        \
+                                                  const int16_t **src, uint8_t *dest, int dstW, \
+                                                  const uint8_t *dither, int offset)            \
+{                                                                                               \
+    ff_yuv2planeX_## template_size ## _neon(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)
+
+void ff_yuv2planeX_8_neon(const int16_t *filter, int filterSize,
+                          const int16_t **src, uint8_t *dest, int dstW,
+                          const uint8_t *dither, int offset);
+void ff_yuv2plane1_8_neon(
+        const int16_t *src,
+        uint8_t *dest,
+        int dstW,
+        const uint8_t *dither,
+        int offset);
+
+void ff_yuv2nv12cX_neon_asm(int isSwapped, const uint8_t *chrDither,
+                            const int16_t *chrFilter, int chrFilterSize,
+                            const int16_t **chrUSrc, const int16_t **chrVSrc,
+                            uint8_t *dest, int chrDstW);
+
+static void ff_yuv2nv12cX_neon(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)
+{
+    if (!isSwappedChroma(dstFormat)) {
+        ff_yuv2nv12cX_neon_asm(1, chrDither, chrFilter, chrFilterSize,
+                               chrUSrc, chrVSrc, dest, chrDstW);
+    } else {
+        ff_yuv2nv12cX_neon_asm(0, chrDither, chrFilter, chrFilterSize,
+                               chrUSrc, chrVSrc, dest, chrDstW);
+    }
+}
+
+#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt) do {              \
+    if (c->srcBpc == 8) {                                               \
+        if(c->dstBpc <= 14) {                                           \
+            hscalefn =                                                  \
+                ff_hscale8to15_ ## filtersize ## _ ## opt;              \
+        } else                                                          \
+            hscalefn =                                                  \
+                ff_hscale8to19_ ## filtersize ## _ ## opt;              \
+    } else {                                                            \
+        if (c->dstBpc <= 14)                                            \
+            hscalefn =                                                  \
+                ff_hscale16to15_ ## filtersize ## _ ## opt;             \
+        else                                                            \
+            hscalefn =                                                  \
+                ff_hscale16to19_ ## filtersize ## _ ## opt;             \
+    }                                                                   \
+} while (0)
+
+#define ASSIGN_SCALE_FUNC(hscalefn, filtersize, opt) do {               \
+    if (filtersize == 4)                                                \
+        ASSIGN_SCALE_FUNC2(hscalefn, 4, opt);                           \
+    else if (filtersize % 8 == 0)                                       \
+        ASSIGN_SCALE_FUNC2(hscalefn, X8, opt);                          \
+    else if (filtersize % 4 == 0 && filtersize % 8 != 0)                \
+        ASSIGN_SCALE_FUNC2(hscalefn, X4, opt);                          \
+} while (0)
+
+#define ASSIGN_VSCALE_FUNC(vscalefn, opt)                               \
+    switch (c->dstBpc) {                                                \
+    case 8: vscalefn = ff_yuv2plane1_8_  ## opt;  break;                \
+    default: break;                                                     \
+    }
+
+#define NEON_INPUT(name) \
+void ff_##name##ToY_neon(uint8_t *dst, const uint8_t *src, const uint8_t *, \
+                        const uint8_t *, int w, uint32_t *coeffs, void *); \
+void ff_##name##ToUV_neon(uint8_t *, uint8_t *, const uint8_t *, \
+                         const uint8_t *, const uint8_t *, int w, \
+                         uint32_t *coeffs, void *); \
+void ff_##name##ToUV_half_neon(uint8_t *, uint8_t *, const uint8_t *, \
+                              const uint8_t *, const uint8_t *, int w, \
+                              uint32_t *coeffs, void *)
+#define NEON_INPUT_DOTPROD(name) \
+void ff_##name##ToY_neon_dotprod(uint8_t *dst, const uint8_t *src, const uint8_t *, \
+                                 const uint8_t *, int w, uint32_t *coeffs, void *);
+
+NEON_INPUT(abgr32);
+NEON_INPUT(argb32);
+NEON_INPUT(bgr24);
+NEON_INPUT(bgra32);
+NEON_INPUT(rgb24);
+NEON_INPUT(rgba32);
+NEON_INPUT_DOTPROD(bgra32);
+NEON_INPUT_DOTPROD(rgba32);
+
+void ff_lumRangeFromJpeg8_neon(int16_t *dst, int width,
+                               uint32_t coeff, int64_t offset);
+void ff_chrRangeFromJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
+                               uint32_t coeff, int64_t offset);
+void ff_lumRangeToJpeg8_neon(int16_t *dst, int width,
+                             uint32_t coeff, int64_t offset);
+void ff_chrRangeToJpeg8_neon(int16_t *dstU, int16_t *dstV, int width,
+                             uint32_t coeff, int64_t offset);
+void ff_lumRangeFromJpeg16_neon(int16_t *dst, int width,
+                                uint32_t coeff, int64_t offset);
+void ff_chrRangeFromJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
+                                uint32_t coeff, int64_t offset);
+void ff_lumRangeToJpeg16_neon(int16_t *dst, int width,
+                              uint32_t coeff, int64_t offset);
+void ff_chrRangeToJpeg16_neon(int16_t *dstU, int16_t *dstV, int width,
+                              uint32_t coeff, int64_t offset);
+
+av_cold void ff_sws_init_range_convert_aarch64(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_neon(cpu_flags)) {
+        if (c->dstBpc <= 14) {
+            if (c->opts.src_range) {
+                c->lumConvertRange = ff_lumRangeFromJpeg8_neon;
+                c->chrConvertRange = ff_chrRangeFromJpeg8_neon;
+            } else {
+                c->lumConvertRange = ff_lumRangeToJpeg8_neon;
+                c->chrConvertRange = ff_chrRangeToJpeg8_neon;
+            }
+        } else {
+            if (c->opts.src_range) {
+                c->lumConvertRange = ff_lumRangeFromJpeg16_neon;
+                c->chrConvertRange = ff_chrRangeFromJpeg16_neon;
+            } else {
+                c->lumConvertRange = ff_lumRangeToJpeg16_neon;
+                c->chrConvertRange = ff_chrRangeToJpeg16_neon;
+            }
+        }
+    }
+}
+
+av_cold void ff_sws_init_xyzdsp_aarch64(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_neon(cpu_flags)) {
+        if (!isBE(c->opts.src_format)) {
+            c->xyz12Torgb48 = xyz12Torgb48le_neon;
+        }
+    }
+}
+
+av_cold void ff_sws_init_swscale_aarch64(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+    enum AVPixelFormat dstFormat = c->opts.dst_format;
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(dstFormat);
+
+    if (have_neon(cpu_flags)) {
+        ASSIGN_SCALE_FUNC(c->hyScale, c->hLumFilterSize, neon);
+        ASSIGN_SCALE_FUNC(c->hcScale, c->hChrFilterSize, neon);
+        ASSIGN_VSCALE_FUNC(c->yuv2plane1, neon);
+        if (c->dstBpc == 8) {
+            c->yuv2planeX = ff_yuv2planeX_8_neon;
+            if (isSemiPlanarYUV(dstFormat) && !isDataInHighBits(dstFormat))
+                c->yuv2nv12cX = ff_yuv2nv12cX_neon;
+        }
+
+        if (isNBPS(dstFormat) && !isSemiPlanarYUV(dstFormat) && !isDataInHighBits(dstFormat)) {
+            if (desc->comp[0].depth == 9) {
+                c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_9BE_neon  : yuv2planeX_9LE_neon;
+            } else if (desc->comp[0].depth == 10) {
+                c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_10BE_neon  : yuv2planeX_10LE_neon;
+            } else if (desc->comp[0].depth == 12) {
+                c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_12BE_neon  : yuv2planeX_12LE_neon;
+            } else if (desc->comp[0].depth == 14) {
+                c->yuv2planeX = isBE(dstFormat) ? yuv2planeX_14BE_neon  : yuv2planeX_14LE_neon;
+            } else
+                av_assert0(0);
+        }
+        switch (c->opts.src_format) {
+        case AV_PIX_FMT_ABGR:
+            c->lumToYV12 = ff_abgr32ToY_neon;
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_abgr32ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_abgr32ToUV_neon;
+            break;
+
+        case AV_PIX_FMT_ARGB:
+            c->lumToYV12 = ff_argb32ToY_neon;
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_argb32ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_argb32ToUV_neon;
+            break;
+        case AV_PIX_FMT_BGR24:
+            c->lumToYV12 = ff_bgr24ToY_neon;
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_bgr24ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_bgr24ToUV_neon;
+            break;
+        case AV_PIX_FMT_BGRA:
+            c->lumToYV12 = ff_bgra32ToY_neon;
+#if HAVE_DOTPROD
+            if (have_dotprod(cpu_flags)) {
+                c->lumToYV12 = ff_bgra32ToY_neon_dotprod;
+            }
+#endif
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_bgra32ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_bgra32ToUV_neon;
+            break;
+        case AV_PIX_FMT_RGB24:
+            c->lumToYV12 = ff_rgb24ToY_neon;
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_rgb24ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_rgb24ToUV_neon;
+            break;
+        case AV_PIX_FMT_RGBA:
+            c->lumToYV12 = ff_rgba32ToY_neon;
+#if HAVE_DOTPROD
+            if (have_dotprod(cpu_flags)) {
+                c->lumToYV12 = ff_rgba32ToY_neon_dotprod;
+            }
+#endif
+            if (c->chrSrcHSubSample)
+                c->chrToYV12 = ff_rgba32ToUV_half_neon;
+            else
+                c->chrToYV12 = ff_rgba32ToUV_neon;
+            break;
+        default:
+            break;
+        }
+    }
+}
diff --git a/libs/ffmpeg/libswscale/aarch64/swscale_unscaled.c b/libs/ffmpeg/libswscale/aarch64/swscale_unscaled.c
new file mode 100644
index 000000000000..ba24775210f0
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/swscale_unscaled.c
@@ -0,0 +1,313 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/aarch64/cpu.h"
+
+#define YUV_TO_RGB_TABLE                                                                    \
+        c->yuv2rgb_v2r_coeff,                                                               \
+        c->yuv2rgb_u2g_coeff,                                                               \
+        c->yuv2rgb_v2g_coeff,                                                               \
+        c->yuv2rgb_u2b_coeff,                                                               \
+
+#define DECLARE_FF_YUVX_TO_RGBX_FUNCS(ifmt, ofmt)                                           \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcU, int linesizeU,                        \
+                                 const uint8_t *srcV, int linesizeV,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff);                                              \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                           \
+                                        dst[0] + srcSliceY * dstStride[0], dstStride[0],    \
+                                        src[0], srcStride[0],                               \
+                                        src[1], srcStride[1],                               \
+                                        src[2], srcStride[2],                               \
+                                        yuv2rgb_table,                                      \
+                                        c->yuv2rgb_y_offset >> 6,                           \
+                                        c->yuv2rgb_y_coeff);                                \
+}                                                                                           \
+
+#define DECLARE_FF_YUVX_TO_GBRP_FUNCS(ifmt, ofmt)                                           \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcU, int linesizeU,                        \
+                                 const uint8_t *srcV, int linesizeV,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff,                                               \
+                                 uint8_t *dst1, int linesize1,                              \
+                                 uint8_t *dst2, int linesize2);                             \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                           \
+                                        dst[0] + srcSliceY * dstStride[0], dstStride[0],    \
+                                        src[0], srcStride[0],                               \
+                                        src[1], srcStride[1],                               \
+                                        src[2], srcStride[2],                               \
+                                        yuv2rgb_table,                                      \
+                                        c->yuv2rgb_y_offset >> 6,                           \
+                                        c->yuv2rgb_y_coeff,                                 \
+                                        dst[1] + srcSliceY * dstStride[1], dstStride[1],    \
+                                        dst[2] + srcSliceY * dstStride[2], dstStride[2]);   \
+}                                                                                           \
+
+#define DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuvx)                                             \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, argb)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgba)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, abgr)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgra)                                                   \
+DECLARE_FF_YUVX_TO_GBRP_FUNCS(yuvx, gbrp)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgb24)                                                  \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgr24)                                                  \
+
+DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv420p)
+DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv422p)
+
+#define DECLARE_FF_YUVA420P_TO_RGBX_FUNCS(ofmt)                                            \
+int ff_yuva420p_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcU, int linesizeU,                        \
+                                 const uint8_t *srcV, int linesizeV,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset, int y_coeff,                                 \
+                                 const uint8_t *srcA, int linesizeA);                       \
+                                                                                            \
+static int yuva420p_to_##ofmt##_neon_wrapper(SwsInternal *c,                                \
+                                             const uint8_t *const src[],                    \
+                                             const int srcStride[], int srcSliceY,          \
+                                             int srcSliceH, uint8_t *const dst[],           \
+                                             const int dstStride[]) {                       \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    return ff_yuva420p_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                           \
+                                        dst[0] + srcSliceY * dstStride[0], dstStride[0],    \
+                                        src[0], srcStride[0],                               \
+                                        src[1], srcStride[1],                               \
+                                        src[2], srcStride[2],                               \
+                                        yuv2rgb_table,                                      \
+                                        c->yuv2rgb_y_offset >> 6,                           \
+                                        c->yuv2rgb_y_coeff,                                 \
+                                        src[3], srcStride[3]);                              \
+}
+
+DECLARE_FF_YUVA420P_TO_RGBX_FUNCS(argb)
+DECLARE_FF_YUVA420P_TO_RGBX_FUNCS(rgba)
+DECLARE_FF_YUVA420P_TO_RGBX_FUNCS(abgr)
+DECLARE_FF_YUVA420P_TO_RGBX_FUNCS(bgra)
+
+#define DECLARE_FF_NVX_TO_RGBX_FUNCS(ifmt, ofmt)                                            \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcC, int linesizeC,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff);                                              \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                           \
+                                        dst[0] + srcSliceY * dstStride[0], dstStride[0],    \
+                                        src[0], srcStride[0], src[1], srcStride[1],         \
+                                        yuv2rgb_table,                                      \
+                                        c->yuv2rgb_y_offset >> 6,                           \
+                                        c->yuv2rgb_y_coeff);                                \
+}                                                                                           \
+
+#define DECLARE_FF_NVX_TO_GBRP_FUNCS(ifmt, ofmt)                                            \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcC, int linesizeC,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff,                                               \
+                                 uint8_t *dst1, int linesize1,                              \
+                                 uint8_t *dst2, int linesize2);                             \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    return ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                           \
+                                        dst[0] + srcSliceY * dstStride[0], dstStride[0],    \
+                                        src[0], srcStride[0], src[1], srcStride[1],         \
+                                        yuv2rgb_table,                                      \
+                                        c->yuv2rgb_y_offset >> 6,                           \
+                                        c->yuv2rgb_y_coeff,                                 \
+                                        dst[1] + srcSliceY * dstStride[1], dstStride[1],    \
+                                        dst[2] + srcSliceY * dstStride[2], dstStride[2]);   \
+}                                                                                           \
+
+void ff_nv24_to_yuv420p_chroma_neon(uint8_t *dst1, int dstStride1,
+                                    uint8_t *dst2, int dstStride2,
+                                    const uint8_t *src, int srcStride,
+                                    int w, int h);
+
+static int nv24_to_yuv420p_neon_wrapper(SwsInternal *c, const uint8_t *const src[],
+                                        const int srcStride[], int srcSliceY, int srcSliceH,
+                                        uint8_t *const dst[], const int dstStride[])
+{
+    uint8_t *dst1 = dst[1] + dstStride[1] * srcSliceY / 2;
+    uint8_t *dst2 = dst[2] + dstStride[2] * srcSliceY / 2;
+
+    ff_copyPlane(src[0], srcStride[0], srcSliceY, srcSliceH, c->opts.src_w,
+                 dst[0], dstStride[0]);
+
+    if (c->opts.src_format == AV_PIX_FMT_NV24)
+        ff_nv24_to_yuv420p_chroma_neon(dst1, dstStride[1], dst2, dstStride[2],
+                                       src[1], srcStride[1], c->opts.src_w / 2,
+                                       srcSliceH);
+    else
+        ff_nv24_to_yuv420p_chroma_neon(dst2, dstStride[2], dst1, dstStride[1],
+                                       src[1], srcStride[1], c->opts.src_w / 2,
+                                       srcSliceH);
+
+    return srcSliceH;
+}
+
+#define DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nvx)                                               \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, argb)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgba)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, abgr)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgra)                                                     \
+DECLARE_FF_NVX_TO_GBRP_FUNCS(nvx, gbrp)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgb24)                                                    \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgr24)                                                    \
+
+DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv12)
+DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21)
+
+/* We need a 16 pixel width alignment. This constraint can easily be removed
+ * for input reading but for the output which is 4-bytes per pixel (RGBA) the
+ * assembly might be writing as much as 4*15=60 extra bytes at the end of the
+ * line, which won't fit the 32-bytes buffer alignment. */
+#define SET_FF_NVX_TO_RGBX_FUNC(ifmt, IFMT, ofmt, OFMT, accurate_rnd) do {                  \
+    if (c->opts.src_format == AV_PIX_FMT_##IFMT                                             \
+        && c->opts.dst_format == AV_PIX_FMT_##OFMT                                          \
+        && !(c->opts.src_h & 1)                                                             \
+        && !(c->opts.src_w & 15)                                                            \
+        && !accurate_rnd)                                                                   \
+        c->convert_unscaled = ifmt##_to_##ofmt##_neon_wrapper;                              \
+} while (0)
+
+#define SET_FF_NVX_TO_ALL_RGBX_FUNC(nvx, NVX, accurate_rnd) do {                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, argb, ARGB, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgba, RGBA, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, abgr, ABGR, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgra, BGRA, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, gbrp, GBRP, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgb24, RGB24, accurate_rnd);                          \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgr24, BGR24, accurate_rnd);                          \
+} while (0)
+
+static void get_unscaled_swscale_neon(SwsInternal *c) {
+    int accurate_rnd = c->opts.flags & SWS_ACCURATE_RND;
+
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(nv12, NV12, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(nv21, NV21, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv420p, YUV420P, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv422p, YUV422P, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuva420p, YUVA420P, argb, ARGB, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuva420p, YUVA420P, rgba, RGBA, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuva420p, YUVA420P, abgr, ABGR, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuva420p, YUVA420P, bgra, BGRA, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuv420p, YUVA420P, rgb24, RGB24, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuv420p, YUVA420P, bgr24, BGR24, accurate_rnd);
+    SET_FF_NVX_TO_RGBX_FUNC(yuv420p, YUVA420P, gbrp,  GBRP,  accurate_rnd);
+
+    if (c->opts.dst_format == AV_PIX_FMT_YUV420P &&
+        (c->opts.src_format == AV_PIX_FMT_NV24 || c->opts.src_format == AV_PIX_FMT_NV42) &&
+        !(c->opts.src_h & 1) && !(c->opts.src_w & 15) && !accurate_rnd)
+        c->convert_unscaled = nv24_to_yuv420p_neon_wrapper;
+}
+
+void ff_get_unscaled_swscale_aarch64(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+    if (have_neon(cpu_flags))
+        get_unscaled_swscale_neon(c);
+}
+
+av_cold SwsFunc ff_yuv2rgb_init_aarch64(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+    if (!have_neon(cpu_flags) ||
+        (c->opts.src_h & 1) || (c->opts.src_w & 15) ||
+        (c->opts.flags & SWS_ACCURATE_RND))
+        return NULL;
+
+    if (c->opts.src_format == AV_PIX_FMT_YUV420P) {
+        switch (c->opts.dst_format) {
+        case AV_PIX_FMT_ARGB:  return yuv420p_to_argb_neon_wrapper;
+        case AV_PIX_FMT_RGBA:  return yuv420p_to_rgba_neon_wrapper;
+        case AV_PIX_FMT_ABGR:  return yuv420p_to_abgr_neon_wrapper;
+        case AV_PIX_FMT_BGRA:  return yuv420p_to_bgra_neon_wrapper;
+        case AV_PIX_FMT_RGB24: return yuv420p_to_rgb24_neon_wrapper;
+        case AV_PIX_FMT_BGR24: return yuv420p_to_bgr24_neon_wrapper;
+        case AV_PIX_FMT_GBRP:  return yuv420p_to_gbrp_neon_wrapper;
+        }
+    } else if (c->opts.src_format == AV_PIX_FMT_YUVA420P) {
+        switch (c->opts.dst_format) {
+#if CONFIG_SWSCALE_ALPHA
+        case AV_PIX_FMT_ARGB:  return yuva420p_to_argb_neon_wrapper;
+        case AV_PIX_FMT_RGBA:  return yuva420p_to_rgba_neon_wrapper;
+        case AV_PIX_FMT_ABGR:  return yuva420p_to_abgr_neon_wrapper;
+        case AV_PIX_FMT_BGRA:  return yuva420p_to_bgra_neon_wrapper;
+#endif
+        case AV_PIX_FMT_RGB24: return yuv420p_to_rgb24_neon_wrapper;
+        case AV_PIX_FMT_BGR24: return yuv420p_to_bgr24_neon_wrapper;
+        case AV_PIX_FMT_GBRP:  return yuv420p_to_gbrp_neon_wrapper;
+        }
+    } else if (c->opts.src_format == AV_PIX_FMT_YUV422P) {
+        switch (c->opts.dst_format) {
+        case AV_PIX_FMT_ARGB:  return yuv422p_to_argb_neon_wrapper;
+        case AV_PIX_FMT_RGBA:  return yuv422p_to_rgba_neon_wrapper;
+        case AV_PIX_FMT_ABGR:  return yuv422p_to_abgr_neon_wrapper;
+        case AV_PIX_FMT_BGRA:  return yuv422p_to_bgra_neon_wrapper;
+        case AV_PIX_FMT_RGB24: return yuv422p_to_rgb24_neon_wrapper;
+        case AV_PIX_FMT_BGR24: return yuv422p_to_bgr24_neon_wrapper;
+        case AV_PIX_FMT_GBRP:  return yuv422p_to_gbrp_neon_wrapper;
+        }
+    }
+    return NULL;
+}
diff --git a/libs/ffmpeg/libswscale/aarch64/swscale_unscaled_neon.S b/libs/ffmpeg/libswscale/aarch64/swscale_unscaled_neon.S
new file mode 100644
index 000000000000..a074b187e512
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/swscale_unscaled_neon.S
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2024 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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/aarch64/asm.S"
+
+function ff_nv24_to_yuv420p_chroma_neon, export=1
+// x0  uint8_t *dst1
+// x1  int dstStride1
+// x2  uint8_t *dst2
+// x3  int dstStride2
+// x4  const uint8_t *src
+// x5  int srcStride
+// w6  int w
+// w7  int h
+
+        add             x9, x4, w5, sxtw            // x9 = src + srcStride
+        lsl             w5, w5, #1                  // srcStride *= 2
+        sub             w5, w5, w6, lsl #2          // srcPadding = (2 * srcStride) - (4 * w)
+        sub             w1, w1, w6                  // dstPadding1 = dstStride1 - w
+        sub             w3, w3, w6                  // dstPadding2 = dstStride2 - w
+
+1:
+        mov             w10, w6                     // w10 = w
+
+2:
+        ld2             {v0.16b, v1.16b}, [x4], #32 // v0 = U1, v1 = V1
+        ld2             {v2.16b, v3.16b}, [x9], #32 // v2 = U2, v3 = V2
+
+        uaddlp          v0.8h, v0.16b               // pairwise add U1 into v0
+        uaddlp          v1.8h, v1.16b               // pairwise add V1 into v1
+        uadalp          v0.8h, v2.16b               // pairwise add U2, accumulate into v0
+        uadalp          v1.8h, v3.16b               // pairwise add V2, accumulate into v1
+
+        shrn            v0.8b, v0.8h, #2            // divide by 4
+        shrn            v1.8b, v1.8h, #2            // divide by 4
+
+        st1             {v0.8b}, [x0], #8           // store U into dst1
+        st1             {v1.8b}, [x2], #8           // store V into dst2
+
+        subs            w10, w10, #8
+        b.gt            2b
+
+        // next row
+        add             x4, x4, w5, sxtw            // src1 += srcPadding
+        add             x9, x9, w5, sxtw            // src2 += srcPadding
+        add             x0, x0, w1, sxtw            // dst1 += dstPadding1
+        add             x2, x2, w3, sxtw            // dst2 += dstPadding2
+
+        subs            w7, w7, #2
+        b.gt            1b
+
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswscale/aarch64/xyz2rgb_neon.S b/libs/ffmpeg/libswscale/aarch64/xyz2rgb_neon.S
new file mode 100644
index 000000000000..4b2135085a55
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/xyz2rgb_neon.S
@@ -0,0 +1,702 @@
+/*
+ * Copyright (c) 2025 Arpad Panyik <Arpad.Panyik@arm.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/aarch64/asm.S"
+#include "asm-offsets.h"
+
+#define JUMP_ALIGN 2
+#define LOOP_ALIGN 2
+
+function ff_xyz12Torgb48le_neon_asm, export=1
+// x0  const SwsColorXform *c
+// x1  uint8_t *dst
+// w2  int dst_stride
+// x3  const uint8_t *src
+// w4  int src_stride
+// w5  int w
+// w6  int h
+
+        ldp             x7,  x8, [x0, #(SCX_GAMMA_IN)]  // gamma.in, gamma.out
+        ldr             q6,  [x0, #(SCX_MAT_00)]        // mat[0][0]..[2][1]
+        ldr             h7,  [x0, #(SCX_MAT_22)]        // mat[2][2]; > 0
+
+        add             w9,  w5,  w5, lsl #1        // w * 3
+        add             x17, x3,  w4, sxtw          // sr2 = src + src_stride
+        add             x16, x1,  w2, sxtw          // ds2 = dst + dst_stride
+        sub             w4,  w4,  w9                // src_stride - w * 3
+        sub             w2,  w2,  w9                // dst_stride - w * 3
+        abs             v6.8h,  v6.8h               // abs(mat[0][0]..[2][1])
+        sbfiz           x4,  x4,  #1, #32           // src_stride * 2 - w * 6
+        sbfiz           x2,  x2,  #1, #32           // dst_stride * 2 - w * 6
+
+        subs            w6,  w6,  #2
+        b.lt            6f                          // h < 2
+
+        stp             x19, x20, [sp, #-64]!
+        stp             x21, x22, [sp, #16]
+        stp             x23, x24, [sp, #32]
+        str             x25, [sp, #48]
+
+        .align LOOP_ALIGN
+1:      // yp loop for 2x4 pixels
+        subs            w0,  w5,  #4
+        b.lt            3f                          // w < 4
+
+        .align LOOP_ALIGN
+2:      // xp loop for 2x4 pixels: XYZ0[0..3], XYZ1[0..3]
+        ldp             x9,  x10, [x3]              // x9  = X0[0] Y0[0] Z0[0] X0[1], x10 = Y0[1] Z0[1] X0[2] Y0[2]
+        ldr             x11, [x3, #16]              // x11 = Z0[2] X0[3] Y0[3] Z0[3]
+        add             x3,  x3,  #24
+        ubfx            x12, x9,  #4,  #12          // X0[0] >> 4
+        lsr             x13, x9,  #52               // X0[1] >> 4
+        ubfx            x14, x10, #36, #12          // X0[2] >> 4
+        ubfx            x15, x11, #20, #12          // X0[3] >> 4
+
+        ldp             x19, x20, [x17]             // x19 = X1[0] Y1[0] Z1[0] X1[1], x20 = Y1[1] Z1[1] X1[2] Y1[2]
+        ldr             x21, [x17, #16]             // x21 = Z1[2] X1[3] Y1[3] Z1[3]
+        add             x17, x17, #24
+        ubfx            x22, x19, #4, #12           // X1[0] >> 4
+        lsr             x23, x19, #52               // X1[1] >> 4
+        ubfx            x24, x20, #36, #12          // X1[2] >> 4
+        ubfx            x25, x21, #20, #12          // X1[3] >> 4
+
+        ldr             h0,  [x7, x12, lsl #1]      // gamma.in[X0[0] >> 4]
+        ubfx            x12, x9,  #20, #12          // Y0[0] >> 4
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[X0[1] >> 4]
+        ubfx            x13, x10, #4, #12           // Y0[1] >> 4
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[X0[2] >> 4]
+        lsr             x14, x10, #52               // Y0[2] >> 4
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[X0[3] >> 4]
+        ubfx            x15, x11, #36, #12          // Y0[3] >> 4
+
+        ldr             h20, [x7, x22, lsl #1]      // gamma.in[X1[0] >> 4]
+        ubfx            x22, x19, #20, #12          // Y1[0] >> 4
+        ldr             h26, [x7, x23, lsl #1]      // gamma.in[X1[1] >> 4]
+        ubfx            x23, x20, #4,  #12          // Y1[1] >> 4
+        ldr             h27, [x7, x24, lsl #1]      // gamma.in[X1[2] >> 4]
+        lsr             x24, x20, #52               // Y1[2] >> 4
+        ldr             h28, [x7, x25, lsl #1]      // gamma.in[X1[3] >> 4]
+        ubfx            x25, x21, #36, #12          // Y1[3] >> 4
+
+        mov             v0.h[1],  v16.h[0]          // v0.4h  = gamma.in[X0[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[X0[2..3] >> 4]
+        mov             v0.s[1],  v17.s[0]          // v0.4h  = gamma.in[X0[0..3] >> 4]
+        ldr             h1,  [x7, x12, lsl #1]      // gamma.in[Y0[0] >> 4]
+        umull           v3.4s, v0.4h, v6.h[0]       // R0[0..3] = gamma.in[X0[0..3] >> 4] * mat[0][0]
+        umull           v5.4s, v0.4h, v6.h[6]       // B0[0..3] = gamma.in[X0[0..3] >> 4] * mat[2][0]
+        ubfx            x12, x9,  #36, #12          // Z0[0] >> 4
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[Y0[1] >> 4]
+
+        mov             v20.h[1], v26.h[0]          // v20.4h = gamma.in[X1[0..1] >> 4]
+        mov             v27.h[1], v28.h[0]          // v27.4h = gamma.in[X1[2..3] >> 4]
+        mov             v20.s[1], v27.s[0]          // v20.4h = gamma.in[X1[0..3] >> 4]
+        ldr             h21, [x7, x22, lsl #1]      // gamma.in[Y1[0] >> 4]
+        umull           v23.4s, v20.4h, v6.h[0]     // R1[0..3] = gamma.in[X1[0..3] >> 4] * mat[0][0]
+        umull           v25.4s, v20.4h, v6.h[6]     // B1[0..3] = gamma.in[X1[0..3] >> 4] * mat[2][0]
+        ubfx            x22, x19, #36, #12          // Z1[0] >> 4
+        ldr             h26, [x7, x23, lsl #1]      // gamma.in[Y1[1] >> 4]
+
+        ubfx            x13, x10, #20, #12          // Z0[1] >> 4
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[Y0[2] >> 4]
+        ubfx            x14, x11, #4,  #12          // Z0[2] >> 4
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[Y0[3] >> 4]
+        lsr             x15, x11, #52               // Z0[3] >> 4
+        mov             v1.h[1],  v16.h[0]          // v1.4h  = gamma.in[Y0[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[Y0[2..3] >> 4]
+        mov             v1.s[1],  v17.s[0]          // v1.4h  = gamma.in[Y0[0..3] >> 4]
+
+        ubfx            x23, x20, #20, #12          // Z1[1] >> 4
+        ldr             h27, [x7, x24, lsl #1]      // gamma.in[Y1[2] >> 4]
+        ubfx            x24, x21, #4,  #12          // Z1[2] >> 4
+        ldr             h28, [x7, x25, lsl #1]      // gamma.in[Y1[3] >> 4]
+        umull           v4.4s,  v1.4h,  v6.h[4]     // G0[0..3]  = gamma.in[Y0[0..3] >> 4] * mat[1][1]
+        umlsl           v3.4s,  v1.4h,  v6.h[1]     // R0[0..3] -= gamma.in[Y0[0..3] >> 4] * mat[0][1]
+
+        lsr             x25, x21, #52               // Z1[3] >> 4
+        mov             v21.h[1], v26.h[0]          // v21.4h = gamma.in[Y1[0..1] >> 4]
+        mov             v27.h[1], v28.h[0]          // v27.4h = gamma.in[Y1[2..3] >> 4]
+        mov             v21.s[1], v27.s[0]          // v21.4h = gamma.in[Y1[0..3] >> 4]
+        umlsl           v4.4s,  v0.4h,  v6.h[3]     // G0[0..3] -= gamma.in[X0[0..3] >> 4] * mat[1][0]
+        umlsl           v5.4s,  v1.4h,  v6.h[7]     // B0[0..3] -= gamma.in[Y0[0..3] >> 4] * mat[2][1]
+
+        ldr             h2,  [x7, x12, lsl #1]      // gamma.in[Z0[0] >> 4]
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[Z0[1] >> 4]
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[Z0[2] >> 4]
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[Z0[3] >> 4]
+        umull           v24.4s, v21.4h, v6.h[4]     // G1[0..3]  = gamma.in[Y1[0..3] >> 4] * mat[1][1]
+        umlsl           v23.4s, v21.4h, v6.h[1]     // R1[0..3] -= gamma.in[Y1[0..3] >> 4] * mat[0][1]
+
+        mov             v2.h[1],  v16.h[0]          // v2.4h  = gamma.in[Z0[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[Z0[2..3] >> 4]
+        mov             v2.s[1],  v17.s[0]          // v2.4h  = gamma.in[Z0[0..3] >> 4]
+        umlsl           v24.4s, v20.4h, v6.h[3]     // G1[0..3] -= gamma.in[X1[0..3] >> 4] * mat[1][0]
+        umlsl           v25.4s, v21.4h, v6.h[7]     // B1[0..3] -= gamma.in[Y1[0..3] >> 4] * mat[2][1]
+
+        ldr             h22, [x7, x22, lsl #1]      // gamma.in[Z1[0] >> 4]
+        ldr             h26, [x7, x23, lsl #1]      // gamma.in[Z1[1] >> 4]
+        ldr             h27, [x7, x24, lsl #1]      // gamma.in[Z1[2] >> 4]
+        ldr             h28, [x7, x25, lsl #1]      // gamma.in[Z1[3] >> 4]
+        mov             v22.h[1], v26.h[0]          // v22.4h = gamma.in[Z1[0..1] >> 4]
+        mov             v27.h[1], v28.h[0]          // v27.4h = gamma.in[Z1[2..3] >> 4]
+        mov             v22.s[1], v27.s[0]          // v22.4h = gamma.in[Z1[0..3] >> 4]
+
+        umlsl           v3.4s,  v2.4h,  v6.h[2]     // R0[0..3] -= gamma.in[Z0[0..3] >> 4] * mat[0][2]
+        sqshrun         v3.4h,  v3.4s,  #12         // clip(R0[0..3] >> 12)
+        umlal           v4.4s,  v2.4h,  v6.h[5]     // G0[0..3] += gamma.in[Z0[0..3] >> 4] * mat[1][2]
+        sqshrun         v4.4h,  v4.4s,  #12         // clip(G0[0..3] >> 12)
+        umov            w9,  v3.h[0]                // clip(R0[0] >> 12)
+        umov            w10, v4.h[1]                // clip(G0[1] >> 12)
+        umlal           v5.4s,  v2.4h,  v7.h[0]     // B0[0..3] += gamma.in[Z0[0..3] >> 4] * mat[2][2]
+        sqshrun         v5.4h,  v5.4s,  #12         // clip(B0[0..3] >> 12)
+
+        umlsl           v23.4s, v22.4h, v6.h[2]     // R1[0..3] -= gamma.in[Z1[0..3] >> 4] * mat[0][2]
+        sqshrun         v23.4h, v23.4s, #12         // clip(R1[0..3] >> 12)
+        umlal           v24.4s, v22.4h, v6.h[5]     // G1[0..3] += gamma.in[Z1[0..3] >> 4] * mat[1][2]
+        sqshrun         v24.4h, v24.4s, #12         // clip(G1[0..3] >> 12)
+        umov            w19, v23.h[0]               // clip(R1[0] >> 12)
+        umov            w20, v24.h[1]               // clip(G1[1] >> 12)
+        umlal           v25.4s, v22.4h, v7.h[0]     // B1[0..3] += gamma.in[Z1[0..3] >> 4] * mat[2][2]
+        sqshrun         v25.4h, v25.4s, #12         // clip(B1[0..3] >> 12)
+
+        umov            w11, v5.h[2]                // clip(B0[2] >> 12)
+        umov            w12, v4.h[0]                // clip(G0[0] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R0[0] = gamma.out[clip(R0[0] >> 12)]
+        lsl             x9,  x9,  #4                // R0[0] << 4
+        umov            w13, v5.h[1]                // clip(B0[1] >> 12)
+        ldrh            w10, [x8, x10, lsl #1]      // G0[1] = gamma.out[clip(G0[1] >> 12)]
+        lsl             x10, x10, #4                // G0[1] << 4
+
+        umov            w21, v25.h[2]               // clip(B1[2] >> 12)
+        umov            w22, v24.h[0]               // clip(G1[0] >> 12)
+        ldrh            w19, [x8, x19, lsl #1]      // R1[0] = gamma.out[clip(R1[0] >> 12)]
+        lsl             x19, x19, #4                // R1[0] << 4
+        umov            w23, v25.h[1]               // clip(B1[1] >> 12)
+        ldrh            w20, [x8, x20, lsl #1]      // G1[1] = gamma.out[clip(G1[1] >> 12)]
+        lsl             x20, x20, #4                // G1[1] << 4
+
+        umov            w14, v3.h[3]                // clip(R0[3] >> 12)
+        ldrh            w11, [x8, x11, lsl #1]      // B0[2] = gamma.out[clip(B0[2] >> 12)]
+        lsl             x11, x11, #4                // B0[2] << 4
+        umov            w15, v5.h[0]                // clip(B0[0] >> 12)
+        ldrh            w12, [x8, x12, lsl #1]      // G0[0] = gamma.out[clip(G0[0] >> 12)]
+        orr             x9,  x9,  x12, lsl #20      // R0[0] << 4, G0[0] << 4
+        umov            w12, v3.h[2]                // clip(R0[2] >> 12)
+        ldrh            w13, [x8, x13, lsl #1]      // B0[1] = gamma.out[clip(B0[1] >> 12)]
+
+        umov            w24, v23.h[3]               // clip(R1[3] >> 12)
+        ldrh            w21, [x8, x21, lsl #1]      // B1[2] = gamma.out[clip(B1[2] >> 12)]
+        lsl             x21, x21, #4                // B1[2] << 4
+        umov            w25, v25.h[0]               // clip(B1[0] >> 12)
+        ldrh            w22, [x8, x22, lsl #1]      // G1[0] = gamma.out[clip(G1[0] >> 12)]
+        orr             x19, x19, x22, lsl #20      // R1[0] << 4, G1[0] << 4
+        umov            w22, v23.h[2]               // clip(R1[2] >> 12)
+        ldrh            w23, [x8, x23, lsl #1]      // B1[1] = gamma.out[clip(B1[1] >> 12)]
+
+        orr             x10, x10, x13, lsl #20      // G0[1] << 4, B0[1] << 4
+        umov            w13, v4.h[3]                // clip(G0[3] >> 12)
+        ldrh            w14, [x8, x14, lsl #1]      // R0[3] = gamma.out[clip(R0[3] >> 12)]
+        orr             x11, x11, x14, lsl #20      // B0[2] << 4, R0[3] << 4
+        umov            w14, v3.h[1]                // clip(R0[1] >> 12)
+        ldrh            w15, [x8, x15, lsl #1]      // B0[0] = gamma.out[clip(B0[0] >> 12)]
+        orr             x9,  x9,  x15, lsl #36      // R0[0] << 4, G0[0] << 4, B0[0] << 4
+        umov            w15, v4.h[2]                // clip(G0[2] >> 12)
+
+        orr             x20, x20, x23, lsl #20      // G1[1] << 4, B1[1] << 4
+        umov            w23, v24.h[3]               // clip(G1[3] >> 12)
+        ldrh            w24, [x8, x24, lsl #1]      // R1[3] = gamma.out[clip(R1[3] >> 12)]
+        orr             x21, x21, x24, lsl #20      // B1[2] << 4, R1[3] << 4
+        umov            w24, v23.h[1]               // clip(R1[1] >> 12)
+        ldrh            w25, [x8, x25, lsl #1]      // B1[0] = gamma.out[clip(B1[0] >> 12)]
+        orr             x19, x19, x25, lsl #36      // R1[0] << 4, G1[0] << 4, B1[0] << 4
+        umov            w25, v24.h[2]               // clip(G1[2] >> 12)
+
+        ldrh            w12, [x8, x12, lsl #1]      // R0[2] = gamma.out[clip(R0[2] >> 12)]
+        orr             x10, x10, x12, lsl #36      // G0[1] << 4, B0[1] << 4, R0[2] << 4
+        umov            w12, v5.h[3]                // clip(B0[3] >> 12)
+        ldrh            w13, [x8, x13, lsl #1]      // G0[3] = gamma.out[clip(G0[3] >> 12)]
+        orr             x11, x11, x13, lsl #36      // B0[2] << 4, R0[3] << 4, G0[3] << 4
+        ldrh            w14, [x8, x14, lsl #1]      // R0[1] = gamma.out[clip(R0[1] >> 12)]
+        orr             x9,  x9,  x14, lsl #52      // x9  = R0[0] << 4, G0[0] << 4, B0[0] << 4, R0[1] << 4
+        ldrh            w15, [x8, x15, lsl #1]      // G0[2] = gamma.out[clip(G0[2] >> 12)]
+        orr             x10, x10, x15, lsl #52      // x10 = G0[1] << 4, B0[1] << 4, R0[2] << 4, G0[2] << 4
+        ldrh            w12, [x8, x12, lsl #1]      // B0[3] = gamma.out[clip(B0[3] >> 12)]
+        orr             x11, x11, x12, lsl #52      // x11 = B0[2] << 4, R0[3] << 4, G0[3] << 4, B0[3] << 4
+        stp             x9,  x10, [x1]
+        str             x11, [x1, #16]
+
+        ldrh            w22, [x8, x22, lsl #1]      // R1[2] = gamma.out[clip(R1[2] >> 12)]
+        orr             x20, x20, x22, lsl #36      // G1[1] << 4, B1[1] << 4, R1[2] << 4
+        umov            w22, v25.h[3]               // clip(B1[3] >> 12)
+        ldrh            w23, [x8, x23, lsl #1]      // G1[3] = gamma.out[clip(G1[3] >> 12)]
+        orr             x21, x21, x23, lsl #36      // B1[2] << 4, R1[3] << 4, G1[3] << 4
+        ldrh            w24, [x8, x24, lsl #1]      // R1[1] = gamma.out[clip(R1[1] >> 12)]
+        orr             x19, x19, x24, lsl #52      // x19 = R1[0] << 4, G1[0] << 4, B1[0] << 4, R1[1] << 4
+        ldrh            w25, [x8, x25, lsl #1]      // G1[2] = gamma.out[clip(G1[2] >> 12)]
+        orr             x20, x20, x25, lsl #52      // x20 = G1[1] << 4, B1[1] << 4, R1[2] << 4, G1[2] << 4
+        ldrh            w22, [x8, x22, lsl #1]      // B1[3] = gamma.out[clip(B1[3] >> 12)]
+        orr             x21, x21, x22, lsl #52      // x21 = B1[2] << 4, R1[3] << 4, G1[3] << 4, B1[3] << 4
+        stp             x19, x20, [x16]
+        str             x21, [x16, #16]
+
+        add             x1,  x1,  #24
+        add             x16, x16, #24
+
+        subs            w0,  w0,  #4
+        b.ge            2b
+
+        .align JUMP_ALIGN
+3:
+        tst             w5,  #3
+        b.eq            5f                          // no residual pixels; (w & 3) == 0
+
+        ldr             w10, [x3]                   // w10 = X0[0] Y0[0]
+        ldrh            w11, [x3, #4]               // w11 = Z0[0]
+        add             x3,  x3,  #6
+        ldr             w20, [x17]                  // w20 = X1[0] Y1[0]
+        ldrh            w21, [x17, #4]              // w21 = Z1[0]
+        add             x17, x17, #6
+        ubfx            w9,  w10, #4,  #12          // X0[0] >> 4
+        ubfx            w10, w10, #20, #12          // Y0[0] >> 4
+        lsr             w11, w11, #4                // Z0[0] >> 4
+        ldr             h0,  [x7, x9,  lsl #1]      // v0.4h = gamma.in[X0[0] >> 4]
+        ldr             h1,  [x7, x10, lsl #1]      // v1.4h = gamma.in[Y0[0] >> 4]
+        ldr             h2,  [x7, x11, lsl #1]      // v2.4h = gamma.in[Z0[0] >> 4]
+        ubfx            w19, w20, #4,  #12          // X1[0] >> 4
+        ubfx            w20, w20, #20, #12          // Y1[0] >> 4
+        lsr             w21, w21, #4                // Z1[0] >> 4
+        ldr             h20, [x7, x19, lsl #1]      // v20.4h = gamma.in[X1[0] >> 4]
+        ldr             h21, [x7, x20, lsl #1]      // v21.4h = gamma.in[Y1[0] >> 4]
+        ldr             h22, [x7, x21, lsl #1]      // v22.4h = gamma.in[Z1[0] >> 4]
+
+        cmp             w0,  #-2
+        b.lt            4f                          // (w & 3) == 1
+
+        ldr             w10, [x3]                   // w10 = X0[1] Y0[1]
+        ldrh            w11, [x3, #4]               // w11 = Z0[1]
+        add             x3,  x3,  #6
+        ldr             w20, [x17]                  // w20 = X1[1] Y1[1]
+        ldrh            w21, [x17, #4]              // w21 = Z1[1]
+        add             x17, x17,  #6
+        ubfx            w9,  w10, #4,  #12          // X0[1] >> 4
+        ubfx            w10, w10, #20, #12          // Y0[1] >> 4
+        lsr             w11, w11, #4                // Z0[1] >> 4
+        ldr             h16, [x7, x9,  lsl #1]      // gamma.in[X0[1] >> 4]
+        ldr             h17, [x7, x10, lsl #1]      // gamma.in[Y0[1] >> 4]
+        ldr             h18, [x7, x11, lsl #1]      // gamma.in[Z0[1] >> 4]
+        ubfx            w19, w20, #4,  #12          // X1[1] >> 4
+        ubfx            w20, w20, #20, #12          // Y1[1] >> 4
+        lsr             w21, w21, #4                // Z1[1] >> 4
+        ldr             h23, [x7, x19, lsl #1]      // gamma.in[X1[1] >> 4]
+        ldr             h24, [x7, x20, lsl #1]      // gamma.in[Y1[1] >> 4]
+        ldr             h25, [x7, x21, lsl #1]      // gamma.in[Z1[1] >> 4]
+        mov             v0.h[1],  v16.h[0]          // v0.4h = gamma.in[X0[0..1] >> 4]
+        mov             v1.h[1],  v17.h[0]          // v1.4h = gamma.in[Y0[0..1] >> 4]
+        mov             v2.h[1],  v18.h[0]          // v2.4h = gamma.in[Z0[0..1] >> 4]
+        mov             v20.h[1], v23.h[0]          // v20.4h = gamma.in[X1[0..1] >> 4]
+        mov             v21.h[1], v24.h[0]          // v21.4h = gamma.in[Y1[0..1] >> 4]
+        mov             v22.h[1], v25.h[0]          // v22.4h = gamma.in[Z1[0..1] >> 4]
+
+        b.le            4f                          // (w & 3) == 2
+
+        ldr             w10, [x3]                   // w10 = X0[2] Y0[2]
+        ldrh            w11, [x3, #4]               // w11 = Z0[2]
+        add             x3,  x3,  #6
+        ldr             w20, [x17]                  // w20 = X1[2] Y1[2]
+        ldrh            w21, [x17, #4]              // w21 = Z1[2]
+        add             x17, x17, #6
+        ubfx            w9,  w10, #4,  #12          // X0[2] >> 4
+        ubfx            w10, w10, #20, #12          // Y0[2] >> 4
+        lsr             w11, w11, #4                // Z0[2] >> 4
+        ldr             h16, [x7, x9,  lsl #1]      // gamma.in[X0[2] >> 4]
+        ldr             h17, [x7, x10, lsl #1]      // gamma.in[Y0[2] >> 4]
+        ldr             h18, [x7, x11, lsl #1]      // gamma.in[Z0[2] >> 4]
+        ubfx            w19, w20, #4,  #12          // X1[2] >> 4
+        ubfx            w20, w20, #20, #12          // Y1[2] >> 4
+        lsr             w21, w21, #4                // Z1[2] >> 4
+        ldr             h23, [x7, x19, lsl #1]      // gamma.in[X1[2] >> 4]
+        ldr             h24, [x7, x20, lsl #1]      // gamma.in[Y1[2] >> 4]
+        ldr             h25, [x7, x21, lsl #1]      // gamma.in[Z1[2] >> 4]
+        mov             v0.h[2],  v16.h[0]          // v0.4h = gamma.in[X0[0..2] >> 4]
+        mov             v1.h[2],  v17.h[0]          // v1.4h = gamma.in[Y0[0..2] >> 4]
+        mov             v2.h[2],  v18.h[0]          // v2.4h = gamma.in[Z0[0..2] >> 4]
+        mov             v20.h[2], v23.h[0]          // v20.4h = gamma.in[X1[0..2] >> 4]
+        mov             v21.h[2], v24.h[0]          // v21.4h = gamma.in[Y1[0..2] >> 4]
+        mov             v22.h[2], v25.h[0]          // v22.4h = gamma.in[Z1[0..2] >> 4]
+
+        .align JUMP_ALIGN
+4:
+        umull           v3.4s,  v0.4h,  v6.h[0]     // R0[0..2] = gamma.in[X0[0..2] >> 4] * mat[0][0]
+        umull           v5.4s,  v0.4h,  v6.h[6]     // B0[0..2] = gamma.in[X0[0..2] >> 4] * mat[2][0]
+
+        umull           v23.4s, v20.4h, v6.h[0]     // R1[0..2] = gamma.in[X1[0..2] >> 4] * mat[0][0]
+        umull           v25.4s, v20.4h, v6.h[6]     // B1[0..2] = gamma.in[X1[0..2] >> 4] * mat[2][0]
+
+        umull           v4.4s,  v1.4h,  v6.h[4]     // G0[0..2]  = gamma.in[Y0[0..2] >> 4] * mat[1][1]
+        umlsl           v3.4s,  v1.4h,  v6.h[1]     // R0[0..2] -= gamma.in[Y0[0..2] >> 4] * mat[0][1]
+        umlsl           v4.4s,  v0.4h,  v6.h[3]     // G0[0..2] -= gamma.in[X0[0..2] >> 4] * mat[1][0]
+        umlsl           v5.4s,  v1.4h,  v6.h[7]     // B0[0..2] -= gamma.in[Y0[0..2] >> 4] * mat[2][1]
+
+        umull           v24.4s, v21.4h, v6.h[4]     // G1[0..2]  = gamma.in[Y1[0..2] >> 4] * mat[1][1]
+        umlsl           v23.4s, v21.4h, v6.h[1]     // R1[0..2] -= gamma.in[Y1[0..2] >> 4] * mat[0][1]
+        umlsl           v24.4s, v20.4h, v6.h[3]     // G1[0..2] -= gamma.in[X1[0..2] >> 4] * mat[1][0]
+        umlsl           v25.4s, v21.4h, v6.h[7]     // B1[0..2] -= gamma.in[Y1[0..2] >> 4] * mat[2][1]
+
+        umlsl           v3.4s,  v2.4h,  v6.h[2]     // R0[0..2] -= gamma.in[Z0[0..2] >> 4] * mat[0][2]
+        sqshrun         v3.4h,  v3.4s,  #12         // clip(R0[0..2] >> 12)
+        umlal           v4.4s,  v2.4h,  v6.h[5]     // G0[0..2] += gamma.in[Z0[0..2] >> 4] * mat[1][2]
+        sqshrun         v4.4h,  v4.4s,  #12         // clip(G0[0..2] >> 12)
+        umlal           v5.4s,  v2.4h,  v7.h[0]     // B0[0..2] += gamma.in[Z0[0..2] >> 4] * mat[2][2]
+        sqshrun         v5.4h,  v5.4s,  #12         // clip(B0[0..2] >> 12)
+
+        umlsl           v23.4s, v22.4h, v6.h[2]     // R1[0..2] -= gamma.in[Z1[0..2] >> 4] * mat[0][2]
+        sqshrun         v23.4h, v23.4s, #12         // clip(R1[0..2] >> 12)
+        umlal           v24.4s, v22.4h, v6.h[5]     // G1[0..2] += gamma.in[Z1[0..2] >> 4] * mat[1][2]
+        sqshrun         v24.4h, v24.4s, #12         // clip(G1[0..2] >> 12)
+        umlal           v25.4s, v22.4h, v7.h[0]     // B1[0..2] += gamma.in[Z1[0..2] >> 4] * mat[2][2]
+        sqshrun         v25.4h, v25.4s, #12         // clip(B1[0..2] >> 12)
+
+        umov            w9,  v3.h[0]                // clip(R0[0] >> 12)
+        umov            w10, v4.h[0]                // clip(G0[0] >> 12)
+        umov            w11, v5.h[0]                // clip(B0[0] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R0[0] = gamma.out[clip(R0[0] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G0[0] = gamma.out[clip(G0[0] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B0[0] = gamma.out[clip(B0[0] >> 12)]
+        umov            w19, v23.h[0]               // clip(R1[0] >> 12)
+        umov            w20, v24.h[0]               // clip(G1[0] >> 12)
+        umov            w21, v25.h[0]               // clip(B1[0] >> 12)
+        ldrh            w19, [x8, x19, lsl #1]      // R1[0] = gamma.out[clip(R1[0] >> 12)]
+        ldrh            w20, [x8, x20, lsl #1]      // G1[0] = gamma.out[clip(G1[0] >> 12)]
+        ldrh            w21, [x8, x21, lsl #1]      // B1[0] = gamma.out[clip(B1[0] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R0[0] << 4
+        lsl             w10, w10, #4                // w10 = G0[0] << 4
+        lsl             w11, w11, #4                // w11 = B0[0] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        lsl             w19, w19, #4                // w19 = R1[0] << 4
+        lsl             w20, w20, #4                // w20 = G1[0] << 4
+        lsl             w21, w21, #4                // w21 = B1[0] << 4
+        strh            w19, [x16]
+        strh            w20, [x16, #2]
+        strh            w21, [x16, #4]
+        add             x1,  x1,  #6
+        add             x16, x16, #6
+
+        cmp             w0,  #-2
+        b.lt            5f                          // (w & 3) == 1
+
+        umov            w9,  v3.h[1]                // clip(R0[1] >> 12)
+        umov            w10, v4.h[1]                // clip(G0[1] >> 12)
+        umov            w11, v5.h[1]                // clip(B0[1] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R0[1] = gamma.out[clip(R0[1] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G0[1] = gamma.out[clip(G0[1] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B0[1] = gamma.out[clip(B0[1] >> 12)]
+        umov            w19, v23.h[1]               // clip(R1[1] >> 12)
+        umov            w20, v24.h[1]               // clip(G1[1] >> 12)
+        umov            w21, v25.h[1]               // clip(B1[1] >> 12)
+        ldrh            w19, [x8, x19, lsl #1]      // R1[1] = gamma.out[clip(R1[1] >> 12)]
+        ldrh            w20, [x8, x20, lsl #1]      // G1[1] = gamma.out[clip(G1[1] >> 12)]
+        ldrh            w21, [x8, x21, lsl #1]      // B1[1] = gamma.out[clip(B1[1] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R0[1] << 4
+        lsl             w10, w10, #4                // w10 = G0[1] << 4
+        lsl             w11, w11, #4                // w11 = B0[1] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        lsl             w19, w19, #4                // w19 = R1[1] << 4
+        lsl             w20, w20, #4                // w20 = G1[1] << 4
+        lsl             w21, w21, #4                // w21 = B1[1] << 4
+        strh            w19, [x16]
+        strh            w20, [x16, #2]
+        strh            w21, [x16, #4]
+        add             x1,  x1,  #6
+        add             x16, x16, #6
+
+        b.le            5f                          // (w & 3) == 2
+
+        umov            w9,  v3.h[2]                // clip(R0[2] >> 12)
+        umov            w10, v4.h[2]                // clip(G0[2] >> 12)
+        umov            w11, v5.h[2]                // clip(B0[2] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R0[2] = gamma.out[clip(R0[2] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G0[2] = gamma.out[clip(G0[2] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B0[2] = gamma.out[clip(B0[2] >> 12)]
+        umov            w19, v23.h[2]               // clip(R1[2] >> 12)
+        umov            w20, v24.h[2]               // clip(G1[2] >> 12)
+        umov            w21, v25.h[2]               // clip(B1[2] >> 12)
+        ldrh            w19, [x8, x19, lsl #1]      // R1[2] = gamma.out[clip(R1[2] >> 12)]
+        ldrh            w20, [x8, x20, lsl #1]      // G1[2] = gamma.out[clip(G1[2] >> 12)]
+        ldrh            w21, [x8, x21, lsl #1]      // B1[2] = gamma.out[clip(B1[2] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R0[2] << 4
+        lsl             w10, w10, #4                // w10 = G0[2] << 4
+        lsl             w11, w11, #4                // w11 = B0[2] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        lsl             w19, w19, #4                // w19 = R1[2] << 4
+        lsl             w20, w20, #4                // w20 = G1[2] << 4
+        lsl             w21, w21, #4                // w21 = B1[2] << 4
+        strh            w19, [x16]
+        strh            w20, [x16, #2]
+        strh            w21, [x16, #4]
+        add             x1,  x1,  #6
+        add             x16, x16, #6
+
+        .align JUMP_ALIGN
+5:
+        add             x3,  x3,  x4
+        add             x17, x17, x4
+        add             x1,  x1,  x2
+        add             x16, x16, x2
+
+        subs            w6,  w6,  #2
+        b.ge            1b
+
+        ldp             x21, x22, [sp, #16]
+        ldp             x23, x24, [sp, #32]
+        ldr             x25, [sp, #48]
+        ldp             x19, x20, [sp], #64
+
+        .align JUMP_ALIGN
+6:
+        tbz             w6,  #0,  10f               // even number of lines; (h & 1) == 0
+
+        subs            w0,  w5,  #4
+        b.lt            8f                          // w < 4
+
+        .align LOOP_ALIGN
+7:      // loop for last odd line by 4 pixels: XYZ[0..3]
+        ldp             x9,  x10, [x3]              // x9  = X[0] Y[0] Z[0] X[1], x10 = Y[1] Z[1] X[2] Y[2]
+        ldr             x11, [x3, #16]              // x11 = Z[2] X[3] Y[3] Z[3]
+        add             x3,  x3,  #24
+
+        ubfx            x12, x9,  #4,  #12          // X[0] >> 4
+        lsr             x13, x9,  #52               // X[1] >> 4
+        ubfx            x14, x10, #36, #12          // X[2] >> 4
+        ubfx            x15, x11, #20, #12          // X[3] >> 4
+
+        ldr             h0,  [x7, x12, lsl #1]      // gamma.in[X[0] >> 4]
+        ubfx            x12, x9,  #20, #12          // Y[0] >> 4
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[X[1] >> 4]
+        ubfx            x13, x10, #4,  #12          // Y[1] >> 4
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[X[2] >> 4]
+        lsr             x14, x10, #52               // Y[2] >> 4
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[X[3] >> 4]
+        ubfx            x15, x11, #36, #12          // Y[3] >> 4
+        mov             v0.h[1],  v16.h[0]          // v0.4h  = gamma.in[X[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[X[2..3] >> 4]
+        mov             v0.s[1],  v17.s[0]          // v0.4h  = gamma.in[X[0..3] >> 4]
+
+        umull           v3.4s,  v0.4h,  v6.h[0]     // R[0..3] = gamma.in[X[0..3] >> 4] * mat[0][0]
+        umull           v5.4s,  v0.4h,  v6.h[6]     // B[0..3] = gamma.in[X[0..3] >> 4] * mat[2][0]
+
+        ldr             h1,  [x7, x12, lsl #1]      // gamma.in[Y[0] >> 4]
+        ubfx            x12, x9,  #36, #12          // Z[0] >> 4
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[Y[1] >> 4]
+        ubfx            x13, x10, #20, #12          // Z[1] >> 4
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[Y[2] >> 4]
+        ubfx            x14, x11, #4,  #12          // Z[2] >> 4
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[Y[3] >> 4]
+        lsr             x15, x11, #52               // Z[3] >> 4
+        mov             v1.h[1],  v16.h[0]          // v1.4h  = gamma.in[Y[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[Y[2..3] >> 4]
+        mov             v1.s[1],  v17.s[0]          // v1.4h  = gamma.in[Y[0..3] >> 4]
+
+        umull           v4.4s,  v1.4h,  v6.h[4]     // G[0..3]  = gamma.in[Y[0..3] >> 4] * mat[1][1]
+        umlsl           v3.4s,  v1.4h,  v6.h[1]     // R[0..3] -= gamma.in[Y[0..3] >> 4] * mat[0][1]
+        umlsl           v4.4s,  v0.4h,  v6.h[3]     // G[0..3] -= gamma.in[X[0..3] >> 4] * mat[1][0]
+        umlsl           v5.4s,  v1.4h,  v6.h[7]     // B[0..3] -= gamma.in[Y[0..3] >> 4] * mat[2][1]
+
+        ldr             h2,  [x7, x12, lsl #1]      // gamma.in[Z[0] >> 4]
+        ldr             h16, [x7, x13, lsl #1]      // gamma.in[Z[1] >> 4]
+        ldr             h17, [x7, x14, lsl #1]      // gamma.in[Z[2] >> 4]
+        ldr             h18, [x7, x15, lsl #1]      // gamma.in[Z[3] >> 4]
+        mov             v2.h[1],  v16.h[0]          // v2.4h  = gamma.in[Z[0..1] >> 4]
+        mov             v17.h[1], v18.h[0]          // v17.4h = gamma.in[Z[2..3] >> 4]
+        mov             v2.s[1],  v17.s[0]          // v2.4h  = gamma.in[Z[0..3] >> 4]
+
+        umlsl           v3.4s,  v2.4h,  v6.h[2]     // R[0..3] -= gamma.in[Z[0..3] >> 4] * mat[0][2]
+        sqshrun         v3.4h,  v3.4s,  #12         // clip(R[0..3] >> 12)
+        umlal           v4.4s,  v2.4h,  v6.h[5]     // G[0..3] += gamma.in[Z[0..3] >> 4] * mat[1][2]
+        sqshrun         v4.4h,  v4.4s,  #12         // clip(G[0..3] >> 12)
+        umlal           v5.4s,  v2.4h,  v7.h[0]     // B[0..3] += gamma.in[Z[0..3] >> 4] * mat[2][2]
+        sqshrun         v5.4h,  v5.4s,  #12         // clip(B[0..3] >> 12)
+
+        umov            w9,  v3.h[0]                // clip(R[0] >> 12)
+        umov            w10, v4.h[1]                // clip(G[1] >> 12)
+        umov            w11, v5.h[2]                // clip(B[2] >> 12)
+
+        umov            w12, v4.h[0]                // clip(G[0] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R[0] = gamma.out[clip(R[0] >> 12)]
+        lsl             x9,  x9,  #4                // R[0] << 4
+        umov            w13, v5.h[1]                // clip(B[1] >> 12)
+        ldrh            w10, [x8, x10, lsl #1]      // G[1] = gamma.out[clip(G[1] >> 12)]
+        lsl             x10, x10, #4                // G[1] << 4
+        umov            w14, v3.h[3]                // clip(R[3] >> 12)
+        ldrh            w11, [x8, x11, lsl #1]      // B[2] = gamma.out[clip(B[2] >> 12)]
+        lsl             x11, x11, #4                // B[2] << 4
+
+        umov            w15, v5.h[0]                // clip(B[0] >> 12)
+        ldrh            w12, [x8, x12, lsl #1]      // G[0] = gamma.out[clip(G[0] >> 12)]
+        orr             x9,  x9,  x12, lsl #20      // R[0] << 4, G[0] << 4
+        umov            w12, v3.h[2]                // clip(R[2] >> 12)
+        ldrh            w13, [x8, x13, lsl #1]      // B[1] = gamma.out[clip(B[1] >> 12)]
+        orr             x10, x10, x13, lsl #20      // G[1] << 4, B[1] << 4
+        umov            w13, v4.h[3]                // clip(G[3] >> 12)
+        ldrh            w14, [x8, x14, lsl #1]      // R[3] = gamma.out[clip(R[3] >> 12)]
+        orr             x11, x11, x14, lsl #20      // B[2] << 4, R[3] << 4
+
+        umov            w14, v3.h[1]                // clip(R[1] >> 12)
+        ldrh            w15, [x8, x15, lsl #1]      // B[0] = gamma.out[clip(B[0] >> 12)]
+        orr             x9,  x9,  x15, lsl #36      // R[0] << 4, G[0] << 4, B[0] << 4
+        umov            w15, v4.h[2]                // clip(G[2] >> 12)
+        ldrh            w12, [x8, x12, lsl #1]      // R[2] = gamma.out[clip(R[2] >> 12)]
+        orr             x10, x10, x12, lsl #36      // G[1] << 4, B[1] << 4, R[2] << 4
+        umov            w12, v5.h[3]                // clip(B[3] >> 12)
+        ldrh            w13, [x8, x13, lsl #1]      // G[3] = gamma.out[clip(G[3] >> 12)]
+        orr             x11, x11, x13, lsl #36      // B[2] << 4, R[3] << 4, G[3] << 4
+
+        ldrh            w14, [x8, x14, lsl #1]      // R[1] = gamma.out[clip(R[1] >> 12)]
+        orr             x9,  x9,  x14, lsl #52      // x9  = R[0] << 4, G[0] << 4, B[0] << 4, R[1] << 4
+        ldrh            w15, [x8, x15, lsl #1]      // G[2] = gamma.out[clip(G[2] >> 12)]
+        orr             x10, x10, x15, lsl #52      // x10 = G[1] << 4, B[1] << 4, R[2] << 4, G[2] << 4
+        ldrh            w12, [x8, x12, lsl #1]      // B[3] = gamma.out[clip(B[3] >> 12)]
+        orr             x11, x11, x12, lsl #52      // x11 = B[2] << 4, R[3] << 4, G[3] << 4, B[3] << 4
+
+        stp             x9,  x10, [x1]
+        str             x11, [x1, #16]
+        add             x1,  x1,  #24
+
+        subs            w0,  w0,  #4
+        b.ge            7b
+
+        .align JUMP_ALIGN
+8:
+        tst             w5,  #3
+        b.eq            10f                         // no residual pixels; (w & 3) == 0
+
+        ldr             w10, [x3]                   // w10 = X[0] Y[0]
+        ldrh            w11, [x3, #4]               // w11 = Z[0]
+        add             x3,  x3,  #6
+        ubfx            w9,  w10, #4,  #12          // X[0] >> 4
+        ubfx            w10, w10, #20, #12          // Y[0] >> 4
+        lsr             w11, w11, #4                // Z[0] >> 4
+        ldr             h0,  [x7, x9,  lsl #1]      // v0.4h = gamma.in[X[0] >> 4]
+        ldr             h1,  [x7, x10, lsl #1]      // v1.4h = gamma.in[Y[0] >> 4]
+        ldr             h2,  [x7, x11, lsl #1]      // v2.4h = gamma.in[Z[0] >> 4]
+
+        cmp             w0,  #-2
+        b.lt            9f                          // (w & 3) == 1
+
+        ldr             w10, [x3]                   // w10 = X[1] Y[1]
+        ldrh            w11, [x3, #4]               // w11 = Z[1]
+        add             x3,  x3,  #6
+        ubfx            w9,  w10, #4, #12           // X[1] >> 4
+        ubfx            w10, w10, #20, #12          // Y[1] >> 4
+        lsr             w11, w11, #4                // Z[1] >> 4
+        ldr             h16, [x7, x9,  lsl #1]      // gamma.in[X[1] >> 4]
+        ldr             h17, [x7, x10, lsl #1]      // gamma.in[Y[1] >> 4]
+        ldr             h18, [x7, x11, lsl #1]      // gamma.in[Z[1] >> 4]
+        mov             v0.h[1], v16.h[0]           // v0.4h = gamma.in[X[0..1] >> 4]
+        mov             v1.h[1], v17.h[0]           // v1.4h = gamma.in[Y[0..1] >> 4]
+        mov             v2.h[1], v18.h[0]           // v2.4h = gamma.in[Z[0..1] >> 4]
+
+        b.le            9f                          // (w & 3) == 2
+
+        ldr             w10, [x3]                   // w10 = X[2] Y[2]
+        ldrh            w11, [x3, #4]               // w11 = Z[2]
+        add             x3,  x3,  #6
+        ubfx            w9,  w10, #4, #12           // X[2] >> 4
+        ubfx            w10, w10, #20, #12          // Y[2] >> 4
+        lsr             w11, w11, #4                // Z[2] >> 4
+        ldr             h16, [x7, x9,  lsl #1]      // gamma.in[X[2] >> 4]
+        ldr             h17, [x7, x10, lsl #1]      // gamma.in[Y[2] >> 4]
+        ldr             h18, [x7, x11, lsl #1]      // gamma.in[Z[2] >> 4]
+        mov             v0.h[2], v16.h[0]           // v0.4h = gamma.in[X[0..2] >> 4]
+        mov             v1.h[2], v17.h[0]           // v1.4h = gamma.in[Y[0..2] >> 4]
+        mov             v2.h[2], v18.h[0]           // v2.4h = gamma.in[Z[0..2] >> 4]
+
+        .align JUMP_ALIGN
+9:
+        umull           v3.4s,  v0.4h,  v6.h[0]     // R[0..2] = gamma.in[X[0..2] >> 4] * mat[0][0]
+        umull           v5.4s,  v0.4h,  v6.h[6]     // B[0..2] = gamma.in[X[0..2] >> 4] * mat[2][0]
+
+        umull           v4.4s,  v1.4h,  v6.h[4]     // G[0..2]  = gamma.in[Y[0..2] >> 4] * mat[1][1]
+        umlsl           v3.4s,  v1.4h,  v6.h[1]     // R[0..2] -= gamma.in[Y[0..2] >> 4] * mat[0][1]
+        umlsl           v4.4s,  v0.4h,  v6.h[3]     // G[0..2] -= gamma.in[X[0..2] >> 4] * mat[1][0]
+        umlsl           v5.4s,  v1.4h,  v6.h[7]     // B[0..2] -= gamma.in[Y[0..2] >> 4] * mat[2][1]
+
+        umlsl           v3.4s,  v2.4h,  v6.h[2]     // R[0..2] -= gamma.in[Z[0..2] >> 4] * mat[0][2]
+        sqshrun         v3.4h,  v3.4s,  #12         // clip(R[0..2] >> 12)
+        umlal           v4.4s,  v2.4h,  v6.h[5]     // G[0..2] += gamma.in[Z[0..2] >> 4] * mat[1][2]
+        sqshrun         v4.4h,  v4.4s,  #12         // clip(G[0..2] >> 12)
+        umlal           v5.4s,  v2.4h,  v7.h[0]     // B[0..2] += gamma.in[Z[0..2] >> 4] * mat[2][2]
+        sqshrun         v5.4h,  v5.4s,  #12         // clip(B[0..2] >> 12)
+
+        umov            w9,  v3.h[0]                // clip(R[0] >> 12)
+        umov            w10, v4.h[0]                // clip(G[0] >> 12)
+        umov            w11, v5.h[0]                // clip(B[0] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R[0] = gamma.out[clip(R[0] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G[0] = gamma.out[clip(G[0] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B[0] = gamma.out[clip(B[0] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R[0] << 4
+        lsl             w10, w10, #4                // w10 = G[0] << 4
+        lsl             w11, w11, #4                // w11 = B[0] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        add             x1,  x1,  #6
+
+        cmp             w0,  #-2
+        b.lt            10f                         // (w & 3) == 1
+
+        umov            w9,  v3.h[1]                // clip(R[1] >> 12)
+        umov            w10, v4.h[1]                // clip(G[1] >> 12)
+        umov            w11, v5.h[1]                // clip(B[1] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R[1] = gamma.out[clip(R[1] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G[1] = gamma.out[clip(G[1] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B[1] = gamma.out[clip(B[1] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R[1] << 4
+        lsl             w10, w10, #4                // w10 = G[1] << 4
+        lsl             w11, w11, #4                // w11 = B[1] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        add             x1,  x1,  #6
+
+        b.le            10f                         // (w & 3) == 2
+
+        umov            w9,  v3.h[2]                // clip(R[2] >> 12)
+        umov            w10, v4.h[2]                // clip(G[2] >> 12)
+        umov            w11, v5.h[2]                // clip(B[2] >> 12)
+        ldrh            w9,  [x8, x9,  lsl #1]      // R[2] = gamma.out[clip(R[2] >> 12)]
+        ldrh            w10, [x8, x10, lsl #1]      // G[2] = gamma.out[clip(G[2] >> 12)]
+        ldrh            w11, [x8, x11, lsl #1]      // B[2] = gamma.out[clip(B[2] >> 12)]
+        lsl             w9,  w9,  #4                // w9  = R[2] << 4
+        lsl             w10, w10, #4                // w10 = G[2] << 4
+        lsl             w11, w11, #4                // w11 = B[2] << 4
+        strh            w9,  [x1]
+        strh            w10, [x1, #2]
+        strh            w11, [x1, #4]
+        add             x1,  x1,  #6
+
+        .align JUMP_ALIGN
+10:
+        ret
+endfunc
diff --git a/libs/ffmpeg/libswscale/aarch64/yuv2rgb_neon.S b/libs/ffmpeg/libswscale/aarch64/yuv2rgb_neon.S
new file mode 100644
index 000000000000..19f750545f82
--- /dev/null
+++ b/libs/ffmpeg/libswscale/aarch64/yuv2rgb_neon.S
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ * Copyright (c) 2016 Clément Bœsch <clement stupeflix.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/aarch64/asm.S"
+
+.macro load_yoff_ycoeff yoff ycoeff
+#if defined(__APPLE__)
+        ldp             w9, w10, [sp, #\yoff]
+#else
+        ldr             w9,  [sp, #\yoff]
+        ldr             w10, [sp, #\ycoeff]
+#endif
+.endm
+
+.macro load_dst1_dst2 dst1 linesize1 dst2 linesize2
+#if defined(__APPLE__)
+#define DST_OFFSET 8
+#else
+#define DST_OFFSET 0
+#endif
+        ldr             x10, [sp, #\dst1      - DST_OFFSET]
+        ldr             w12, [sp, #\linesize1 - DST_OFFSET]
+        ldr             x15, [sp, #\dst2      - DST_OFFSET]
+        ldr             w16, [sp, #\linesize2 - DST_OFFSET]
+#undef DST_OFFSET
+        sub             w12, w12, w0                                    // w12 = linesize1 - width     (padding1)
+        sub             w16, w16, w0                                    // w16 = linesize2 - width     (padding2)
+.endm
+
+.macro load_args_nv12 ofmt
+        ldr             x8,  [sp]                                       // table
+        load_yoff_ycoeff 8, 16                                           // y_offset, y_coeff
+        ld1             {v1.1d}, [x8]
+        dup             v0.8h, w10
+        dup             v3.8h, w9
+.ifc \ofmt,gbrp
+        load_dst1_dst2  24, 32, 40, 48
+        sub             w3, w3, w0                                      // w3 = linesize  - width     (padding)
+.else
+ .ifc \ofmt,rgb24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+ .else
+  .ifc \ofmt,bgr24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+  .else
+        sub             w3, w3, w0, lsl #2                              // w3 = linesize  - width * 4 (padding)
+  .endif
+ .endif
+.endif
+        sub             w5, w5, w0                                      // w5 = linesizeY - width     (paddingY)
+        sub             w7, w7, w0                                      // w7 = linesizeC - width     (paddingC)
+        neg             w11, w0
+.endm
+
+.macro load_args_nv21 ofmt
+        load_args_nv12  \ofmt
+.endm
+
+.macro load_args_yuv420p ofmt
+        ldr             x13, [sp]                                       // srcV
+        ldr             w14, [sp, #8]                                   // linesizeV
+        ldr             x8,  [sp, #16]                                  // table
+        load_yoff_ycoeff 24, 32                                          // y_offset, y_coeff
+        ld1             {v1.1d}, [x8]
+        dup             v0.8h, w10
+        dup             v3.8h, w9
+.ifc \ofmt,gbrp
+        load_dst1_dst2  40, 48, 56, 64
+        sub             w3, w3, w0                                      // w3 = linesize  - width     (padding)
+.else
+ .ifc \ofmt,rgb24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+ .else
+  .ifc \ofmt,bgr24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+  .else
+        sub             w3, w3, w0, lsl #2                              // w3 = linesize  - width * 4 (padding)
+  .endif
+ .endif
+.endif
+        sub             w5, w5, w0                                      // w5 = linesizeY - width     (paddingY)
+        sub             w7,  w7,  w0, lsr #1                            // w7  = linesizeU - width / 2 (paddingU)
+        sub             w14, w14, w0, lsr #1                            // w14 = linesizeV - width / 2 (paddingV)
+        lsr             w11, w0, #1
+        neg             w11, w11
+.endm
+
+.macro load_args_yuva420p ofmt
+        load_args_yuv420p \ofmt
+#if defined(__APPLE__)
+        ldr             x15, [sp, #32]                                  // srcA
+        ldr             w16, [sp, #40]                                  // linesizeA
+#else
+        ldr             x15, [sp, #40]                                  // srcA
+        ldr             w16, [sp, #48]                                  // linesizeA
+#endif
+        sub             w16, w16, w0                                    // w16 = linesizeA - width    (paddingA)
+.endm
+
+.macro load_args_yuv422p ofmt
+        ldr             x13, [sp]                                       // srcV
+        ldr             w14, [sp, #8]                                   // linesizeV
+        ldr             x8,  [sp, #16]                                  // table
+        load_yoff_ycoeff 24, 32                                          // y_offset, y_coeff
+        ld1             {v1.1d}, [x8]
+        dup             v0.8h, w10
+        dup             v3.8h, w9
+.ifc \ofmt,gbrp
+        load_dst1_dst2  40, 48, 56, 64
+        sub             w3, w3, w0                                      // w3 = linesize  - width     (padding)
+.else
+ .ifc \ofmt,rgb24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+ .else
+  .ifc \ofmt,bgr24
+        add             w17, w0, w0, lsl #1
+        sub             w3, w3, w17                                     // w3 = linesize  - width * 3 (padding)
+  .else
+        sub             w3, w3, w0, lsl #2                              // w3 = linesize  - width * 4 (padding)
+  .endif
+ .endif
+.endif
+        sub             w5, w5, w0                                      // w5 = linesizeY - width     (paddingY)
+        sub             w7,  w7,  w0, lsr #1                            // w7  = linesizeU - width / 2 (paddingU)
+        sub             w14, w14, w0, lsr #1                            // w14 = linesizeV - width / 2 (paddingV)
+.endm
+
+.macro load_chroma_nv12
+        ld2             {v16.8b, v17.8b}, [x6], #16
+        ushll           v18.8h, v16.8b, #3
+        ushll           v19.8h, v17.8b, #3
+.endm
+
+.macro load_chroma_nv21
+        ld2             {v16.8b, v17.8b}, [x6], #16
+        ushll           v19.8h, v16.8b, #3
+        ushll           v18.8h, v17.8b, #3
+.endm
+
+.macro load_chroma_yuv420p
+        ld1             {v16.8b}, [ x6], #8
+        ld1             {v17.8b}, [x13], #8
+        ushll           v18.8h, v16.8b, #3
+        ushll           v19.8h, v17.8b, #3
+.endm
+
+.macro load_chroma_yuva420p
+        load_chroma_yuv420p
+.endm
+
+.macro load_chroma_yuv422p
+        load_chroma_yuv420p
+.endm
+
+.macro increment_nv12
+        ands            w17, w1, #1
+        csel            w17, w7, w11, ne                                // incC = (h & 1) ? paddincC : -width
+        add             x6,  x6, w17, sxtw                              // srcC += incC
+.endm
+
+.macro increment_nv21
+        increment_nv12
+.endm
+
+.macro increment_yuv420p
+        ands            w17, w1, #1
+        csel            w17,  w7, w11, ne                               // incU = (h & 1) ? paddincU : -width/2
+        add             x6,  x6,  w17, sxtw                             // srcU += incU
+        csel            w17, w14, w11, ne                               // incV = (h & 1) ? paddincV : -width/2
+        add             x13, x13, w17, sxtw                             // srcV += incV
+.endm
+
+.macro increment_yuva420p
+        increment_yuv420p
+        add             x15, x15, w16, sxtw                             // srcA += paddingA (every row)
+.endm
+
+.macro increment_yuv422p
+        add             x6,  x6,  w7, sxtw                              // srcU += incU
+        add             x13, x13, w14, sxtw                             // srcV += incV
+.endm
+
+.macro compute_rgb r1 g1 b1 r2 g2 b2
+        add             v20.8h, v26.8h, v20.8h                          // Y1 + R1
+        add             v21.8h, v27.8h, v21.8h                          // Y2 + R2
+        add             v22.8h, v26.8h, v22.8h                          // Y1 + G1
+        add             v23.8h, v27.8h, v23.8h                          // Y2 + G2
+        add             v24.8h, v26.8h, v24.8h                          // Y1 + B1
+        add             v25.8h, v27.8h, v25.8h                          // Y2 + B2
+        sqrshrun        \r1, v20.8h, #1                                 // clip_u8((Y1 + R1) >> 1)
+        sqrshrun        \r2, v21.8h, #1                                 // clip_u8((Y2 + R1) >> 1)
+        sqrshrun        \g1, v22.8h, #1                                 // clip_u8((Y1 + G1) >> 1)
+        sqrshrun        \g2, v23.8h, #1                                 // clip_u8((Y2 + G1) >> 1)
+        sqrshrun        \b1, v24.8h, #1                                 // clip_u8((Y1 + B1) >> 1)
+        sqrshrun        \b2, v25.8h, #1                                 // clip_u8((Y2 + B1) >> 1)
+.endm
+
+.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2
+        compute_rgb     \r1, \g1, \b1, \r2, \g2, \b2
+        mov             \a1, v30.8b
+        mov             \a2, v30.8b
+.endm
+
+.macro compute_rgba_alpha r1 g1 b1 a1 r2 g2 b2 a2
+        compute_rgb     \r1, \g1, \b1, \r2, \g2, \b2
+        mov             \a1, v28.8b                                     // real alpha (first 8 pixels)
+        mov             \a2, v29.8b                                     // real alpha (next 8 pixels)
+.endm
+
+.macro declare_func ifmt ofmt
+function ff_\ifmt\()_to_\ofmt\()_neon, export=1
+        load_args_\ifmt \ofmt
+
+        movi            v31.8h, #4, lsl #8                              // 128 * (1<<3) (loop-invariant)
+        movi            v30.8b, #255                                    // alpha = 255  (loop-invariant)
+        mov             w9, w1
+1:
+        mov             w8, w0                                          // w8 = width
+2:
+        load_chroma_\ifmt
+        sub             v18.8h, v18.8h, v31.8h                          // U*(1<<3) - 128*(1<<3)
+        sub             v19.8h, v19.8h, v31.8h                          // V*(1<<3) - 128*(1<<3)
+        sqdmulh         v20.8h, v19.8h, v1.h[0]                         // V * v2r            (R)
+        sqdmulh         v22.8h, v18.8h, v1.h[1]                         // U * u2g
+        ld1             {v2.16b}, [x4], #16                             // load luma (interleaved)
+.ifc \ifmt,yuva420p
+        ld1             {v28.8b, v29.8b}, [x15], #16                    // load 16 alpha bytes
+.endif
+        sqdmulh         v19.8h, v19.8h, v1.h[2]                         //           V * v2g
+        sqdmulh         v24.8h, v18.8h, v1.h[3]                         // U * u2b            (B)
+        ushll           v26.8h, v2.8b,  #3                              // Y1*(1<<3)
+        ushll2          v27.8h, v2.16b, #3                              // Y2*(1<<3)
+        add             v22.8h, v22.8h, v19.8h                          // U * u2g + V * v2g  (G)
+        sub             v26.8h, v26.8h, v3.8h                           // Y1*(1<<3) - y_offset
+        sub             v27.8h, v27.8h, v3.8h                           // Y2*(1<<3) - y_offset
+        zip2            v21.8h, v20.8h, v20.8h                          // R2
+        zip1            v20.8h, v20.8h, v20.8h                          // R1
+        sqdmulh         v26.8h, v26.8h, v0.8h                           // ((Y1*(1<<3) - y_offset) * y_coeff) >> 15
+        sqdmulh         v27.8h, v27.8h, v0.8h                           // ((Y2*(1<<3) - y_offset) * y_coeff) >> 15
+        zip2            v23.8h, v22.8h, v22.8h                          // G2
+        zip1            v22.8h, v22.8h, v22.8h                          // G1
+        zip2            v25.8h, v24.8h, v24.8h                          // B2
+        zip1            v24.8h, v24.8h, v24.8h                          // B1
+
+.ifc \ofmt,argb // 1 2 3 0
+ .ifc \ifmt,yuva420p
+        compute_rgba_alpha v5.8b,v6.8b,v7.8b,v4.8b, v17.8b,v18.8b,v19.8b,v16.8b
+ .else
+        compute_rgba    v5.8b,v6.8b,v7.8b,v4.8b, v17.8b,v18.8b,v19.8b,v16.8b
+ .endif
+.endif
+
+.ifc \ofmt,rgba // 0 1 2 3
+ .ifc \ifmt,yuva420p
+        compute_rgba_alpha v4.8b,v5.8b,v6.8b,v7.8b, v16.8b,v17.8b,v18.8b,v19.8b
+ .else
+        compute_rgba    v4.8b,v5.8b,v6.8b,v7.8b, v16.8b,v17.8b,v18.8b,v19.8b
+ .endif
+.endif
+
+.ifc \ofmt,abgr // 3 2 1 0
+ .ifc \ifmt,yuva420p
+        compute_rgba_alpha v7.8b,v6.8b,v5.8b,v4.8b, v19.8b,v18.8b,v17.8b,v16.8b
+ .else
+        compute_rgba    v7.8b,v6.8b,v5.8b,v4.8b, v19.8b,v18.8b,v17.8b,v16.8b
+ .endif
+.endif
+
+.ifc \ofmt,bgra // 2 1 0 3
+ .ifc \ifmt,yuva420p
+        compute_rgba_alpha v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b
+ .else
+        compute_rgba    v6.8b,v5.8b,v4.8b,v7.8b, v18.8b,v17.8b,v16.8b,v19.8b
+ .endif
+.endif
+
+.ifc \ofmt,rgb24
+        compute_rgb     v4.8b,v5.8b,v6.8b, v16.8b,v17.8b,v18.8b
+        st3             { v4.8b, v5.8b, v6.8b}, [x2], #24
+        st3             {v16.8b,v17.8b,v18.8b}, [x2], #24
+.else
+ .ifc \ofmt,bgr24
+        compute_rgb     v6.8b,v5.8b,v4.8b, v18.8b,v17.8b,v16.8b
+        st3             { v4.8b, v5.8b, v6.8b}, [x2], #24
+        st3             {v16.8b,v17.8b,v18.8b}, [x2], #24
+ .else
+  .ifc \ofmt,gbrp
+        compute_rgb     v18.8b,v4.8b,v6.8b, v19.8b,v5.8b,v7.8b
+        st1             {  v4.8b,  v5.8b }, [x2],  #16
+        st1             {  v6.8b,  v7.8b }, [x10], #16
+        st1             { v18.8b, v19.8b }, [x15], #16
+  .else
+        st4             { v4.8b, v5.8b, v6.8b, v7.8b}, [x2], #32
+        st4             {v16.8b,v17.8b,v18.8b,v19.8b}, [x2], #32
+  .endif
+ .endif
+.endif
+        subs            w8, w8, #16                                     // width -= 16
+        b.gt            2b
+        add             x2, x2, w3, sxtw                                // dst  += padding
+.ifc \ofmt,gbrp
+        add             x10, x10, w12, sxtw                             // dst1 += padding1
+        add             x15, x15, w16, sxtw                             // dst2 += padding2
+.endif
+        add             x4, x4, w5, sxtw                                // srcY += paddingY
+        increment_\ifmt
+        subs            w1, w1, #1                                      // height -= 1
+        b.gt            1b
+        mov             w0, w9
+        ret
+endfunc
+.endm
+
+.macro declare_rgb_funcs ifmt
+        declare_func    \ifmt, argb
+        declare_func    \ifmt, rgba
+        declare_func    \ifmt, abgr
+        declare_func    \ifmt, bgra
+        declare_func    \ifmt, gbrp
+        declare_func    \ifmt, rgb24
+        declare_func    \ifmt, bgr24
+.endm
+
+declare_rgb_funcs nv12
+declare_rgb_funcs nv21
+declare_rgb_funcs yuv420p
+declare_rgb_funcs yuv422p
+
+.macro declare_yuva_funcs ifmt
+        declare_func    \ifmt, argb
+        declare_func    \ifmt, rgba
+        declare_func    \ifmt, abgr
+        declare_func    \ifmt, bgra
+.endm
+
+declare_yuva_funcs yuva420p
diff --git a/libs/ffmpeg/libswscale/alphablend.c b/libs/ffmpeg/libswscale/alphablend.c
new file mode 100644
index 000000000000..45db5189d2b2
--- /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/arm/hscale.S b/libs/ffmpeg/libswscale/arm/hscale.S
new file mode 100644
index 000000000000..5c3551a0f19f
--- /dev/null
+++ b/libs/ffmpeg/libswscale/arm/hscale.S
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Clément Bœsch <clement stupeflix.com>
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.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/arm/asm.S"
+
+function ff_hscale_8_to_15_neon, export=1
+    push                {r4-r12, lr}
+    vpush               {q4-q7}
+    ldr                 r4, [sp, #104]                                 @ filter
+    ldr                 r5, [sp, #108]                                 @ filterPos
+    ldr                 r6, [sp, #112]                                 @ filterSize
+    add                 r10, r4, r6, lsl #1                            @ filter2 = filter + filterSize * 2
+1:  ldr                 r8, [r5], #4                                   @ filterPos[0]
+    ldr                 r9, [r5], #4                                   @ filterPos[1]
+    vmov.s32            q4, #0                                         @ val accumulator
+    vmov.s32            q5, #0                                         @ val accumulator
+    mov                 r7, r6                                         @ tmpfilterSize = filterSize
+    mov                 r0, r3                                         @ srcp
+2:  add                 r11, r0, r8                                    @ srcp + filterPos[0]
+    add                 r12, r0, r9                                    @ srcp + filterPos[1]
+    vld1.8              d0, [r11]                                      @ srcp[filterPos[0] + {0..7}]
+    vld1.8              d2, [r12]                                      @ srcp[filterPos[1] + {0..7}]
+    vld1.16             {q2}, [r4]!                                    @ load 8x16-bit filter values
+    vld1.16             {q3}, [r10]!                                   @ load 8x16-bit filter values
+    vmovl.u8            q0, d0                                         @ unpack src values to 16-bit
+    vmovl.u8            q1, d2                                         @ unpack src values to 16-bit
+    vmull.s16           q8, d0, d4                                     @ srcp[filterPos[0] + {0..7}] * filter[{0..7}] (part 1)
+    vmull.s16           q9, d1, d5                                     @ srcp[filterPos[0] + {0..7}] * filter[{0..7}] (part 2)
+    vmull.s16           q10, d2, d6                                    @ srcp[filterPos[1] + {0..7}] * filter[{0..7}] (part 1)
+    vmull.s16           q11, d3, d7                                    @ srcp[filterPos[1] + {0..7}] * filter[{0..7}] (part 2)
+    vpadd.s32           d16, d16, d17                                  @ horizontal pair adding of the 8x32-bit multiplied values into 4x32-bit (part 1)
+    vpadd.s32           d17, d18, d19                                  @ horizontal pair adding of the 8x32-bit multiplied values into 4x32-bit (part 2)
+    vpadd.s32           d20, d20, d21                                  @ horizontal pair adding of the 8x32-bit multiplied values into 4x32-bit (part 1)
+    vpadd.s32           d21, d22, d23                                  @ horizontal pair adding of the 8x32-bit multiplied values into 4x32-bit (part 2)
+    vadd.s32            q4, q8                                         @ update val accumulator
+    vadd.s32            q5, q10                                        @ update val accumulator
+    add                 r0, #8                                         @ srcp += 8
+    subs                r7, #8                                         @ tmpfilterSize -= 8
+    bgt                 2b                                             @ loop until tmpfilterSize is consumed
+    mov                 r4, r10                                        @ filter = filter2
+    add                 r10, r10, r6, lsl #1                           @ filter2 += filterSize * 2
+    vpadd.s32           d8, d8, d9                                     @ horizontal pair adding of the 8x32-bit sums into 4x32-bit (part 1)
+    vpadd.s32           d9, d10, d11                                   @ horizontal pair adding of the 8x32-bit sums into 4x32-bit (part 2)
+    vpadd.s32           d8, d8, d9                                     @ horizontal pair adding of the 4x32-bit sums into 2x32-bit
+    vqshrn.s32          d8, q4, #7                                     @ shift and clip the 2x16-bit final values
+    vst1.32             {d8[0]},[r1]!                                  @ write destination
+    subs                r2, #2                                         @ dstW -= 2
+    bgt                 1b                                             @ loop until end of line
+    vpop                {q4-q7}
+    pop                 {r4-r12, pc}
+endfunc
diff --git a/libs/ffmpeg/libswscale/arm/output.S b/libs/ffmpeg/libswscale/arm/output.S
new file mode 100644
index 000000000000..670c6189e084
--- /dev/null
+++ b/libs/ffmpeg/libswscale/arm/output.S
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Clément Bœsch <clement stupeflix.com>
+ * Copyright (c) 2016 Matthieu Bouron <matthieu.bouron stupeflix.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/arm/asm.S"
+
+function ff_yuv2planeX_8_neon, export=1
+    push {r4-r12, lr}
+    vpush {q4-q7}
+    ldr                 r4, [sp, #104]                                 @ dstW
+    ldr                 r5, [sp, #108]                                 @ dither
+    ldr                 r6, [sp, #112]                                 @ offset
+    vld1.8              {d0}, [r5]                                     @ load 8x8-bit dither values
+    cmp                 r6, #0                                         @ check offsetting which can be 0 or 3 only
+    beq                 1f
+    vext.u8             d0, d0, d0, #3                                 @ honor offsetting which can be 3 only
+1:  vmovl.u8            q0, d0                                         @ extend dither to 16-bit
+    vshll.u16           q1, d0, #12                                    @ extend dither to 32-bit with left shift by 12 (part 1)
+    vshll.u16           q2, d1, #12                                    @ extend dither to 32-bit with left shift by 12 (part 2)
+    mov                 r7, #0                                         @ i = 0
+2:  vmov.u8             q3, q1                                         @ initialize accumulator with dithering values (part 1)
+    vmov.u8             q4, q2                                         @ initialize accumulator with dithering values (part 2)
+    mov                 r8, r1                                         @ tmpFilterSize = filterSize
+    mov                 r9, r2                                         @ srcp
+    mov                 r10, r0                                        @ filterp
+3:  ldr                 r11, [r9], #4                                  @ get pointer @ src[j]
+    ldr                 r12, [r9], #4                                  @ get pointer @ src[j+1]
+    add                 r11, r11, r7, lsl #1                           @ &src[j][i]
+    add                 r12, r12, r7, lsl #1                           @ &src[j+1][i]
+    vld1.16             {q5}, [r11]                                    @ read 8x16-bit @ src[j  ][i + {0..7}]: A,B,C,D,E,F,G,H
+    vld1.16             {q6}, [r12]                                    @ read 8x16-bit @ src[j+1][i + {0..7}]: I,J,K,L,M,N,O,P
+    ldr                 r11, [r10], #4                                 @ read 2x16-bit coeffs (X, Y) at (filter[j], filter[j+1])
+    vmov.16             q7, q5                                         @ copy 8x16-bit @ src[j  ][i + {0..7}] for following inplace zip instruction
+    vmov.16             q8, q6                                         @ copy 8x16-bit @ src[j+1][i + {0..7}] for following inplace zip instruction
+    vzip.16             q7, q8                                         @ A,I,B,J,C,K,D,L,E,M,F,N,G,O,H,P
+    vdup.32             q15, r11                                       @ X,Y,X,Y,X,Y,X,Y
+    vmull.s16           q9, d14, d30                                   @ A*X,I*Y,B*X,J*Y
+    vmull.s16           q10, d15, d31                                  @ C*X,K*Y,D*X,L*Y
+    vmull.s16           q11, d16, d30                                  @ E*X,M*Y,F*X,N*Y
+    vmull.s16           q12, d17, d31                                  @ G*X,O*Y,H*X,P*Y
+    vpadd.s32           d10, d18, d19                                  @ A*X+I*Y,B*X+J*Y
+    vpadd.s32           d11, d20, d21                                  @ C*X+K*Y,D*X+L*Y
+    vpadd.s32           d12, d22, d23                                  @ E*X+M*Y,F*X+N*Y
+    vpadd.s32           d13, d24, d25                                  @ G*X+O*Y,H*X+P*Y
+    vadd.s32            q3, q5                                         @ update val accumulator (part 1)
+    vadd.s32            q4, q6                                         @ update val accumulator (part 2)
+    subs                r8, #2                                         @ tmpFilterSize -= 2
+    bgt                 3b                                             @ loop until filterSize is consumed
+    vshr.s32            q3, q3, #19                                    @ val>>19 (part 1)
+    vshr.s32            q4, q4, #19                                    @ val>>19 (part 2)
+    vqmovun.s32         d6, q3                                         @ clip16(val>>19) (part 1)
+    vqmovun.s32         d7, q4                                         @ clip16(val>>19) (part 2)
+    vqmovn.u16          d6, q3                                         @ merge part 1 and part 2
+    vst1.8              {d6}, [r3]!                                    @ write destination
+    add                 r7, #8                                         @ i += 8
+    subs                r4, r4, #8                                     @ dstW -= 8
+    bgt                 2b                                             @ loop until width is consumed
+    vpop                {q4-q7}
+    pop                 {r4-r12, pc}
+endfunc
diff --git a/libs/ffmpeg/libswscale/arm/swscale.c b/libs/ffmpeg/libswscale/arm/swscale.c
new file mode 100644
index 000000000000..f4a96292eb81
--- /dev/null
+++ b/libs/ffmpeg/libswscale/arm/swscale.c
@@ -0,0 +1,48 @@
+/*
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General 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 "libavutil/attributes.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/arm/cpu.h"
+
+void ff_hscale_8_to_15_neon(SwsInternal *c, int16_t *dst, int dstW,
+                            const uint8_t *src, const int16_t *filter,
+                            const int32_t *filterPos, int filterSize);
+
+void ff_yuv2planeX_8_neon(const int16_t *filter, int filterSize,
+                          const int16_t **src, uint8_t *dest, int dstW,
+                          const uint8_t *dither, int offset);
+
+av_cold void ff_sws_init_swscale_arm(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+    if (have_neon(cpu_flags)) {
+        if (c->srcBpc == 8 && c->dstBpc <= 14 &&
+            (c->hLumFilterSize % 8) == 0 &&
+            (c->hChrFilterSize % 8) == 0)
+        {
+            c->hyScale = c->hcScale = ff_hscale_8_to_15_neon;
+        }
+        if (c->dstBpc == 8) {
+            c->yuv2planeX = ff_yuv2planeX_8_neon;
+        }
+    }
+}
diff --git a/libs/ffmpeg/libswscale/arm/swscale_unscaled.c b/libs/ffmpeg/libswscale/arm/swscale_unscaled.c
new file mode 100644
index 000000000000..c526ea1c5069
--- /dev/null
+++ b/libs/ffmpeg/libswscale/arm/swscale_unscaled.c
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2013 Xiaolei Yu <dreifachstein@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"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/arm/cpu.h"
+
+#if HAVE_AS_DN_DIRECTIVE
+extern void rgbx_to_nv12_neon_32(const uint8_t *src, uint8_t *y, uint8_t *chroma,
+                int width, int height,
+                int y_stride, int c_stride, int src_stride,
+                int32_t coeff_tbl[9]);
+
+extern void rgbx_to_nv12_neon_16(const uint8_t *src, uint8_t *y, uint8_t *chroma,
+                int width, int height,
+                int y_stride, int c_stride, int src_stride,
+                int32_t coeff_tbl[9]);
+
+static int rgbx_to_nv12_neon_32_wrapper(SwsInternal *context, const uint8_t *const src[],
+                        const int srcStride[], int srcSliceY, int srcSliceH,
+                        uint8_t *const dst[], const int dstStride[]) {
+
+    rgbx_to_nv12_neon_32(src[0] + srcSliceY * srcStride[0],
+            dst[0] + srcSliceY * dstStride[0],
+            dst[1] + (srcSliceY / 2) * dstStride[1],
+            context->opts.src_w, srcSliceH,
+            dstStride[0], dstStride[1], srcStride[0],
+            context->input_rgb2yuv_table);
+
+    return 0;
+}
+
+static int rgbx_to_nv12_neon_16_wrapper(SwsInternal *context, const uint8_t *const src[],
+                        const int srcStride[], int srcSliceY, int srcSliceH,
+                        uint8_t *const dst[], const int dstStride[]) {
+
+    rgbx_to_nv12_neon_16(src[0] + srcSliceY * srcStride[0],
+            dst[0] + srcSliceY * dstStride[0],
+            dst[1] + (srcSliceY / 2) * dstStride[1],
+            context->opts.src_w, srcSliceH,
+            dstStride[0], dstStride[1], srcStride[0],
+            context->input_rgb2yuv_table);
+
+    return 0;
+}
+
+#define YUV_TO_RGB_TABLE                                                                    \
+        c->yuv2rgb_v2r_coeff,                                                               \
+        c->yuv2rgb_u2g_coeff,                                                               \
+        c->yuv2rgb_v2g_coeff,                                                               \
+        c->yuv2rgb_u2b_coeff,                                                               \
+
+#define DECLARE_FF_YUVX_TO_RGBX_FUNCS(ifmt, ofmt)                                           \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcU, int linesizeU,                        \
+                                 const uint8_t *srcV, int linesizeV,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff);                                              \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                                  \
+                                 dst[0] + srcSliceY * dstStride[0], dstStride[0],           \
+                                 src[0], srcStride[0],                                      \
+                                 src[1], srcStride[1],                                      \
+                                 src[2], srcStride[2],                                      \
+                                 yuv2rgb_table,                                             \
+                                 c->yuv2rgb_y_offset >> 6,                                  \
+                                 c->yuv2rgb_y_coeff);                                       \
+                                                                                            \
+    return 0;                                                                               \
+}                                                                                           \
+
+#define DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuvx)                                             \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, argb)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, rgba)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, abgr)                                                   \
+DECLARE_FF_YUVX_TO_RGBX_FUNCS(yuvx, bgra)                                                   \
+
+DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv420p)
+DECLARE_FF_YUVX_TO_ALL_RGBX_FUNCS(yuv422p)
+
+#define DECLARE_FF_NVX_TO_RGBX_FUNCS(ifmt, ofmt)                                            \
+int ff_##ifmt##_to_##ofmt##_neon(int w, int h,                                              \
+                                 uint8_t *dst, int linesize,                                \
+                                 const uint8_t *srcY, int linesizeY,                        \
+                                 const uint8_t *srcC, int linesizeC,                        \
+                                 const int16_t *table,                                      \
+                                 int y_offset,                                              \
+                                 int y_coeff);                                              \
+                                                                                            \
+static int ifmt##_to_##ofmt##_neon_wrapper(SwsInternal *c, const uint8_t *const src[],      \
+                                           const int srcStride[], int srcSliceY,            \
+                                           int srcSliceH, uint8_t *const dst[],             \
+                                           const int dstStride[]) {                         \
+    const int16_t yuv2rgb_table[] = { YUV_TO_RGB_TABLE };                                   \
+                                                                                            \
+    ff_##ifmt##_to_##ofmt##_neon(c->opts.src_w, srcSliceH,                                  \
+                                 dst[0] + srcSliceY * dstStride[0], dstStride[0],           \
+                                 src[0], srcStride[0], src[1], srcStride[1],                \
+                                 yuv2rgb_table,                                             \
+                                 c->yuv2rgb_y_offset >> 6,                                  \
+                                 c->yuv2rgb_y_coeff);                                       \
+                                                                                            \
+    return 0;                                                                               \
+}                                                                                           \
+
+#define DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nvx)                                               \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, argb)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, rgba)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, abgr)                                                     \
+DECLARE_FF_NVX_TO_RGBX_FUNCS(nvx, bgra)                                                     \
+
+DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv12)
+DECLARE_FF_NVX_TO_ALL_RGBX_FUNCS(nv21)
+
+/* We need a 16 pixel width alignment. This constraint can easily be removed
+ * for input reading but for the output which is 4-bytes per pixel (RGBA) the
+ * assembly might be writing as much as 4*15=60 extra bytes at the end of the
+ * line, which won't fit the 32-bytes buffer alignment. */
+#define SET_FF_NVX_TO_RGBX_FUNC(ifmt, IFMT, ofmt, OFMT, accurate_rnd) do {                  \
+    if (c->opts.src_format == AV_PIX_FMT_##IFMT                                             \
+        && c->opts.dst_format == AV_PIX_FMT_##OFMT                                          \
+        && !(c->opts.src_h & 1)                                                             \
+        && !(c->opts.src_w & 15)                                                            \
+        && !accurate_rnd) {                                                                 \
+        c->convert_unscaled = ifmt##_to_##ofmt##_neon_wrapper;                              \
+    }                                                                                       \
+} while (0)
+
+#define SET_FF_NVX_TO_ALL_RGBX_FUNC(nvx, NVX, accurate_rnd) do {                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, argb, ARGB, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, rgba, RGBA, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, abgr, ABGR, accurate_rnd);                            \
+    SET_FF_NVX_TO_RGBX_FUNC(nvx, NVX, bgra, BGRA, accurate_rnd);                            \
+} while (0)
+
+static void get_unscaled_swscale_neon(SwsInternal *c) {
+    int accurate_rnd = c->opts.flags & SWS_ACCURATE_RND;
+    if (c->opts.src_format == AV_PIX_FMT_RGBA
+            && c->opts.dst_format == AV_PIX_FMT_NV12
+            && (c->opts.src_w >= 16)) {
+        c->convert_unscaled = accurate_rnd ? rgbx_to_nv12_neon_32_wrapper
+                                           : rgbx_to_nv12_neon_16_wrapper;
+    }
+
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(nv12, NV12, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(nv21, NV21, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv420p, YUV420P, accurate_rnd);
+    SET_FF_NVX_TO_ALL_RGBX_FUNC(yuv422p, YUV422P, accurate_rnd);
+}
+
+void ff_get_unscaled_swscale_arm(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+    if (have_neon(cpu_flags))
+        get_unscaled_swscale_neon(c);
+}
+#else
+void ff_get_unscaled_swscale_arm(SwsInternal *c)
+{
+}
+#endif
diff --git a/libs/ffmpeg/libswscale/arm/yuv2rgb_neon.S b/libs/ffmpeg/libswscale/arm/yuv2rgb_neon.S
new file mode 100644
index 000000000000..6777d625f980
--- /dev/null
+++ b/libs/ffmpeg/libswscale/arm/yuv2rgb_neon.S
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2015 Matthieu Bouron <matthieu.bouron stupeflix.com>
+ * Copyright (c) 2015 Clément Bœsch <clement stupeflix.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/arm/asm.S"
+
+
+.macro compute_premult
+    vsub.u16            q14,q11                                        @ q14 = U * (1 << 3) - 128 * (1 << 3)
+    vsub.u16            q15,q11                                        @ q15 = V * (1 << 3) - 128 * (1 << 3)
+    vqdmulh.s16         q8, q15, d1[0]                                 @ q8  = V * v2r
+    vqdmulh.s16         q9, q14, d1[1]                                 @ q9  = U * u2g
+    vqdmulh.s16         q5, q15, d1[2]                                 @ q5  = V * v2g
+    vadd.s16            q9, q5                                         @ q9  = U * u2g + V * v2g
+    vqdmulh.s16         q10,q14, d1[3]                                 @ q10 = U * u2b
+.endm
+
+.macro compute_color dst_comp1 dst_comp2 pre
+    vadd.s16            q1, q14, \pre
+    vadd.s16            q2, q15, \pre
+    vqrshrun.s16        \dst_comp1, q1, #1
+    vqrshrun.s16        \dst_comp2, q2, #1
+.endm
+
+.macro compute_rgba r1 g1 b1 a1 r2 g2 b2 a2
+    compute_color       \r1, \r2, q8
+    compute_color       \g1, \g2, q9
+    compute_color       \b1, \b2, q10
+    vmov.u8             \a1, #255
+    vmov.u8             \a2, #255
+.endm
+
+.macro compute dst ofmt
+    vshll.u8            q14, d14, #3                                   @ q14 = Y * (1 << 3)
+    vshll.u8            q15, d15, #3                                   @ q15 = Y * (1 << 3)
+    vsub.s16            q14, q12                                       @ q14 = (Y - y_offset)
+    vsub.s16            q15, q12                                       @ q15 = (Y - y_offset)
+    vqdmulh.s16         q14, q13                                       @ q14 = (Y - y_offset) * y_coeff
+    vqdmulh.s16         q15, q13                                       @ q15 = (Y - y_offset) * y_coeff
+
+.ifc \ofmt,argb
+    compute_rgba        d7, d8, d9, d6, d11, d12, d13, d10
+.endif
+
+.ifc \ofmt,rgba
+    compute_rgba        d6, d7, d8, d9, d10, d11, d12, d13
+.endif
+
+.ifc \ofmt,abgr
+    compute_rgba        d9, d8, d7, d6, d13, d12, d11, d10
+.endif
+
+.ifc \ofmt,bgra
+    compute_rgba        d8, d7, d6, d9, d12, d11, d10, d13
+.endif
+
+    vzip.8              d6, d10                                        @ d6 = R1R2R3R4R5R6R7R8 d10 = R9R10R11R12R13R14R15R16
+    vzip.8              d7, d11                                        @ d7 = G1G2G3G4G5G6G7G8 d11 = G9G10G11G12G13G14G15G16
+    vzip.8              d8, d12                                        @ d8 = B1B2B3B4B5B6B7B8 d12 = B9B10B11B12B13B14B15B16
+    vzip.8              d9, d13                                        @ d9 = A1A2A3A4A5A6A7A8 d13 = A9A10A11A12A13A14A15A16
+    vst4.8              {q3, q4}, [\dst]!
+    vst4.8              {q5, q6}, [\dst]!
+.endm
+
+.macro process_1l_internal dst src ofmt
+    vld2.8              {d14, d15}, [\src]!                            @ q7 = Y (interleaved)
+    compute             \dst, \ofmt
+.endm
+
+.macro process_1l ofmt
+    compute_premult
+    process_1l_internal r2, r4, \ofmt
+.endm
+
+.macro process_2l ofmt
+    compute_premult
+    process_1l_internal r2, r4, \ofmt
+    process_1l_internal r11,r12,\ofmt
+.endm
+
+.macro load_args_nv12
+    push                {r4-r12, lr}
+    vpush               {q4-q7}
+    ldr                 r4, [sp, #104]                                 @ r4  = srcY
+    ldr                 r5, [sp, #108]                                 @ r5  = linesizeY
+    ldr                 r6, [sp, #112]                                 @ r6  = srcC
+    ldr                 r7, [sp, #116]                                 @ r7  = linesizeC
+    ldr                 r8, [sp, #120]                                 @ r8  = table
+    ldr                 r9, [sp, #124]                                 @ r9  = y_offset
+    ldr                 r10,[sp, #128]                                 @ r10 = y_coeff
+    vdup.16             d0, r10                                        @ d0  = y_coeff
+    vld1.16             {d1}, [r8]                                     @ d1  = *table
+    add                 r11, r2, r3                                    @ r11 = dst + linesize (dst2)
+    add                 r12, r4, r5                                    @ r12 = srcY + linesizeY (srcY2)
+    lsl                 r3, r3, #1
+    lsl                 r5, r5, #1
+    sub                 r3, r3, r0, lsl #2                             @ r3 = linesize  * 2 - width * 4 (padding)
+    sub                 r5, r5, r0                                     @ r5 = linesizeY * 2 - width     (paddingY)
+    sub                 r7, r7, r0                                     @ r7 = linesizeC     - width     (paddingC)
+.endm
+
+.macro load_args_nv21
+    load_args_nv12
+.endm
+
+.macro load_args_yuv420p
+    push                {r4-r12, lr}
+    vpush               {q4-q7}
+    ldr                 r4, [sp, #104]                                 @ r4  = srcY
+    ldr                 r5, [sp, #108]                                 @ r5  = linesizeY
+    ldr                 r6, [sp, #112]                                 @ r6  = srcU
+    ldr                 r8, [sp, #128]                                 @ r8  = table
+    ldr                 r9, [sp, #132]                                 @ r9  = y_offset
+    ldr                 r10,[sp, #136]                                 @ r10 = y_coeff
+    vdup.16             d0, r10                                        @ d0  = y_coeff
+    vld1.16             {d1}, [r8]                                     @ d1  = *table
+    add                 r11, r2, r3                                    @ r11 = dst + linesize (dst2)
+    add                 r12, r4, r5                                    @ r12 = srcY + linesizeY (srcY2)
+    lsl                 r3, r3, #1
+    lsl                 r5, r5, #1
+    sub                 r3, r3, r0, lsl #2                             @ r3 = linesize  * 2 - width * 4 (padding)
+    sub                 r5, r5, r0                                     @ r5 = linesizeY * 2 - width     (paddingY)
+    ldr                 r10,[sp, #120]                                 @ r10 = srcV
+.endm
+
+.macro load_args_yuv422p
+    push                {r4-r12, lr}
+    vpush               {q4-q7}
+    ldr                 r4, [sp, #104]                                 @ r4  = srcY
+    ldr                 r5, [sp, #108]                                 @ r5  = linesizeY
+    ldr                 r6, [sp, #112]                                 @ r6  = srcU
+    ldr                 r7, [sp, #116]                                 @ r7  = linesizeU
+    ldr                 r12,[sp, #124]                                 @ r12 = linesizeV
+    ldr                 r8, [sp, #128]                                 @ r8  = table
+    ldr                 r9, [sp, #132]                                 @ r9  = y_offset
+    ldr                 r10,[sp, #136]                                 @ r10 = y_coeff
+    vdup.16             d0, r10                                        @ d0  = y_coeff
+    vld1.16             {d1}, [r8]                                     @ d1  = *table
+    sub                 r3, r3, r0, lsl #2                             @ r3  = linesize  - width * 4 (padding)
+    sub                 r5, r5, r0                                     @ r5  = linesizeY - width     (paddingY)
+    sub                 r7, r7, r0, lsr #1                             @ r7  = linesizeU - width / 2 (paddingU)
+    sub                 r12,r12,r0, lsr #1                             @ r12 = linesizeV - width / 2 (paddingV)
+    ldr                 r10,[sp, #120]                                 @ r10 = srcV
+.endm
+
+.macro load_chroma_nv12
+    pld [r12, #64*3]
+
+    vld2.8              {d2, d3}, [r6]!                                @ q1: interleaved chroma line
+    vshll.u8            q14, d2, #3                                    @ q14 = U * (1 << 3)
+    vshll.u8            q15, d3, #3                                    @ q15 = V * (1 << 3)
+.endm
+
+.macro load_chroma_nv21
+    pld [r12, #64*3]
+
+    vld2.8              {d2, d3}, [r6]!                                @ q1: interleaved chroma line
+    vshll.u8            q14, d3, #3                                    @ q14 = U * (1 << 3)
+    vshll.u8            q15, d2, #3                                    @ q15 = V * (1 << 3)
+.endm
+
+.macro load_chroma_yuv420p
+    pld [r10, #64*3]
+    pld [r12, #64*3]
+
+    vld1.8              d2, [r6]!                                      @ d2: chroma red line
+    vld1.8              d3, [r10]!                                     @ d3: chroma blue line
+    vshll.u8            q14, d2, #3                                    @ q14 = U * (1 << 3)
+    vshll.u8            q15, d3, #3                                    @ q15 = V * (1 << 3)
+.endm
+
+.macro load_chroma_yuv422p
+    pld [r10, #64*3]
+
+    vld1.8              d2, [r6]!                                      @ d2: chroma red line
+    vld1.8              d3, [r10]!                                     @ d3: chroma blue line
+    vshll.u8            q14, d2, #3                                    @ q14 = U * (1 << 3)
+    vshll.u8            q15, d3, #3                                    @ q15 = V * (1 << 3)
+.endm
+
+.macro increment_and_test_nv12
+    add                 r11, r11, r3                                   @ dst2  += padding
+    add                 r12, r12, r5                                   @ srcY2 += paddingY
+    add                 r6, r6, r7                                     @ srcC  += paddingC
+    subs                r1, r1, #2                                     @ height -= 2
+.endm
+
+.macro increment_and_test_nv21
+    increment_and_test_nv12
+.endm
+
+.macro increment_and_test_yuv420p
+    add                 r11, r11, r3                                   @ dst2  += padding
+    add                 r12, r12, r5                                   @ srcY2 += paddingY
+    ldr                 r7, [sp, #116]                                 @ r7     = linesizeU
+    sub                 r7, r7, r0, lsr #1                             @ r7     = linesizeU - width / 2 (paddingU)
+    add                 r6, r6, r7                                     @ srcU  += paddingU
+    ldr                 r7, [sp, #124]                                 @ r7     = linesizeV
+    sub                 r7, r7, r0, lsr #1                             @ r7     = linesizeV - width / 2 (paddingV)
+    add                 r10, r10, r7                                   @ srcV  += paddingV
+    subs                r1, r1, #2                                     @ height -= 2
+.endm
+
+.macro increment_and_test_yuv422p
+    add                 r6, r6, r7                                     @ srcU  += paddingU
+    add                 r10,r10,r12                                    @ srcV  += paddingV
+    subs                r1, r1, #1                                     @ height -= 1
+.endm
+
+.macro process_nv12 ofmt
+    process_2l \ofmt
+.endm
+
+.macro process_nv21 ofmt
+    process_2l \ofmt
+.endm
+
+.macro process_yuv420p ofmt
+    process_2l \ofmt
+.endm
+
+.macro process_yuv422p ofmt
+    process_1l \ofmt
+.endm
+
+.macro declare_func ifmt ofmt
+function ff_\ifmt\()_to_\ofmt\()_neon, export=1
+    load_args_\ifmt
+    vmov.u16            q11, #1024                                     @ q11 = 128 * (1 << 3)
+    vdup.16             q12, r9                                        @ q12 = y_offset
+    vmov                d26, d0                                        @ q13 = y_coeff
+    vmov                d27, d0                                        @ q13 = y_coeff
+1:
+    mov                 r8, r0                                         @ r8 = width
+2:
+    pld [r6, #64*3]
+    pld [r4, #64*3]
+    vmov.i8             d10, #128
+    load_chroma_\ifmt
+    process_\ifmt \ofmt
+    subs                r8, r8, #16                                    @ width -= 16
+    bgt                 2b
+    add                 r2, r2, r3                                     @ dst   += padding
+    add                 r4, r4, r5                                     @ srcY  += paddingY
+    increment_and_test_\ifmt
+    bgt                 1b
+    vpop                {q4-q7}
+    pop                 {r4-r12, pc}
+endfunc
+.endm
+
+.macro declare_rgb_funcs ifmt
+    declare_func \ifmt, argb
+    declare_func \ifmt, rgba
+    declare_func \ifmt, abgr
+    declare_func \ifmt, bgra
+.endm
+
+declare_rgb_funcs nv12
+declare_rgb_funcs nv21
+declare_rgb_funcs yuv420p
+declare_rgb_funcs yuv422p
diff --git a/libs/ffmpeg/libswscale/bayer_template.c b/libs/ffmpeg/libswscale/bayer_template.c
new file mode 100644
index 000000000000..82fe8ffde817
--- /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 000000000000..3a1a438c4962
--- /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 000000000000..5323a27260b6
--- /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 000000000000..6ab6ac3f7a8e
--- /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 000000000000..c28e4ac7aed1
--- /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 000000000000..3464a8af7c6a
--- /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 000000000000..d66851893fe1
--- /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 000000000000..7fb1b7763f1a
--- /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 000000000000..8e8fb01f95fa
--- /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 000000000000..676f8cb46ac2
--- /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/hscale.c b/libs/ffmpeg/libswscale/hscale.c
new file mode 100644
index 000000000000..6e09181048a3
--- /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 000000000000..abcfb95e2ccd
--- /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 000000000000..175ed705f243
--- /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/lut3d.c b/libs/ffmpeg/libswscale/lut3d.c
new file mode 100644
index 000000000000..535694e61c1a
--- /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 000000000000..273059f9a111
--- /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 000000000000..9961f4f79121
--- /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 000000000000..64a4a6dd61d8
--- /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 000000000000..ceecae4f991e
--- /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 000000000000..b1616f6b0205
--- /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 000000000000..244515418669
--- /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 000000000000..532622fd2ce3
--- /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 000000000000..67ce225b829f
--- /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(&copy);
+    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 000000000000..270ff09e3130
--- /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 000000000000..3db850c290ee
--- /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 000000000000..fd8b79ec3437
--- /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 000000000000..abba9df2ffc4
--- /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 000000000000..1b1df2c7a0f4
--- /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 000000000000..254077e126dc
--- /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 000000000000..4ce86e3ad9f9
--- /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 000000000000..06e51dcfe9b7
--- /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 000000000000..396380ac72db
--- /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 000000000000..4bba657bd142
--- /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 000000000000..ed6e08a565cb
--- /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 000000000000..c36bbccea9f4
--- /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 000000000000..44c3bd74b443
--- /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 000000000000..cd4ef9676bb8
--- /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 000000000000..1cfd4068f9d1
--- /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 000000000000..7d5eeae20329
--- /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 000000000000..cd5e76cfc749
--- /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 000000000000..2b233cf0e672
--- /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 000000000000..31135f9cb187
--- /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 000000000000..0129e168546a
--- /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 000000000000..0dc507921ed4
--- /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 000000000000..e972bd70e280
--- /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/x86/hscale_fast_bilinear_simd.c b/libs/ffmpeg/libswscale/x86/hscale_fast_bilinear_simd.c
new file mode 100644
index 000000000000..f0f3b230f5f2
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/hscale_fast_bilinear_simd.c
@@ -0,0 +1,363 @@
+/*
+ * 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include "../swscale_internal.h"
+#include "libavutil/attributes.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/mem_internal.h"
+
+#define RET 0xC3 // near return opcode for x86
+#define PREFETCH "prefetchnta"
+
+av_cold int ff_init_hscaler_mmxext(int dstW, int xInc, uint8_t *filterCode,
+                                       int16_t *filter, int32_t *filterPos,
+                                       int numSplits)
+{
+    uint8_t *fragmentA;
+    x86_reg imm8OfPShufW1A;
+    x86_reg imm8OfPShufW2A;
+    x86_reg fragmentLengthA;
+    uint8_t *fragmentB;
+    x86_reg imm8OfPShufW1B;
+    x86_reg imm8OfPShufW2B;
+    x86_reg fragmentLengthB;
+    int fragmentPos;
+
+    int xpos, i;
+
+    // create an optimized horizontal scaling routine
+    /* This scaler is made of runtime-generated MMXEXT code using specially tuned
+     * pshufw instructions. For every four output pixels, if four input pixels
+     * are enough for the fast bilinear scaling, then a chunk of fragmentB is
+     * used. If five input pixels are needed, then a chunk of fragmentA is used.
+     */
+
+    // code fragment
+
+    __asm__ volatile (
+        "jmp                         9f                 \n\t"
+        // Begin
+        "0:                                             \n\t"
+        "movq    (%%"FF_REG_d", %%"FF_REG_a"), %%mm3    \n\t"
+        "movd    (%%"FF_REG_c", %%"FF_REG_S"), %%mm0    \n\t"
+        "movd   1(%%"FF_REG_c", %%"FF_REG_S"), %%mm1    \n\t"
+        "punpcklbw                %%mm7, %%mm1          \n\t"
+        "punpcklbw                %%mm7, %%mm0          \n\t"
+        "pshufw                   $0xFF, %%mm1, %%mm1   \n\t"
+        "1:                                             \n\t"
+        "pshufw                   $0xFF, %%mm0, %%mm0   \n\t"
+        "2:                                             \n\t"
+        "psubw                    %%mm1, %%mm0          \n\t"
+        "movl   8(%%"FF_REG_b", %%"FF_REG_a"), %%esi    \n\t"
+        "pmullw                   %%mm3, %%mm0          \n\t"
+        "psllw                       $7, %%mm1          \n\t"
+        "paddw                    %%mm1, %%mm0          \n\t"
+
+        "movq                     %%mm0, (%%"FF_REG_D", %%"FF_REG_a") \n\t"
+
+        "add                         $8, %%"FF_REG_a"   \n\t"
+        // End
+        "9:                                             \n\t"
+        "lea       " LOCAL_MANGLE(0b) ", %0             \n\t"
+        "lea       " LOCAL_MANGLE(1b) ", %1             \n\t"
+        "lea       " LOCAL_MANGLE(2b) ", %2             \n\t"
+        "dec                         %1                 \n\t"
+        "dec                         %2                 \n\t"
+        "sub                         %0, %1             \n\t"
+        "sub                         %0, %2             \n\t"
+        "lea       " LOCAL_MANGLE(9b) ", %3             \n\t"
+        "sub                         %0, %3             \n\t"
+
+
+        : "=r" (fragmentA), "=r" (imm8OfPShufW1A), "=r" (imm8OfPShufW2A),
+          "=r" (fragmentLengthA)
+        );
+
+    __asm__ volatile (
+        "jmp                         9f                 \n\t"
+        // Begin
+        "0:                                             \n\t"
+        "movq    (%%"FF_REG_d", %%"FF_REG_a"), %%mm3    \n\t"
+        "movd    (%%"FF_REG_c", %%"FF_REG_S"), %%mm0    \n\t"
+        "punpcklbw                %%mm7, %%mm0          \n\t"
+        "pshufw                   $0xFF, %%mm0, %%mm1   \n\t"
+        "1:                                             \n\t"
+        "pshufw                   $0xFF, %%mm0, %%mm0   \n\t"
+        "2:                                             \n\t"
+        "psubw                    %%mm1, %%mm0          \n\t"
+        "movl   8(%%"FF_REG_b", %%"FF_REG_a"), %%esi    \n\t"
+        "pmullw                   %%mm3, %%mm0          \n\t"
+        "psllw                       $7, %%mm1          \n\t"
+        "paddw                    %%mm1, %%mm0          \n\t"
+
+        "movq                     %%mm0, (%%"FF_REG_D", %%"FF_REG_a") \n\t"
+
+        "add                         $8, %%"FF_REG_a"   \n\t"
+        // End
+        "9:                                             \n\t"
+        "lea       " LOCAL_MANGLE(0b) ", %0             \n\t"
+        "lea       " LOCAL_MANGLE(1b) ", %1             \n\t"
+        "lea       " LOCAL_MANGLE(2b) ", %2             \n\t"
+        "dec                         %1                 \n\t"
+        "dec                         %2                 \n\t"
+        "sub                         %0, %1             \n\t"
+        "sub                         %0, %2             \n\t"
+        "lea       " LOCAL_MANGLE(9b) ", %3             \n\t"
+        "sub                         %0, %3             \n\t"
+
+
+        : "=r" (fragmentB), "=r" (imm8OfPShufW1B), "=r" (imm8OfPShufW2B),
+          "=r" (fragmentLengthB)
+        );
+
+    xpos        = 0; // lumXInc/2 - 0x8000; // difference between pixel centers
+    fragmentPos = 0;
+
+    for (i = 0; i < dstW / numSplits; i++) {
+        int xx = xpos >> 16;
+
+        if ((i & 3) == 0) {
+            int a                  = 0;
+            int b                  = ((xpos + xInc) >> 16) - xx;
+            int c                  = ((xpos + xInc * 2) >> 16) - xx;
+            int d                  = ((xpos + xInc * 3) >> 16) - xx;
+            int inc                = (d + 1 < 4);
+            uint8_t *fragment      = inc ? fragmentB : fragmentA;
+            x86_reg imm8OfPShufW1  = inc ? imm8OfPShufW1B : imm8OfPShufW1A;
+            x86_reg imm8OfPShufW2  = inc ? imm8OfPShufW2B : imm8OfPShufW2A;
+            x86_reg fragmentLength = inc ? fragmentLengthB : fragmentLengthA;
+            int maxShift           = 3 - (d + inc);
+            int shift              = 0;
+
+            if (filterCode) {
+                filter[i]        = ((xpos              & 0xFFFF) ^ 0xFFFF) >> 9;
+                filter[i + 1]    = (((xpos + xInc)     & 0xFFFF) ^ 0xFFFF) >> 9;
+                filter[i + 2]    = (((xpos + xInc * 2) & 0xFFFF) ^ 0xFFFF) >> 9;
+                filter[i + 3]    = (((xpos + xInc * 3) & 0xFFFF) ^ 0xFFFF) >> 9;
+                filterPos[i / 2] = xx;
+
+                memcpy(filterCode + fragmentPos, fragment, fragmentLength);
+
+                filterCode[fragmentPos + imm8OfPShufW1] =  (a + inc)       |
+                                                          ((b + inc) << 2) |
+                                                          ((c + inc) << 4) |
+                                                          ((d + inc) << 6);
+                filterCode[fragmentPos + imm8OfPShufW2] =  a | (b << 2) |
+                                                               (c << 4) |
+                                                               (d << 6);
+
+                if (i + 4 - inc >= dstW)
+                    shift = maxShift;               // avoid overread
+                else if ((filterPos[i / 2] & 3) <= maxShift)
+                    shift = filterPos[i / 2] & 3;   // align
+
+                if (shift && i >= shift) {
+                    filterCode[fragmentPos + imm8OfPShufW1] += 0x55 * shift;
+                    filterCode[fragmentPos + imm8OfPShufW2] += 0x55 * shift;
+                    filterPos[i / 2]                        -= shift;
+                }
+            }
+
+            fragmentPos += fragmentLength;
+
+            if (filterCode)
+                filterCode[fragmentPos] = RET;
+        }
+        xpos += xInc;
+    }
+    if (filterCode)
+        filterPos[((i / 2) + 1) & (~1)] = xpos >> 16;  // needed to jump to the next part
+
+    return fragmentPos + 1;
+}
+
+void ff_hyscale_fast_mmxext(SwsInternal *c, int16_t *dst,
+                                 int dstWidth, const uint8_t *src,
+                                 int srcW, int xInc)
+{
+    int32_t *filterPos = c->hLumFilterPos;
+    int16_t *filter    = c->hLumFilter;
+    void    *mmxextFilterCode = c->lumMmxextFilterCode;
+    int i;
+#if ARCH_X86_64
+    uint64_t retsave;
+#else
+#if !HAVE_EBX_AVAILABLE
+    uint64_t ebxsave;
+#endif
+#endif
+
+    __asm__ volatile(
+#if ARCH_X86_64
+        "mov               -8(%%rsp), %%"FF_REG_a"    \n\t"
+        "mov            %%"FF_REG_a", %5              \n\t"  // retsave
+#else
+#if !HAVE_EBX_AVAILABLE
+        "mov            %%"FF_REG_b", %5              \n\t"  // ebxsave
+#endif
+#endif
+        "pxor                  %%mm7, %%mm7           \n\t"
+        "mov                      %0, %%"FF_REG_c"    \n\t"
+        "mov                      %1, %%"FF_REG_D"    \n\t"
+        "mov                      %2, %%"FF_REG_d"    \n\t"
+        "mov                      %3, %%"FF_REG_b"    \n\t"
+        "xor            %%"FF_REG_a", %%"FF_REG_a"    \n\t" // i
+        PREFETCH"      (%%"FF_REG_c")                 \n\t"
+        PREFETCH"    32(%%"FF_REG_c")                 \n\t"
+        PREFETCH"    64(%%"FF_REG_c")                 \n\t"
+
+#if ARCH_X86_64
+#define CALL_MMXEXT_FILTER_CODE \
+        "movl               (%%"FF_REG_b"), %%esi        \n\t"\
+        "call                          *%4               \n\t"\
+        "movl (%%"FF_REG_b", %%"FF_REG_a"), %%esi        \n\t"\
+        "add                  %%"FF_REG_S", %%"FF_REG_c" \n\t"\
+        "add                  %%"FF_REG_a", %%"FF_REG_D" \n\t"\
+        "xor                  %%"FF_REG_a", %%"FF_REG_a" \n\t"\
+
+#else
+#define CALL_MMXEXT_FILTER_CODE \
+        "movl               (%%"FF_REG_b"), %%esi        \n\t"\
+        "call                          *%4               \n\t"\
+        "addl (%%"FF_REG_b", %%"FF_REG_a"), %%"FF_REG_c" \n\t"\
+        "add                  %%"FF_REG_a", %%"FF_REG_D" \n\t"\
+        "xor                  %%"FF_REG_a", %%"FF_REG_a" \n\t"\
+
+#endif /* ARCH_X86_64 */
+
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+
+#if ARCH_X86_64
+        "mov                      %5, %%"FF_REG_a" \n\t"
+        "mov            %%"FF_REG_a", -8(%%rsp)    \n\t"
+#else
+#if !HAVE_EBX_AVAILABLE
+        "mov                      %5, %%"FF_REG_b" \n\t"
+#endif
+#endif
+        :: "m" (src), "m" (dst), "m" (filter), "m" (filterPos),
+           "m" (mmxextFilterCode)
+#if ARCH_X86_64
+          ,"m"(retsave)
+#else
+#if !HAVE_EBX_AVAILABLE
+          ,"m" (ebxsave)
+#endif
+#endif
+        : "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_D
+#if ARCH_X86_64 || HAVE_EBX_AVAILABLE
+         ,"%"FF_REG_b
+#endif
+    );
+
+    for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--)
+        dst[i] = src[srcW-1]*128;
+}
+
+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)
+{
+    int32_t *filterPos = c->hChrFilterPos;
+    int16_t *filter    = c->hChrFilter;
+    void    *mmxextFilterCode = c->chrMmxextFilterCode;
+    int i;
+#if ARCH_X86_64
+    DECLARE_ALIGNED(8, uint64_t, retsave);
+#else
+#if !HAVE_EBX_AVAILABLE
+    DECLARE_ALIGNED(8, uint64_t, ebxsave);
+#endif
+#endif
+    __asm__ volatile(
+#if ARCH_X86_64
+        "mov          -8(%%rsp), %%"FF_REG_a"    \n\t"
+        "mov       %%"FF_REG_a", %7              \n\t"  // retsave
+#else
+#if !HAVE_EBX_AVAILABLE
+        "mov       %%"FF_REG_b", %7              \n\t"  // ebxsave
+#endif
+#endif
+        "pxor             %%mm7, %%mm7           \n\t"
+        "mov                 %0, %%"FF_REG_c"    \n\t"
+        "mov                 %1, %%"FF_REG_D"    \n\t"
+        "mov                 %2, %%"FF_REG_d"    \n\t"
+        "mov                 %3, %%"FF_REG_b"    \n\t"
+        "xor          %%"FF_REG_a", %%"FF_REG_a" \n\t" // i
+        PREFETCH"   (%%"FF_REG_c")               \n\t"
+        PREFETCH" 32(%%"FF_REG_c")               \n\t"
+        PREFETCH" 64(%%"FF_REG_c")               \n\t"
+
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        "xor          %%"FF_REG_a", %%"FF_REG_a" \n\t" // i
+        "mov                    %5, %%"FF_REG_c" \n\t" // src2
+        "mov                    %6, %%"FF_REG_D" \n\t" // dst2
+        PREFETCH"   (%%"FF_REG_c")               \n\t"
+        PREFETCH" 32(%%"FF_REG_c")               \n\t"
+        PREFETCH" 64(%%"FF_REG_c")               \n\t"
+
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+        CALL_MMXEXT_FILTER_CODE
+
+#if ARCH_X86_64
+        "mov                    %7, %%"FF_REG_a" \n\t"
+        "mov          %%"FF_REG_a", -8(%%rsp)    \n\t"
+#else
+#if !HAVE_EBX_AVAILABLE
+        "mov %7, %%"FF_REG_b"    \n\t"
+#endif
+#endif
+        :: "m" (src1), "m" (dst1), "m" (filter), "m" (filterPos),
+           "m" (mmxextFilterCode), "m" (src2), "m"(dst2)
+#if ARCH_X86_64
+          ,"m"(retsave)
+#else
+#if !HAVE_EBX_AVAILABLE
+          ,"m" (ebxsave)
+#endif
+#endif
+        : "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S, "%"FF_REG_D
+#if ARCH_X86_64 || HAVE_EBX_AVAILABLE
+         ,"%"FF_REG_b
+#endif
+    );
+
+    for (i=dstWidth-1; (i*xInc)>>16 >=srcW-1; i--) {
+        dst1[i] = src1[srcW-1]*128;
+        dst2[i] = src2[srcW-1]*128;
+    }
+}
+
+#endif
diff --git a/libs/ffmpeg/libswscale/x86/input.asm b/libs/ffmpeg/libswscale/x86/input.asm
new file mode 100644
index 000000000000..ce31436e49f8
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/input.asm
@@ -0,0 +1,1252 @@
+;******************************************************************************
+;* x86-optimized input routines; does shuffling of packed
+;* YUV formats into individual planes, and converts RGB
+;* into YUV planes also.
+;* Copyright (c) 2012 Ronald S. Bultje <rsbultje@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/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+%define RY 0x20DE
+%define GY 0x4087
+%define BY 0x0C88
+%define RU 0xECFF
+%define GU 0xDAC8
+%define BU 0x3838
+%define RV 0x3838
+%define GV 0xD0E3
+%define BV 0xF6E4
+
+rgb_Yrnd:        times 4 dd 0x80100        ;  16.5 << 15
+rgb_UVrnd:       times 4 dd 0x400100       ; 128.5 << 15
+%define bgr_Ycoeff_12x4 16*4 + 16* 0 + tableq
+%define bgr_Ycoeff_3x56 16*4 + 16* 1 + tableq
+%define rgb_Ycoeff_12x4 16*4 + 16* 2 + tableq
+%define rgb_Ycoeff_3x56 16*4 + 16* 3 + tableq
+%define bgr_Ucoeff_12x4 16*4 + 16* 4 + tableq
+%define bgr_Ucoeff_3x56 16*4 + 16* 5 + tableq
+%define rgb_Ucoeff_12x4 16*4 + 16* 6 + tableq
+%define rgb_Ucoeff_3x56 16*4 + 16* 7 + tableq
+%define bgr_Vcoeff_12x4 16*4 + 16* 8 + tableq
+%define bgr_Vcoeff_3x56 16*4 + 16* 9 + tableq
+%define rgb_Vcoeff_12x4 16*4 + 16*10 + tableq
+%define rgb_Vcoeff_3x56 16*4 + 16*11 + tableq
+
+%define rgba_Ycoeff_rb 16*4 + 16*12 + tableq
+%define rgba_Ycoeff_br 16*4 + 16*13 + tableq
+%define rgba_Ycoeff_ga 16*4 + 16*14 + tableq
+%define rgba_Ycoeff_ag 16*4 + 16*15 + tableq
+%define rgba_Ucoeff_rb 16*4 + 16*16 + tableq
+%define rgba_Ucoeff_br 16*4 + 16*17 + tableq
+%define rgba_Ucoeff_ga 16*4 + 16*18 + tableq
+%define rgba_Ucoeff_ag 16*4 + 16*19 + tableq
+%define rgba_Vcoeff_rb 16*4 + 16*20 + tableq
+%define rgba_Vcoeff_br 16*4 + 16*21 + tableq
+%define rgba_Vcoeff_ga 16*4 + 16*22 + tableq
+%define rgba_Vcoeff_ag 16*4 + 16*23 + tableq
+
+; bgr_Ycoeff_12x4: times 2 dw BY, GY, 0, BY
+; bgr_Ycoeff_3x56: times 2 dw RY, 0, GY, RY
+; rgb_Ycoeff_12x4: times 2 dw RY, GY, 0, RY
+; rgb_Ycoeff_3x56: times 2 dw BY, 0, GY, BY
+; bgr_Ucoeff_12x4: times 2 dw BU, GU, 0, BU
+; bgr_Ucoeff_3x56: times 2 dw RU, 0, GU, RU
+; rgb_Ucoeff_12x4: times 2 dw RU, GU, 0, RU
+; rgb_Ucoeff_3x56: times 2 dw BU, 0, GU, BU
+; bgr_Vcoeff_12x4: times 2 dw BV, GV, 0, BV
+; bgr_Vcoeff_3x56: times 2 dw RV, 0, GV, RV
+; rgb_Vcoeff_12x4: times 2 dw RV, GV, 0, RV
+; rgb_Vcoeff_3x56: times 2 dw BV, 0, GV, BV
+
+; rgba_Ycoeff_rb:  times 4 dw RY, BY
+; rgba_Ycoeff_br:  times 4 dw BY, RY
+; rgba_Ycoeff_ga:  times 4 dw GY, 0
+; rgba_Ycoeff_ag:  times 4 dw 0,  GY
+; rgba_Ucoeff_rb:  times 4 dw RU, BU
+; rgba_Ucoeff_br:  times 4 dw BU, RU
+; rgba_Ucoeff_ga:  times 4 dw GU, 0
+; rgba_Ucoeff_ag:  times 4 dw 0,  GU
+; rgba_Vcoeff_rb:  times 4 dw RV, BV
+; rgba_Vcoeff_br:  times 4 dw BV, RV
+; rgba_Vcoeff_ga:  times 4 dw GV, 0
+; rgba_Vcoeff_ag:  times 4 dw 0,  GV
+
+shuf_rgb_12x4:   db 0, 0x80, 1, 0x80,  2, 0x80,  3, 0x80, \
+                    6, 0x80, 7, 0x80,  8, 0x80,  9, 0x80, \
+                    0, 0x80, 1, 0x80,  2, 0x80,  3, 0x80, \
+                    6, 0x80, 7, 0x80,  8, 0x80,  9, 0x80
+shuf_rgb_3x56:   db 2, 0x80, 3, 0x80,  4, 0x80,  5, 0x80, \
+                    8, 0x80, 9, 0x80, 10, 0x80, 11, 0x80, \
+                    2, 0x80, 3, 0x80,  4, 0x80,  5, 0x80, \
+                    8, 0x80, 9, 0x80, 10, 0x80, 11, 0x80
+pd_65535f:     times 8 dd 65535.0
+pb_pack_shuffle16le:    db  0,  1,  4,  5, \
+                            8,  9, 12, 13, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                            0,  1,  4,  5, \
+                            8,  9, 12, 13
+pb_shuffle32be:         db  3,  2,  1,  0, \
+                            7,  6,  5,  4, \
+                           11, 10,  9,  8, \
+                           15, 14, 13, 12, \
+                            3,  2,  1,  0, \
+                            7,  6,  5,  4, \
+                           11, 10,  9,  8, \
+                           15, 14, 13, 12
+pb_shuffle16be:         db  1,  0,  3,  2, \
+                            5,  4,  7,  6, \
+                            9,  8, 11, 10, \
+                           13, 12, 15, 14, \
+                            1,  0,  3,  2, \
+                            5,  4,  7,  6, \
+                            9,  8, 11, 10, \
+                           13, 12, 15, 14
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; RGB to Y/UV.
+;
+; void <fmt>ToY_<opt>(uint8_t *dst, const uint8_t *src, int w);
+; and
+; void <fmt>toUV_<opt>(uint8_t *dstU, uint8_t *dstV, const uint8_t *src,
+;                      const uint8_t *unused, int w);
+;-----------------------------------------------------------------------------
+
+; %1 = nr. of XMM registers
+; %2 = rgb or bgr
+%macro RGB24_TO_Y_FN 2-3
+cglobal %2 %+ 24ToY, 6, 6, %1, dst, src, u1, u2, w, table
+%if ARCH_X86_64
+%if mmsize == 32
+    vbroadcasti128 m8, [%2_Ycoeff_12x4]
+    vbroadcasti128 m9, [%2_Ycoeff_3x56]
+%else
+    mova           m8, [%2_Ycoeff_12x4]
+    mova           m9, [%2_Ycoeff_3x56]
+%endif
+%define coeff1 m8
+%define coeff2 m9
+%else ; x86-32
+%define coeff1 [%2_Ycoeff_12x4]
+%define coeff2 [%2_Ycoeff_3x56]
+%endif ; x86-32/64
+%if ARCH_X86_64 && %0 == 3
+    jmp mangle(private_prefix %+ _ %+ %3 %+ 24ToY %+ SUFFIX).body
+%else ; ARCH_X86_64 && %0 == 3
+.body:
+%if cpuflag(ssse3)
+    mova           m7, [shuf_rgb_12x4]
+%define shuf_rgb1 m7
+%if ARCH_X86_64
+    mova          m10, [shuf_rgb_3x56]
+%define shuf_rgb2 m10
+%else ; x86-32
+%define shuf_rgb2 [shuf_rgb_3x56]
+%endif ; x86-32/64
+%endif ; cpuflag(ssse3)
+%if ARCH_X86_64
+    movsxd         wq, wd
+%endif
+    add            wq, wq
+    add          dstq, wq
+    neg            wq
+%if notcpuflag(ssse3)
+    pxor           m7, m7
+%endif ; !cpuflag(ssse3)
+%if mmsize == 32
+    vbroadcasti128 m4, [rgb_Yrnd]
+%else
+    mova           m4, [rgb_Yrnd]
+%endif
+.loop:
+%if cpuflag(ssse3)
+    movu          xm0, [srcq+0]           ; (byte) { Bx, Gx, Rx }[0-3]
+    movu          xm2, [srcq+8]           ; (byte) { Bx, Gx, Rx }[4-7]
+%if mmsize == 32
+    vinserti128    m0, m0, [srcq+24], 1
+    vinserti128    m2, m2, [srcq+32], 1
+%endif
+    psrldq         m2, 4
+    pshufb         m1, m0, shuf_rgb2      ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 }
+    pshufb         m0, shuf_rgb1          ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 }
+    pshufb         m3, m2, shuf_rgb2      ; (word) { R4, B5, G5, R5, R6, B7, G7, R7 }
+    pshufb         m2, shuf_rgb1          ; (word) { B4, G4, R4, B5, B6, G6, R6, B7 }
+%else ; !cpuflag(ssse3)
+    movd           m0, [srcq+0]           ; (byte) { B0, G0, R0, B1 }
+    movd           m1, [srcq+2]           ; (byte) { R0, B1, G1, R1 }
+    movd           m2, [srcq+6]           ; (byte) { B2, G2, R2, B3 }
+    movd           m3, [srcq+8]           ; (byte) { R2, B3, G3, R3 }
+    punpckldq      m0, m2                 ; (byte) { B0, G0, R0, B1, B2, G2, R2, B3 }
+    punpckldq      m1, m3                 ; (byte) { R0, B1, G1, R1, R2, B3, G3, R3 }
+    movd           m2, [srcq+12]          ; (byte) { B4, G4, R4, B5 }
+    movd           m3, [srcq+14]          ; (byte) { R4, B5, G5, R5 }
+    movd           m5, [srcq+18]          ; (byte) { B6, G6, R6, B7 }
+    movd           m6, [srcq+20]          ; (byte) { R6, B7, G7, R7 }
+    punpckldq      m2, m5                 ; (byte) { B4, G4, R4, B5, B6, G6, R6, B7 }
+    punpckldq      m3, m6                 ; (byte) { R4, B5, G5, R5, R6, B7, G7, R7 }
+    punpcklbw      m0, m7                 ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 }
+    punpcklbw      m1, m7                 ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 }
+    punpcklbw      m2, m7                 ; (word) { B4, G4, R4, B5, B6, G6, R6, B7 }
+    punpcklbw      m3, m7                 ; (word) { R4, B5, G5, R5, R6, B7, G7, R7 }
+%endif ; cpuflag(ssse3)
+    add          srcq, 3 * mmsize / 2
+    pmaddwd        m0, coeff1             ; (dword) { B0*BY + G0*GY, B1*BY, B2*BY + G2*GY, B3*BY }
+    pmaddwd        m1, coeff2             ; (dword) { R0*RY, G1+GY + R1*RY, R2*RY, G3+GY + R3*RY }
+    pmaddwd        m2, coeff1             ; (dword) { B4*BY + G4*GY, B5*BY, B6*BY + G6*GY, B7*BY }
+    pmaddwd        m3, coeff2             ; (dword) { R4*RY, G5+GY + R5*RY, R6*RY, G7+GY + R7*RY }
+    paddd          m0, m1                 ; (dword) { Bx*BY + Gx*GY + Rx*RY }[0-3]
+    paddd          m2, m3                 ; (dword) { Bx*BY + Gx*GY + Rx*RY }[4-7]
+    paddd          m0, m4                 ; += rgb_Yrnd, i.e. (dword) { Y[0-3] }
+    paddd          m2, m4                 ; += rgb_Yrnd, i.e. (dword) { Y[4-7] }
+    psrad          m0, 9
+    psrad          m2, 9
+    packssdw       m0, m2                 ; (word) { Y[0-7] }
+    mova    [dstq+wq], m0
+    add            wq, mmsize
+    jl .loop
+    RET
+%endif ; ARCH_X86_64 && %0 == 3
+%endmacro
+
+; %1 = nr. of XMM registers
+; %2 = aligned/unaligned output argument
+; %3-4 = rgb or bgr
+%macro RGB24_TO_UV_FN 3-4
+cglobal %3 %+ 24ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table
+%if ARCH_X86_64
+%if mmsize == 32
+    vbroadcasti128  m8, [%3_Ucoeff_12x4]
+    vbroadcasti128  m9, [%3_Ucoeff_3x56]
+    vbroadcasti128 m10, [%3_Vcoeff_12x4]
+    vbroadcasti128 m11, [%3_Vcoeff_3x56]
+%else
+    mova            m8, [%3_Ucoeff_12x4]
+    mova            m9, [%3_Ucoeff_3x56]
+    mova           m10, [%3_Vcoeff_12x4]
+    mova           m11, [%3_Vcoeff_3x56]
+%endif
+%define coeffU1 m8
+%define coeffU2 m9
+%define coeffV1 m10
+%define coeffV2 m11
+%else ; x86-32
+%define coeffU1 [%3_Ucoeff_12x4]
+%define coeffU2 [%3_Ucoeff_3x56]
+%define coeffV1 [%3_Vcoeff_12x4]
+%define coeffV2 [%3_Vcoeff_3x56]
+%endif ; x86-32/64
+%if ARCH_X86_64 && %0 == 4
+    jmp mangle(private_prefix %+ _ %+ %4 %+ 24ToUV %+ SUFFIX).body
+%else ; ARCH_X86_64 && %0 == 4
+.body:
+%if cpuflag(ssse3)
+    mova           m7, [shuf_rgb_12x4]
+%define shuf_rgb1 m7
+%if ARCH_X86_64
+    mova          m12, [shuf_rgb_3x56]
+%define shuf_rgb2 m12
+%else ; x86-32
+%define shuf_rgb2 [shuf_rgb_3x56]
+%endif ; x86-32/64
+%endif ; cpuflag(ssse3)
+%if ARCH_X86_64
+    movsxd         wq, dword r5m
+%else ; x86-32
+    mov            wq, r5m
+%endif
+    add            wq, wq
+    add         dstUq, wq
+    add         dstVq, wq
+    neg            wq
+%if mmsize == 32
+    vbroadcasti128 m6, [rgb_UVrnd]
+%else
+    mova           m6, [rgb_UVrnd]
+%endif
+%if notcpuflag(ssse3)
+    pxor           m7, m7
+%endif
+.loop:
+%if cpuflag(ssse3)
+    movu          xm0, [srcq+0]           ; (byte) { Bx, Gx, Rx }[0-3]
+    movu          xm4, [srcq+8]           ; (byte) { Bx, Gx, Rx }[4-7]
+%if mmsize == 32
+    vinserti128    m0, m0, [srcq+24], 1
+    vinserti128    m4, m4, [srcq+32], 1
+%endif
+    psrldq         m4, 4
+    pshufb         m1, m0, shuf_rgb2      ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 }
+    pshufb         m0, shuf_rgb1          ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 }
+%else ; !cpuflag(ssse3)
+    movd           m0, [srcq+0]           ; (byte) { B0, G0, R0, B1 }
+    movd           m1, [srcq+2]           ; (byte) { R0, B1, G1, R1 }
+    movd           m4, [srcq+6]           ; (byte) { B2, G2, R2, B3 }
+    movd           m5, [srcq+8]           ; (byte) { R2, B3, G3, R3 }
+    punpckldq      m0, m4                 ; (byte) { B0, G0, R0, B1, B2, G2, R2, B3 }
+    punpckldq      m1, m5                 ; (byte) { R0, B1, G1, R1, R2, B3, G3, R3 }
+    movd           m4, [srcq+12]          ; (byte) { B4, G4, R4, B5 }
+    movd           m5, [srcq+14]          ; (byte) { R4, B5, G5, R5 }
+    punpcklbw      m0, m7                 ; (word) { B0, G0, R0, B1, B2, G2, R2, B3 }
+    punpcklbw      m1, m7                 ; (word) { R0, B1, G1, R1, R2, B3, G3, R3 }
+%endif ; cpuflag(ssse3)
+    pmaddwd        m2, m0, coeffV1        ; (dword) { B0*BV + G0*GV, B1*BV, B2*BV + G2*GV, B3*BV }
+    pmaddwd        m3, m1, coeffV2        ; (dword) { R0*BV, G1*GV + R1*BV, R2*BV, G3*GV + R3*BV }
+    pmaddwd        m0, coeffU1            ; (dword) { B0*BU + G0*GU, B1*BU, B2*BU + G2*GU, B3*BU }
+    pmaddwd        m1, coeffU2            ; (dword) { R0*BU, G1*GU + R1*BU, R2*BU, G3*GU + R3*BU }
+    paddd          m0, m1                 ; (dword) { Bx*BU + Gx*GU + Rx*RU }[0-3]
+    paddd          m2, m3                 ; (dword) { Bx*BV + Gx*GV + Rx*RV }[0-3]
+%if cpuflag(ssse3)
+    pshufb         m5, m4, shuf_rgb2      ; (word) { R4, B5, G5, R5, R6, B7, G7, R7 }
+    pshufb         m4, shuf_rgb1          ; (word) { B4, G4, R4, B5, B6, G6, R6, B7 }
+%else ; !cpuflag(ssse3)
+    movd           m1, [srcq+18]          ; (byte) { B6, G6, R6, B7 }
+    movd           m3, [srcq+20]          ; (byte) { R6, B7, G7, R7 }
+    punpckldq      m4, m1                 ; (byte) { B4, G4, R4, B5, B6, G6, R6, B7 }
+    punpckldq      m5, m3                 ; (byte) { R4, B5, G5, R5, R6, B7, G7, R7 }
+    punpcklbw      m4, m7                 ; (word) { B4, G4, R4, B5, B6, G6, R6, B7 }
+    punpcklbw      m5, m7                 ; (word) { R4, B5, G5, R5, R6, B7, G7, R7 }
+%endif ; cpuflag(ssse3)
+    add          srcq, 3 * mmsize / 2
+    pmaddwd        m1, m4, coeffU1        ; (dword) { B4*BU + G4*GU, B5*BU, B6*BU + G6*GU, B7*BU }
+    pmaddwd        m3, m5, coeffU2        ; (dword) { R4*BU, G5*GU + R5*BU, R6*BU, G7*GU + R7*BU }
+    pmaddwd        m4, coeffV1            ; (dword) { B4*BV + G4*GV, B5*BV, B6*BV + G6*GV, B7*BV }
+    pmaddwd        m5, coeffV2            ; (dword) { R4*BV, G5*GV + R5*BV, R6*BV, G7*GV + R7*BV }
+    paddd          m1, m3                 ; (dword) { Bx*BU + Gx*GU + Rx*RU }[4-7]
+    paddd          m4, m5                 ; (dword) { Bx*BV + Gx*GV + Rx*RV }[4-7]
+    paddd          m0, m6                 ; += rgb_UVrnd, i.e. (dword) { U[0-3] }
+    paddd          m2, m6                 ; += rgb_UVrnd, i.e. (dword) { V[0-3] }
+    paddd          m1, m6                 ; += rgb_UVrnd, i.e. (dword) { U[4-7] }
+    paddd          m4, m6                 ; += rgb_UVrnd, i.e. (dword) { V[4-7] }
+    psrad          m0, 9
+    psrad          m2, 9
+    psrad          m1, 9
+    psrad          m4, 9
+    packssdw       m0, m1                 ; (word) { U[0-7] }
+    packssdw       m2, m4                 ; (word) { V[0-7] }
+    mov%2  [dstUq+wq], m0
+    mov%2  [dstVq+wq], m2
+    add            wq, mmsize
+    jl .loop
+    RET
+%endif ; ARCH_X86_64 && %0 == 4
+%endmacro
+
+; %1 = nr. of XMM registers for rgb-to-Y func
+; %2 = nr. of XMM registers for rgb-to-UV func
+; %3 = aligned/unaligned output argument
+%macro RGB24_FUNCS 3
+RGB24_TO_Y_FN %1, rgb
+RGB24_TO_Y_FN %1, bgr, rgb
+RGB24_TO_UV_FN %2, %3, rgb
+RGB24_TO_UV_FN %2, %3, bgr, rgb
+%endmacro
+
+INIT_XMM sse2
+RGB24_FUNCS 10, 12, a
+
+INIT_XMM ssse3
+RGB24_FUNCS 11, 13, a
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+RGB24_FUNCS 11, 13, a
+%endif
+
+%if ARCH_X86_64
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+RGB24_FUNCS 11, 13, u
+%endif
+%endif
+
+; %1 = nr. of XMM registers
+; %2-5 = rgba, bgra, argb or abgr (in individual characters)
+%macro RGB32_TO_Y_FN 5-6
+cglobal %2%3%4%5 %+ ToY, 6, 6, %1, dst, src, u1, u2, w, table
+%if mmsize == 32
+    vbroadcasti128 m5, [rgba_Ycoeff_%2%4]
+    vbroadcasti128 m6, [rgba_Ycoeff_%3%5]
+%else
+    mova           m5, [rgba_Ycoeff_%2%4]
+    mova           m6, [rgba_Ycoeff_%3%5]
+%endif
+%if %0 == 6
+    jmp mangle(private_prefix %+ _ %+ %6 %+ ToY %+ SUFFIX).body
+%else ; %0 == 6
+.body:
+%if ARCH_X86_64
+    movsxd         wq, wd
+%endif
+    add            wq, wq
+    sub            wq, mmsize - 1
+    lea          srcq, [srcq+wq*2]
+    add          dstq, wq
+    neg            wq
+%if mmsize == 32
+    vbroadcasti128 m4, [rgb_Yrnd]
+%else
+    mova           m4, [rgb_Yrnd]
+%endif
+    pcmpeqb        m7, m7
+    psrlw          m7, 8                  ; (word) { 0x00ff } x4
+.loop:
+    ; FIXME check alignment and use mova
+    movu          xm0, [srcq+wq*2+0]      ; (byte) { Bx, Gx, Rx, xx }[0-3]
+    movu          xm2, [srcq+wq*2+16]     ; (byte) { Bx, Gx, Rx, xx }[4-7]
+%if mmsize == 32
+    vinserti128    m0, m0, [srcq+wq*2+32], 1
+    vinserti128    m2, m2, [srcq+wq*2+48], 1
+%endif
+    DEINTB          1,  0,  3,  2,  7     ; (word) { Gx, xx (m0/m2) or Bx, Rx (m1/m3) }[0-3]/[4-7]
+    pmaddwd        m1, m5                 ; (dword) { Bx*BY + Rx*RY }[0-3]
+    pmaddwd        m0, m6                 ; (dword) { Gx*GY }[0-3]
+    pmaddwd        m3, m5                 ; (dword) { Bx*BY + Rx*RY }[4-7]
+    pmaddwd        m2, m6                 ; (dword) { Gx*GY }[4-7]
+    paddd          m0, m4                 ; += rgb_Yrnd
+    paddd          m2, m4                 ; += rgb_Yrnd
+    paddd          m0, m1                 ; (dword) { Y[0-3] }
+    paddd          m2, m3                 ; (dword) { Y[4-7] }
+    psrad          m0, 9
+    psrad          m2, 9
+    packssdw       m0, m2                 ; (word) { Y[0-7] }
+    mova    [dstq+wq], m0
+    add            wq, mmsize
+    jl .loop
+    sub            wq, mmsize - 1
+    jz .end
+    add            srcq, 2*mmsize - 2
+    add            dstq, mmsize - 1
+.loop2:
+INIT_XMM cpuname
+    movd           m0, [srcq+wq*2+0]      ; (byte) { Bx, Gx, Rx, xx }[0-3]
+    DEINTB          1,  0,  3,  2,  7     ; (word) { Gx, xx (m0/m2) or Bx, Rx (m1/m3) }[0-3]/[4-7]
+    pmaddwd        m1, m5                 ; (dword) { Bx*BY + Rx*RY }[0-3]
+    pmaddwd        m0, m6                 ; (dword) { Gx*GY }[0-3]
+    paddd          m0, m4                 ; += rgb_Yrnd
+    paddd          m0, m1                 ; (dword) { Y[0-3] }
+    psrad          m0, 9
+    packssdw       m0, m0                 ; (word) { Y[0-7] }
+    movd    [dstq+wq], m0
+    add            wq, 2
+    jl .loop2
+.end:
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+    RET
+%endif ; %0 == 3
+%endmacro
+
+; %1 = nr. of XMM registers
+; %2 = aligned/unaligned output argument
+; %3-6 = rgba, bgra, argb or abgr (in individual characters)
+%macro RGB32_TO_UV_FN 6-7
+cglobal %3%4%5%6 %+ ToUV, 7, 7, %1, dstU, dstV, u1, src, u2, w, table
+%if ARCH_X86_64
+%if mmsize == 32
+    vbroadcasti128  m8, [rgba_Ucoeff_%3%5]
+    vbroadcasti128  m9, [rgba_Ucoeff_%4%6]
+    vbroadcasti128 m10, [rgba_Vcoeff_%3%5]
+    vbroadcasti128 m11, [rgba_Vcoeff_%4%6]
+%else
+    mova            m8, [rgba_Ucoeff_%3%5]
+    mova            m9, [rgba_Ucoeff_%4%6]
+    mova           m10, [rgba_Vcoeff_%3%5]
+    mova           m11, [rgba_Vcoeff_%4%6]
+%endif
+%define coeffU1 m8
+%define coeffU2 m9
+%define coeffV1 m10
+%define coeffV2 m11
+%else ; x86-32
+%define coeffU1 [rgba_Ucoeff_%3%5]
+%define coeffU2 [rgba_Ucoeff_%4%6]
+%define coeffV1 [rgba_Vcoeff_%3%5]
+%define coeffV2 [rgba_Vcoeff_%4%6]
+%endif ; x86-64/32
+%if ARCH_X86_64 && %0 == 7
+    jmp mangle(private_prefix %+ _ %+ %7 %+ ToUV %+ SUFFIX).body
+%else ; ARCH_X86_64 && %0 == 7
+.body:
+%if ARCH_X86_64
+    movsxd         wq, dword r5m
+%else ; x86-32
+    mov            wq, r5m
+%endif
+    add            wq, wq
+    sub            wq, mmsize - 1
+    add         dstUq, wq
+    add         dstVq, wq
+    lea          srcq, [srcq+wq*2]
+    neg            wq
+    pcmpeqb        m7, m7
+    psrlw          m7, 8                  ; (word) { 0x00ff } x4
+%if mmsize == 32
+    vbroadcasti128 m6, [rgb_UVrnd]
+%else
+    mova           m6, [rgb_UVrnd]
+%endif
+.loop:
+    ; FIXME check alignment and use mova
+    movu          xm0, [srcq+wq*2+0]      ; (byte) { Bx, Gx, Rx, xx }[0-3]
+    movu          xm4, [srcq+wq*2+16]     ; (byte) { Bx, Gx, Rx, xx }[4-7]
+%if mmsize == 32
+    vinserti128    m0, m0, [srcq+wq*2+32], 1
+    vinserti128    m4, m4, [srcq+wq*2+48], 1
+%endif
+    DEINTB          1,  0,  5,  4,  7     ; (word) { Gx, xx (m0/m4) or Bx, Rx (m1/m5) }[0-3]/[4-7]
+    pmaddwd        m3, m1, coeffV1        ; (dword) { Bx*BV + Rx*RV }[0-3]
+    pmaddwd        m2, m0, coeffV2        ; (dword) { Gx*GV }[0-3]
+    pmaddwd        m1, coeffU1            ; (dword) { Bx*BU + Rx*RU }[0-3]
+    pmaddwd        m0, coeffU2            ; (dword) { Gx*GU }[0-3]
+    paddd          m3, m6                 ; += rgb_UVrnd
+    paddd          m1, m6                 ; += rgb_UVrnd
+    paddd          m2, m3                 ; (dword) { V[0-3] }
+    paddd          m0, m1                 ; (dword) { U[0-3] }
+    pmaddwd        m3, m5, coeffV1        ; (dword) { Bx*BV + Rx*RV }[4-7]
+    pmaddwd        m1, m4, coeffV2        ; (dword) { Gx*GV }[4-7]
+    pmaddwd        m5, coeffU1            ; (dword) { Bx*BU + Rx*RU }[4-7]
+    pmaddwd        m4, coeffU2            ; (dword) { Gx*GU }[4-7]
+    paddd          m3, m6                 ; += rgb_UVrnd
+    paddd          m5, m6                 ; += rgb_UVrnd
+    psrad          m0, 9
+    paddd          m1, m3                 ; (dword) { V[4-7] }
+    paddd          m4, m5                 ; (dword) { U[4-7] }
+    psrad          m2, 9
+    psrad          m4, 9
+    psrad          m1, 9
+    packssdw       m0, m4                 ; (word) { U[0-7] }
+    packssdw       m2, m1                 ; (word) { V[0-7] }
+    ; FIXME check alignment and use mova
+    mov%2  [dstUq+wq], m0
+    mov%2  [dstVq+wq], m2
+    add            wq, mmsize
+    jl .loop
+    sub            wq, mmsize - 1
+    jz .end
+    add            srcq , 2*mmsize - 2
+    add            dstUq, mmsize - 1
+    add            dstVq, mmsize - 1
+.loop2:
+INIT_XMM cpuname
+    movd           m0, [srcq+wq*2]        ; (byte) { Bx, Gx, Rx, xx }[0-3]
+    DEINTB          1,  0,  5,  4,  7     ; (word) { Gx, xx (m0/m4) or Bx, Rx (m1/m5) }[0-3]/[4-7]
+    pmaddwd        m3, m1, coeffV1        ; (dword) { Bx*BV + Rx*RV }[0-3]
+    pmaddwd        m2, m0, coeffV2        ; (dword) { Gx*GV }[0-3]
+    pmaddwd        m1, coeffU1            ; (dword) { Bx*BU + Rx*RU }[0-3]
+    pmaddwd        m0, coeffU2            ; (dword) { Gx*GU }[0-3]
+    paddd          m3, m6                 ; += rgb_UVrnd
+    paddd          m1, m6                 ; += rgb_UVrnd
+    paddd          m2, m3                 ; (dword) { V[0-3] }
+    paddd          m0, m1                 ; (dword) { U[0-3] }
+    psrad          m0, 9
+    psrad          m2, 9
+    packssdw       m0, m0                 ; (word) { U[0-7] }
+    packssdw       m2, m2                 ; (word) { V[0-7] }
+    movd   [dstUq+wq], m0
+    movd   [dstVq+wq], m2
+    add            wq, 2
+    jl .loop2
+.end:
+%if cpuflag(avx2)
+INIT_YMM cpuname
+%endif
+    RET
+%endif ; ARCH_X86_64 && %0 == 7
+%endmacro
+
+; %1 = nr. of XMM registers for rgb-to-Y func
+; %2 = nr. of XMM registers for rgb-to-UV func
+; %3 = aligned/unaligned output argument
+%macro RGB32_FUNCS 3
+RGB32_TO_Y_FN %1, r, g, b, a
+RGB32_TO_Y_FN %1, b, g, r, a, rgba
+RGB32_TO_Y_FN %1, a, r, g, b, rgba
+RGB32_TO_Y_FN %1, a, b, g, r, rgba
+
+RGB32_TO_UV_FN %2, %3, r, g, b, a
+RGB32_TO_UV_FN %2, %3, b, g, r, a, rgba
+RGB32_TO_UV_FN %2, %3, a, r, g, b, rgba
+RGB32_TO_UV_FN %2, %3, a, b, g, r, rgba
+%endmacro
+
+INIT_XMM sse2
+RGB32_FUNCS 8, 12, a
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+RGB32_FUNCS 8, 12, a
+%endif
+
+%if ARCH_X86_64
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+RGB32_FUNCS 8, 12, u
+%endif
+%endif
+
+;-----------------------------------------------------------------------------
+; YUYV/UYVY/NV12/NV21 packed pixel shuffling.
+;
+; void <fmt>ToY_<opt>(uint8_t *dst, const uint8_t *src, int w);
+; and
+; void <fmt>toUV_<opt>(uint8_t *dstU, uint8_t *dstV, const uint8_t *src,
+;                      const uint8_t *unused, int w);
+;-----------------------------------------------------------------------------
+
+; %1 = a (aligned) or u (unaligned)
+; %2 = yuyv or uyvy
+%macro LOOP_YUYV_TO_Y 2
+.loop_%1:
+    mov%1          m0, [srcq+wq*2]        ; (byte) { Y0, U0, Y1, V0, ... }
+    mov%1          m1, [srcq+wq*2+mmsize] ; (byte) { Y8, U4, Y9, V4, ... }
+%ifidn %2, yuyv
+    pand           m0, m2                 ; (word) { Y0, Y1, ..., Y7 }
+    pand           m1, m2                 ; (word) { Y8, Y9, ..., Y15 }
+%else ; uyvy
+    psrlw          m0, 8                  ; (word) { Y0, Y1, ..., Y7 }
+    psrlw          m1, 8                  ; (word) { Y8, Y9, ..., Y15 }
+%endif ; yuyv/uyvy
+    packuswb       m0, m1                 ; (byte) { Y0, ..., Y15 }
+    mova    [dstq+wq], m0
+    add            wq, mmsize
+    jl .loop_%1
+    RET
+%endmacro
+
+; %1 = nr. of XMM registers
+; %2 = yuyv or uyvy
+; %3 = if specified, it means that unaligned and aligned code in loop
+;      will be the same (i.e. YUYV+AVX), and thus we don't need to
+;      split the loop in an aligned and unaligned case
+%macro YUYV_TO_Y_FN 2-3
+cglobal %2ToY, 5, 5, %1, dst, unused0, unused1, src, w
+%if ARCH_X86_64
+    movsxd         wq, wd
+%endif
+    add          dstq, wq
+    test         srcq, 15
+    lea          srcq, [srcq+wq*2]
+%ifidn %2, yuyv
+    pcmpeqb        m2, m2                 ; (byte) { 0xff } x 16
+    psrlw          m2, 8                  ; (word) { 0x00ff } x 8
+%endif ; yuyv
+    jnz .loop_u_start
+    neg            wq
+    LOOP_YUYV_TO_Y  a, %2
+.loop_u_start:
+    neg            wq
+    LOOP_YUYV_TO_Y  u, %2
+%endmacro
+
+; %1 = a (aligned) or u (unaligned)
+; %2 = yuyv or uyvy
+%macro LOOP_YUYV_TO_UV 2
+.loop_%1:
+%ifidn %2, yuyv
+    mov%1          m0, [srcq+wq*4]        ; (byte) { Y0, U0, Y1, V0, ... }
+    mov%1          m1, [srcq+wq*4+mmsize] ; (byte) { Y8, U4, Y9, V4, ... }
+    psrlw          m0, 8                  ; (word) { U0, V0, ..., U3, V3 }
+    psrlw          m1, 8                  ; (word) { U4, V4, ..., U7, V7 }
+%else ; uyvy
+%if cpuflag(avx)
+    vpand          m0, m2, [srcq+wq*4]        ; (word) { U0, V0, ..., U3, V3 }
+    vpand          m1, m2, [srcq+wq*4+mmsize] ; (word) { U4, V4, ..., U7, V7 }
+%else
+    mov%1          m0, [srcq+wq*4]        ; (byte) { Y0, U0, Y1, V0, ... }
+    mov%1          m1, [srcq+wq*4+mmsize] ; (byte) { Y8, U4, Y9, V4, ... }
+    pand           m0, m2                 ; (word) { U0, V0, ..., U3, V3 }
+    pand           m1, m2                 ; (word) { U4, V4, ..., U7, V7 }
+%endif
+%endif ; yuyv/uyvy
+    packuswb       m0, m1                 ; (byte) { U0, V0, ..., U7, V7 }
+    pand           m1, m0, m2             ; (word) { U0, U1, ..., U7 }
+    psrlw          m0, 8                  ; (word) { V0, V1, ..., V7 }
+    packuswb       m1, m0                 ; (byte) { U0, ... U7, V1, ... V7 }
+    movh   [dstUq+wq], m1
+    movhps [dstVq+wq], m1
+    add            wq, mmsize / 2
+    jl .loop_%1
+    RET
+%endmacro
+
+; %1 = nr. of XMM registers
+; %2 = yuyv or uyvy
+; %3 = if specified, it means that unaligned and aligned code in loop
+;      will be the same (i.e. UYVY+AVX), and thus we don't need to
+;      split the loop in an aligned and unaligned case
+%macro YUYV_TO_UV_FN 2-3
+cglobal %2ToUV, 4, 5, %1, dstU, dstV, unused, src, w
+%if ARCH_X86_64
+    movsxd         wq, dword r5m
+%else ; x86-32
+    mov            wq, r5m
+%endif
+    add         dstUq, wq
+    add         dstVq, wq
+%if %0 == 2
+    test         srcq, 15
+%endif
+    lea          srcq, [srcq+wq*4]
+    pcmpeqb        m2, m2                 ; (byte) { 0xff } x 16
+    psrlw          m2, 8                  ; (word) { 0x00ff } x 8
+    ; NOTE: if uyvy+avx, u/a are identical
+%if %0 == 2
+    jnz .loop_u_start
+    neg            wq
+    LOOP_YUYV_TO_UV a, %2
+.loop_u_start:
+    neg            wq
+    LOOP_YUYV_TO_UV u, %2
+%else
+    neg            wq
+    LOOP_YUYV_TO_UV a, %2
+%endif
+%endmacro
+
+; %1 = a (aligned) or u (unaligned)
+; %2 = nv12 or nv21
+%macro LOOP_NVXX_TO_UV 2
+.loop_%1:
+    mov%1          m0, [srcq+wq*2]        ; (byte) { U0, V0, U1, V1, ... }
+    mov%1          m1, [srcq+wq*2+mmsize] ; (byte) { U8, V8, U9, V9, ... }
+    pand           m2, m0, m5             ; (word) { U0, U1, ..., U7 }
+    pand           m3, m1, m5             ; (word) { U8, U9, ..., U15 }
+    psrlw          m0, 8                  ; (word) { V0, V1, ..., V7 }
+    psrlw          m1, 8                  ; (word) { V8, V9, ..., V15 }
+    packuswb       m2, m3                 ; (byte) { U0, ..., U15 }
+    packuswb       m0, m1                 ; (byte) { V0, ..., V15 }
+%ifidn %2, nv12
+    mov%1  [dstUq+wq], m2
+    mov%1  [dstVq+wq], m0
+%else ; nv21
+    mov%1  [dstVq+wq], m2
+    mov%1  [dstUq+wq], m0
+%endif ; nv12/21
+    add            wq, mmsize
+    jl .loop_%1
+    RET
+%endmacro
+
+; %1 = nr. of XMM registers
+; %2 = nv12 or nv21
+%macro NVXX_TO_UV_FN 2
+cglobal %2ToUV, 4, 5, %1, dstU, dstV, tmp, src, w
+%if ARCH_X86_64
+    movsxd         wq, dword r5m
+%else ; x86-32
+    mov            wq, r5m
+%endif
+    mov          tmpq, srcq
+    or           tmpq, dstUq
+    or           tmpq, dstVq
+    add         dstUq, wq
+    add         dstVq, wq
+    test         tmpq, 15
+    lea          srcq, [srcq+wq*2]
+    pcmpeqb        m5, m5                 ; (byte) { 0xff } x 16
+    psrlw          m5, 8                  ; (word) { 0x00ff } x 8
+    jnz .loop_u_start
+    neg            wq
+    LOOP_NVXX_TO_UV a, %2
+.loop_u_start:
+    neg            wq
+    LOOP_NVXX_TO_UV u, %2
+%endmacro
+
+INIT_XMM sse2
+YUYV_TO_Y_FN  3, yuyv
+YUYV_TO_Y_FN  2, uyvy
+YUYV_TO_UV_FN 3, yuyv
+YUYV_TO_UV_FN 3, uyvy
+NVXX_TO_UV_FN 5, nv12
+NVXX_TO_UV_FN 5, nv21
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+; in theory, we could write a yuy2-to-y using vpand (i.e. AVX), but
+; that's not faster in practice
+YUYV_TO_UV_FN 3, yuyv
+YUYV_TO_UV_FN 3, uyvy, 1
+NVXX_TO_UV_FN 5, nv12
+NVXX_TO_UV_FN 5, nv21
+%endif
+
+%if ARCH_X86_64
+%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
+
+%define R m0
+%define G m1
+%define B m2
+
+%macro SWAP32 1
+%if mmsize > 16 || cpuflag(sse4)
+    pshufb   m%1, [pb_shuffle32be]
+%else
+    psrlw    xm7, xm%1, 8
+    psllw   xm%1, 8
+    por     xm%1, xm7
+    pshuflw xm%1, xm%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
+    pshufhw xm%1, xm%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
+%endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - is big endian
+; 4 - load only 2 values on sse2
+%macro LOADF32 4
+    %if notcpuflag(sse4) && %4
+        %if %3  ; big endian
+            mov tmp1q, %2
+            bswap tmp1q
+            movq xm%1, tmp1q
+        %else
+            movq m%1, %2
+        %endif
+    %else
+        movu m%1, %2
+        %if %3
+            SWAP32 %1
+        %endif
+    %endif
+    maxps m%1, m9 ; 0.0 (nan, -inf) -> 0.0
+    mulps m%1, m8 ; [pd_65535f]
+    minps m%1, m8 ; +inf -> 65535
+    ; cvtps2dq rounds to nearest int
+    ; assuming mxcsr register is default rounding
+    ; 0.40 -> 0.0, 0.50 -> 0.0, 0.51 -> 1.0
+    cvtps2dq m%1, m%1
+
+    %if notcpuflag(sse4) && %4
+        ; line up the 2 values in lanes 0,2
+        %if %3 ; big endian
+            pshufd m%1, m%1, (3 << 6 | 0 << 4 | 2 << 2 | 1 << 0)
+        %else
+            pshufd m%1, m%1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        %endif
+    %endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - is big endian
+%macro LOAD16 3
+    %if cpuflag(sse4) || mmsize > 16
+        pmovzxwd  m%1, %2
+        %if %3 ; bigendian
+            pshufb m%1, m8 ; [pb_shuffle16be]
+        %endif
+    %else
+        %if %3 ; bigendian
+            mov     tmp1d, dword %2
+            bswap   tmp1d
+            movd     xm%1, tmp1d
+            pshuflw   m%1, m%1, (3 << 6 | 0 << 4 | 3 << 2 | 1 << 0)
+            pshufd    m%1, m%1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        %else
+            movd     xm%1, %2
+            punpcklwd m%1, m9 ; interleave words with zero
+            pshufd    m%1, m%1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        %endif
+    %endif
+%endmacro
+
+%macro LOAD8_RGB 0
+    %if cpuflag(sse4) || mmsize > 16
+        pmovzxbd  R, [srcRq + xq]
+        pmovzxbd  G, [srcGq + xq]
+        pmovzxbd  B, [srcBq + xq]
+    %else
+        ; thought this would be faster but from my measurements its not
+        ; movd m0, [srcRq + xq + 0]; overeads by 2 bytes
+        ; punpcklbw m0, m9 ; interleave bytes with zero
+        ; punpcklwd m0, m9 ; interleave words with zero
+        ; pshufd m0, m0, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+
+        movzx tmp2q, byte [srcRq + xq + 1]
+        movzx tmp1q, byte [srcRq + xq + 0]
+        shl   tmp2q, 32
+        or    tmp1q, tmp2q
+        movq    xm0, tmp1q
+
+        movzx tmp2q, byte [srcGq + xq + 1]
+        movzx tmp3q, byte [srcGq + xq + 0]
+        shl   tmp2q, 32
+        or    tmp3q, tmp2q
+        movq    xm1, tmp3q
+
+        movzx tmp2q, byte [srcBq + xq + 1]
+        movzx tmp1q, byte [srcBq + xq + 0]
+        shl   tmp2q, 32
+        or    tmp1q, tmp2q
+        movq    xm2, tmp1q
+
+        pshufd   m0, m0, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        pshufd   m1, m1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        pshufd   m2, m2, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+    %endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - store only 2 values on sse2
+%macro STORE16 3
+    %if %3 && notcpuflag(sse4)
+        pshufd        m%2,  m%2, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        pshuflw       m%2,  m%2, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+        movd           %1,  m%2
+    %elif mmsize > 16
+        pshufb        m%2,   m7   ; [pb_pack_shuffle16le]
+        vpermq        m%2,  m%2,  (3 << 6 | 0 << 4 | 3 << 2 | 0 << 0)
+        movu           %1, xm%2
+    %else
+        %if cpuflag(sse4)
+            pshufb  m%2,  m7 ; [pb_pack_shuffle16le]
+        %else
+            pshuflw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+            pshufhw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+            pshufd  m%2, m%2, (3 << 6 | 3 << 4 | 2 << 2 | 0 << 0)
+        %endif
+        movq %1, m%2
+    %endif
+%endmacro
+
+%macro PMUL 3
+%if cpuflag(sse4) || mmsize > 16
+    pmulld  %1, %2, %3
+%else
+    pmuludq %1, %2, %3
+%endif
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is big endian
+; 4 - is float
+; in sse2 mode only 2 values are done per loop, due to lack of pmulld instruction
+%macro planar_rgb_to_y_fn 4
+%if %2 == 8
+    %define OFFSET (0x801<<(RGB2YUV_SHIFT-7))
+    %define RSHIFT (RGB2YUV_SHIFT-6)
+%else
+    %if %2 < 16
+        %define SHIFT %2
+        %define BPC %2
+    %else
+        %define SHIFT 14
+        %define BPC 16
+    %endif
+    %define OFFSET ((16 << (RGB2YUV_SHIFT + BPC - 8)) + (1 << (RGB2YUV_SHIFT + SHIFT - 15)))
+    %define RSHIFT (RGB2YUV_SHIFT + SHIFT - 14)
+%endif
+cglobal planar_%1_to_y, 4, 12, 13, dst, src, w, rgb2yuv, srcR, srcG, srcB, x, tmp1, tmp2, tmp3, tmp4
+    VBROADCASTSS m10, dword [rgb2yuvq + RY_IDX*4] ; ry
+    VBROADCASTSS m11, dword [rgb2yuvq + GY_IDX*4] ; gy
+    VBROADCASTSS m12, dword [rgb2yuvq + BY_IDX*4] ; by
+    pxor m9, m9
+
+    %if %4
+        movu m8, [pd_65535f]
+    %endif
+
+    %if cpuflag(sse4) || mmsize > 16
+        movu m7, [pb_pack_shuffle16le]
+        %if %3 && %2 > 8 && %2 <= 16
+            movu m8,  [pb_shuffle16be]
+        %endif
+    %endif
+
+    mov           xq, OFFSET
+    movq         xm6, xq
+    VBROADCASTSS  m6, xm6
+
+    mov srcGq, [srcq +  0]
+    mov srcBq, [srcq +  8]
+    mov srcRq, [srcq + 16]
+
+    xor xq, xq
+    %%loop_x:
+        %if %4
+            LOADF32 0, [srcRq + xq*4], %3, 1
+            LOADF32 1, [srcGq + xq*4], %3, 1
+            LOADF32 2, [srcBq + xq*4], %3, 1
+        %elif %2 == 8
+            LOAD8_RGB
+        %else
+            LOAD16 0, [srcRq + xq*2], %3
+            LOAD16 1, [srcGq + xq*2], %3
+            LOAD16 2, [srcBq + xq*2], %3
+        %endif
+
+        PMUL      R, R, m10 ; r*ry
+        PMUL      G, G, m11 ; g*gy
+        PMUL      B, B, m12 ; b*by
+        paddd    m0, m6       ; + OFFSET
+        paddd     B, G
+        paddd    m0, B
+        psrad    m0, RSHIFT
+        STORE16 [dstq + 2*xq], 0, 1
+
+        %if cpuflag(avx2) || cpuflag(sse4)
+            add xq, mmsize/4
+        %else
+            add xd, 2
+        %endif
+        cmp xd, wd
+        jl %%loop_x
+RET
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is big endian
+; 4 - is float
+; in sse2 mode only 2 values are done per loop, due to lack of pmulld instruction
+%macro planar_rgb_to_uv_fn 4
+%if %2 == 8
+    %define OFFSET (0x4001<<(RGB2YUV_SHIFT-7))
+    %define RSHIFT (RGB2YUV_SHIFT-6)
+%else
+    %if %2 < 16
+        %define SHIFT %2
+        %define BPC %2
+    %else
+        %define SHIFT 14
+        %define BPC 16
+    %endif
+    %define OFFSET ((128 << (RGB2YUV_SHIFT + BPC - 8)) + (1 << (RGB2YUV_SHIFT + SHIFT - 15)))
+    %define RSHIFT (RGB2YUV_SHIFT + SHIFT - 14)
+%endif
+cglobal planar_%1_to_uv, 5, 12, 16, dstU, dstV, src, w, rgb2yuv, srcR, srcG, srcB, x, tmp1, tmp2, tmp3
+    VBROADCASTSS m10, dword [rgb2yuvq + RU_IDX*4] ; ru
+    VBROADCASTSS m11, dword [rgb2yuvq + GU_IDX*4] ; gu
+    VBROADCASTSS m12, dword [rgb2yuvq + BU_IDX*4] ; bu
+    VBROADCASTSS m13, dword [rgb2yuvq + RV_IDX*4] ; rv
+    VBROADCASTSS m14, dword [rgb2yuvq + GV_IDX*4] ; gv
+    VBROADCASTSS m15, dword [rgb2yuvq + BV_IDX*4] ; bv
+    pxor m9, m9
+
+    %if %4
+        movu m8, [pd_65535f]
+    %endif
+
+    %if cpuflag(sse4) || mmsize > 16
+        movu m7, [pb_pack_shuffle16le]
+        %if %3 && %2 > 8 && %2 <= 16
+            movu m8,  [pb_shuffle16be]
+        %endif
+    %endif
+
+    mov          xq, OFFSET
+    movq        xm6, xq
+    VBROADCASTSS m6, xm6
+
+    mov srcGq, [srcq +  0]
+    mov srcBq, [srcq +  8]
+    mov srcRq, [srcq + 16]
+
+    xor xq, xq
+    %%loop_x:
+        %if %4
+            LOADF32 0, [srcRq + xq*4], %3, 1
+            LOADF32 1, [srcGq + xq*4], %3, 1
+            LOADF32 2, [srcBq + xq*4], %3, 1
+        %elif %2 == 8
+            LOAD8_RGB
+        %else
+            LOAD16 0, [srcRq + xq*2], %3
+            LOAD16 1, [srcGq + xq*2], %3
+            LOAD16 2, [srcBq + xq*2], %3
+        %endif
+
+        PMUL      m5, R, m10 ; r*ru
+        PMUL      m4, G, m11 ; b*gu
+        paddd     m4, m5
+        PMUL      m5, B, m12 ; b*bu
+        paddd     m4, m6     ; + OFFSET
+        paddd     m4, m5
+        psrad     m4, RSHIFT
+        STORE16 [dstUq + 2*xq], 4, 1
+
+        PMUL      R, R, m13 ; r*rv
+        PMUL      G, G, m14 ; g*gv*g
+        PMUL      B, B, m15 ; b*bv
+        paddd    m0, m6     ; + OFFSET
+        paddd     B, G
+        paddd    m0, B
+        psrad    m0, RSHIFT
+        STORE16 [dstVq + 2*xq], 0, 1
+
+        %if cpuflag(avx2) || cpuflag(sse4)
+            add xd, mmsize/4
+        %else
+            add xd, 2
+        %endif
+        cmp xd, wd
+        jl %%loop_x
+RET
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is big endian
+; 4 - is float
+%macro planar_rgb_to_a_fn 4
+cglobal planar_%1_to_a, 4, 6, 10, dst, src, w, rgb2yuv, srcA, x
+    %if %4 && (cpuflag(sse4) || mmsize > 16)
+        movu m7, [pb_pack_shuffle16le]
+    %elif %3 && (cpuflag(sse4) || mmsize > 16)
+        movu m7, [pb_shuffle16be]
+    %endif
+
+    %if %4
+        movu m8, [pd_65535f]
+    %endif
+
+    pxor   m9, m9
+    mov srcAq, [srcq +  24]
+    xor    xq, xq
+    %%loop_x:
+        %if %4 ; float
+            LOADF32 0, [srcAq + xq*4], %3, 0
+            STORE16 [dstq + xq*2], 0, 0
+            add xq, mmsize/4
+        %elif %2 == 8
+            ; only need to convert 8bit value to 16bit
+            %if cpuflag(sse4) || mmsize > 16
+                pmovzxbw  m0, [srcAq + xq]
+            %else
+                movsd     m0, [srcAq + xq]
+                punpcklbw m0, m9 ; interleave bytes with zero
+            %endif
+            psllw m0, 6
+            movu [dstq + xq*2], m0
+            add xq, mmsize/2
+        %else
+            ; only need to convert 16bit format to 16le
+            movu m0, [srcAq + xq*2]
+            %if %3 ; bigendian
+                %if cpuflag(sse4) || mmsize > 16
+                    pshufb m0, m7 ; [pb_shuffle16be]
+                %else
+                    psrlw  m7, m0, 8
+                    psllw  m0, 8
+                    por    m0, m7
+                %endif
+            %endif
+            %if %2 < 16
+                psllw m0, (14 - %2)
+            %endif
+            movu [dstq + xq*2], m0
+            add xq, mmsize/2
+        %endif
+        cmp xd, wd
+        jl %%loop_x
+RET
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is float
+%macro planer_rgbxx_y_fn_decl 3
+planar_rgb_to_y_fn  %1le,  %2, 0, %3
+planar_rgb_to_y_fn  %1be,  %2, 1, %3
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is float
+%macro planer_rgbxx_uv_fn_decl 3
+planar_rgb_to_uv_fn  %1le,  %2, 0, %3
+planar_rgb_to_uv_fn  %1be,  %2, 1, %3
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - is float
+%macro planer_rgbxx_a_fn_decl 3
+planar_rgb_to_a_fn  %1le,  %2, 0, %3
+planar_rgb_to_a_fn  %1be,  %2, 1, %3
+%endmacro
+
+%macro planar_rgb_y_all_fn_decl 0
+planar_rgb_to_y_fn        rgb,  8, 0, 0
+planer_rgbxx_y_fn_decl   rgb9,  9, 0
+planer_rgbxx_y_fn_decl  rgb10, 10, 0
+planer_rgbxx_y_fn_decl  rgb12, 12, 0
+planer_rgbxx_y_fn_decl  rgb14, 14, 0
+planer_rgbxx_y_fn_decl  rgb16, 16, 0
+planer_rgbxx_y_fn_decl rgbf32, 32, 1
+%endmacro
+
+%macro planar_rgb_uv_all_fn_decl 0
+planar_rgb_to_uv_fn        rgb,  8, 0, 0
+planer_rgbxx_uv_fn_decl   rgb9,  9, 0
+planer_rgbxx_uv_fn_decl  rgb10, 10, 0
+planer_rgbxx_uv_fn_decl  rgb12, 12, 0
+planer_rgbxx_uv_fn_decl  rgb14, 14, 0
+planer_rgbxx_uv_fn_decl  rgb16, 16, 0
+planer_rgbxx_uv_fn_decl rgbf32, 32, 1
+%endmacro
+
+%macro planar_rgb_a_all_fn_decl 0
+planar_rgb_to_a_fn        rgb,  8, 0, 0
+planer_rgbxx_a_fn_decl  rgb10, 10, 0
+planer_rgbxx_a_fn_decl  rgb12, 12, 0
+planer_rgbxx_a_fn_decl  rgb16, 16, 0
+planer_rgbxx_a_fn_decl rgbf32, 32, 1
+%endmacro
+
+; sse2 to_y only matches c speed with current implementation
+; except on floating point formats
+INIT_XMM sse2
+planer_rgbxx_y_fn_decl rgbf32, 32, 1
+planar_rgb_uv_all_fn_decl
+planar_rgb_a_all_fn_decl
+
+; sse4 to_a conversions are just the sse2 ones
+; except on floating point formats
+INIT_XMM sse4
+planar_rgb_y_all_fn_decl
+planar_rgb_uv_all_fn_decl
+planer_rgbxx_a_fn_decl rgbf32, 32, 1
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+planar_rgb_y_all_fn_decl
+planar_rgb_uv_all_fn_decl
+planar_rgb_a_all_fn_decl
+%endif
+
+%endif ; ARCH_X86_64
diff --git a/libs/ffmpeg/libswscale/x86/ops.c b/libs/ffmpeg/libswscale/x86/ops.c
new file mode 100644
index 000000000000..c2b3bd76b949
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/ops.c
@@ -0,0 +1,773 @@
+/**
+ * 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 defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <float.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/mem.h"
+
+#include "../ops_chain.h"
+
+#define DECL_ENTRY(TYPE, NAME, ...)                                             \
+    static const SwsOpEntry op_##NAME = {                                       \
+        .type = SWS_PIXEL_##TYPE,                                               \
+        __VA_ARGS__                                                             \
+    }
+
+#define DECL_ASM(TYPE, NAME, ...)                                               \
+    void ff_##NAME(void);                                                       \
+    DECL_ENTRY(TYPE, NAME,                                                      \
+        .func = ff_##NAME,                                                      \
+        __VA_ARGS__)
+
+#define DECL_PATTERN(TYPE, NAME, X, Y, Z, W, ...)                               \
+    DECL_ASM(TYPE, p##X##Y##Z##W##_##NAME,                                      \
+        .unused = { !X, !Y, !Z, !W },                                           \
+        __VA_ARGS__                                                             \
+    )
+
+#define REF_PATTERN(NAME, X, Y, Z, W)                                           \
+    &op_p##X##Y##Z##W##_##NAME
+
+#define DECL_COMMON_PATTERNS(TYPE, NAME, ...)                                   \
+    DECL_PATTERN(TYPE, NAME, 1, 0, 0, 0, __VA_ARGS__);                          \
+    DECL_PATTERN(TYPE, NAME, 1, 0, 0, 1, __VA_ARGS__);                          \
+    DECL_PATTERN(TYPE, NAME, 1, 1, 1, 0, __VA_ARGS__);                          \
+    DECL_PATTERN(TYPE, NAME, 1, 1, 1, 1, __VA_ARGS__)                           \
+
+#define REF_COMMON_PATTERNS(NAME)                                               \
+    REF_PATTERN(NAME, 1, 0, 0, 0),                                              \
+    REF_PATTERN(NAME, 1, 0, 0, 1),                                              \
+    REF_PATTERN(NAME, 1, 1, 1, 0),                                              \
+    REF_PATTERN(NAME, 1, 1, 1, 1)
+
+#define DECL_RW(EXT, TYPE, NAME, OP, ELEMS, PACKED, FRAC)                       \
+    DECL_ASM(TYPE, NAME##ELEMS##EXT,                                            \
+        .op = SWS_OP_##OP,                                                      \
+        .rw = { .elems = ELEMS, .packed = PACKED, .frac = FRAC },               \
+    );
+
+#define DECL_PACKED_RW(EXT, DEPTH)                                              \
+    DECL_RW(EXT, U##DEPTH, read##DEPTH##_packed,  READ,  2, true,  0)           \
+    DECL_RW(EXT, U##DEPTH, read##DEPTH##_packed,  READ,  3, true,  0)           \
+    DECL_RW(EXT, U##DEPTH, read##DEPTH##_packed,  READ,  4, true,  0)           \
+    DECL_RW(EXT, U##DEPTH, write##DEPTH##_packed, WRITE, 2, true,  0)           \
+    DECL_RW(EXT, U##DEPTH, write##DEPTH##_packed, WRITE, 3, true,  0)           \
+    DECL_RW(EXT, U##DEPTH, write##DEPTH##_packed, WRITE, 4, true,  0)           \
+
+#define DECL_PACK_UNPACK(EXT, TYPE, X, Y, Z, W)                                 \
+    DECL_ASM(TYPE, pack_##X##Y##Z##W##EXT,                                      \
+        .op = SWS_OP_PACK,                                                      \
+        .pack.pattern = {X, Y, Z, W},                                           \
+    );                                                                          \
+                                                                                \
+    DECL_ASM(TYPE, unpack_##X##Y##Z##W##EXT,                                    \
+        .op = SWS_OP_UNPACK,                                                    \
+        .pack.pattern = {X, Y, Z, W},                                           \
+    );                                                                          \
+
+static int setup_swap_bytes(const SwsOp *op, SwsOpPriv *out)
+{
+    const int mask = ff_sws_pixel_type_size(op->type) - 1;
+    for (int i = 0; i < 16; i++)
+        out->u8[i] = (i & ~mask) | (mask - (i & mask));
+    return 0;
+}
+
+#define DECL_SWAP_BYTES(EXT, TYPE, X, Y, Z, W)                                  \
+    DECL_ENTRY(TYPE, p##X##Y##Z##W##_swap_bytes_##TYPE##EXT,                    \
+        .op = SWS_OP_SWAP_BYTES,                                                \
+        .unused = { !X, !Y, !Z, !W },                                           \
+        .func = ff_p##X##Y##Z##W##_shuffle##EXT,                                \
+        .setup = setup_swap_bytes,                                              \
+    );
+
+#define DECL_CLEAR_ALPHA(EXT, IDX)                                              \
+    DECL_ASM(U8, clear_alpha##IDX##EXT,                                         \
+        .op = SWS_OP_CLEAR,                                                     \
+        .clear_value = -1,                                                      \
+        .unused[IDX] = true,                                                    \
+    );                                                                          \
+
+#define DECL_CLEAR_ZERO(EXT, IDX)                                               \
+    DECL_ASM(U8, clear_zero##IDX##EXT,                                          \
+        .op = SWS_OP_CLEAR,                                                     \
+        .clear_value = 0,                                                       \
+        .unused[IDX] = true,                                                    \
+    );
+
+static int setup_clear(const SwsOp *op, SwsOpPriv *out)
+{
+    for (int i = 0; i < 4; i++)
+        out->u32[i] = (uint32_t) op->c.q4[i].num;
+    return 0;
+}
+
+#define DECL_CLEAR(EXT, X, Y, Z, W)                                             \
+    DECL_PATTERN(U8, clear##EXT, X, Y, Z, W,                                    \
+        .op = SWS_OP_CLEAR,                                                     \
+        .setup = setup_clear,                                                   \
+        .flexible = true,                                                       \
+    );
+
+#define DECL_SWIZZLE(EXT, X, Y, Z, W)                                           \
+    DECL_ASM(U8, swizzle_##X##Y##Z##W##EXT,                                     \
+        .op = SWS_OP_SWIZZLE,                                                   \
+        .swizzle.in = {X, Y, Z, W},                                             \
+    );
+
+#define DECL_CONVERT(EXT, FROM, TO)                                             \
+    DECL_COMMON_PATTERNS(FROM, convert_##FROM##_##TO##EXT,                      \
+        .op = SWS_OP_CONVERT,                                                   \
+        .convert.to = SWS_PIXEL_##TO,                                           \
+    );
+
+#define DECL_EXPAND(EXT, FROM, TO)                                              \
+    DECL_COMMON_PATTERNS(FROM, expand_##FROM##_##TO##EXT,                       \
+        .op = SWS_OP_CONVERT,                                                   \
+        .convert.to = SWS_PIXEL_##TO,                                           \
+        .convert.expand = true,                                                 \
+    );
+
+static int setup_shift(const SwsOp *op, SwsOpPriv *out)
+{
+    out->u16[0] = op->c.u;
+    return 0;
+}
+
+#define DECL_SHIFT16(EXT)                                                       \
+    DECL_COMMON_PATTERNS(U16, lshift16##EXT,                                    \
+        .op = SWS_OP_LSHIFT,                                                    \
+        .setup = setup_shift,                                                   \
+        .flexible = true,                                                       \
+    );                                                                          \
+                                                                                \
+    DECL_COMMON_PATTERNS(U16, rshift16##EXT,                                    \
+        .op = SWS_OP_RSHIFT,                                                    \
+        .setup = setup_shift,                                                   \
+        .flexible = true,                                                       \
+    );
+
+#define DECL_MIN_MAX(EXT)                                                       \
+    DECL_COMMON_PATTERNS(F32, min##EXT,                                         \
+        .op = SWS_OP_MIN,                                                       \
+        .setup = ff_sws_setup_q4,                                               \
+        .flexible = true,                                                       \
+    );                                                                          \
+                                                                                \
+    DECL_COMMON_PATTERNS(F32, max##EXT,                                         \
+        .op = SWS_OP_MAX,                                                       \
+        .setup = ff_sws_setup_q4,                                               \
+        .flexible = true,                                                       \
+    );
+
+#define DECL_SCALE(EXT)                                                         \
+    DECL_COMMON_PATTERNS(F32, scale##EXT,                                       \
+        .op = SWS_OP_SCALE,                                                     \
+        .setup = ff_sws_setup_q,                                                \
+        .flexible = true,                                                       \
+    );
+
+#define DECL_EXPAND_BITS(EXT, BITS)                                             \
+    DECL_ASM(U##BITS, expand_bits##BITS##EXT,                                   \
+        .op = SWS_OP_SCALE,                                                     \
+        .scale = { .num = ((1 << (BITS)) - 1), .den = 1 },                      \
+    );
+
+static int setup_dither(const SwsOp *op, SwsOpPriv *out)
+{
+    /* 1x1 matrix / single constant */
+    if (!op->dither.size_log2) {
+        const AVRational k = op->dither.matrix[0];
+        out->f32[0] = (float) k.num / k.den;
+        return 0;
+    }
+
+    const int size = 1 << op->dither.size_log2;
+    const int8_t *off = op->dither.y_offset;
+    int max_offset = 0;
+    for (int i = 0; i < 4; i++) {
+        if (off[i] >= 0)
+            max_offset = FFMAX(max_offset, off[i] & (size - 1));
+    }
+
+    /* Allocate extra rows to allow over-reading for row offsets. Note that
+     * max_offset is currently never larger than 5, so the extra space needed
+     * for this over-allocation is bounded by 5 * size * sizeof(float),
+     * typically 320 bytes for a 16x16 dither matrix. */
+    const int stride = size * sizeof(float);
+    const int num_rows = size + max_offset;
+    float *matrix = out->ptr = av_mallocz(num_rows * stride);
+    if (!matrix)
+        return AVERROR(ENOMEM);
+
+    for (int i = 0; i < size * size; i++)
+        matrix[i] = (float) op->dither.matrix[i].num / op->dither.matrix[i].den;
+
+    memcpy(&matrix[size * size], matrix, max_offset * stride);
+
+    /* Store relative pointer offset to each row inside extra space */
+    static_assert(sizeof(out->ptr) <= sizeof(int16_t[4]), ">8 byte pointers not supported");
+    assert(max_offset * stride <= INT16_MAX);
+    int16_t *off_out = &out->i16[4];
+    for (int i = 0; i < 4; i++)
+        off_out[i] = off[i] >= 0 ? (off[i] & (size - 1)) * stride : -1;
+
+    return 0;
+}
+
+#define DECL_DITHER(DECL_MACRO, EXT, SIZE)                                      \
+    DECL_MACRO(F32, dither##SIZE##EXT,                                          \
+        .op    = SWS_OP_DITHER,                                                 \
+        .setup = setup_dither,                                                  \
+        .free  = (SIZE) ? av_free : NULL,                                       \
+        .dither_size = SIZE,                                                    \
+    );
+
+static int setup_linear(const SwsOp *op, SwsOpPriv *out)
+{
+    float *matrix = out->ptr = av_mallocz(sizeof(float[4][5]));
+    if (!matrix)
+        return AVERROR(ENOMEM);
+
+    for (int y = 0; y < 4; y++) {
+        for (int x = 0; x < 5; x++)
+            matrix[y * 5 + x] = (float) op->lin.m[y][x].num / op->lin.m[y][x].den;
+    }
+
+    return 0;
+}
+
+#define DECL_LINEAR(EXT, NAME, MASK)                                            \
+    DECL_ASM(F32, NAME##EXT,                                                    \
+        .op    = SWS_OP_LINEAR,                                                 \
+        .setup = setup_linear,                                                  \
+        .free  = av_free,                                                       \
+        .linear_mask = (MASK),                                                  \
+    );
+
+#define DECL_FUNCS_8(SIZE, EXT, FLAG)                                           \
+    DECL_RW(EXT, U8, read_planar,   READ,  1, false, 0)                         \
+    DECL_RW(EXT, U8, read_planar,   READ,  2, false, 0)                         \
+    DECL_RW(EXT, U8, read_planar,   READ,  3, false, 0)                         \
+    DECL_RW(EXT, U8, read_planar,   READ,  4, false, 0)                         \
+    DECL_RW(EXT, U8, write_planar,  WRITE, 1, false, 0)                         \
+    DECL_RW(EXT, U8, write_planar,  WRITE, 2, false, 0)                         \
+    DECL_RW(EXT, U8, write_planar,  WRITE, 3, false, 0)                         \
+    DECL_RW(EXT, U8, write_planar,  WRITE, 4, false, 0)                         \
+    DECL_RW(EXT, U8, read_nibbles,  READ,  1, false, 1)                         \
+    DECL_RW(EXT, U8, read_bits,     READ,  1, false, 3)                         \
+    DECL_RW(EXT, U8, write_bits,    WRITE, 1, false, 3)                         \
+    DECL_EXPAND_BITS(EXT, 8)                                                    \
+    DECL_PACKED_RW(EXT, 8)                                                      \
+    DECL_PACK_UNPACK(EXT, U8, 1, 2, 1, 0)                                       \
+    DECL_PACK_UNPACK(EXT, U8, 3, 3, 2, 0)                                       \
+    DECL_PACK_UNPACK(EXT, U8, 2, 3, 3, 0)                                       \
+    void ff_p1000_shuffle##EXT(void);                                           \
+    void ff_p1001_shuffle##EXT(void);                                           \
+    void ff_p1110_shuffle##EXT(void);                                           \
+    void ff_p1111_shuffle##EXT(void);                                           \
+    DECL_SWIZZLE(EXT, 3, 0, 1, 2)                                               \
+    DECL_SWIZZLE(EXT, 3, 0, 2, 1)                                               \
+    DECL_SWIZZLE(EXT, 2, 1, 0, 3)                                               \
+    DECL_SWIZZLE(EXT, 3, 2, 1, 0)                                               \
+    DECL_SWIZZLE(EXT, 3, 1, 0, 2)                                               \
+    DECL_SWIZZLE(EXT, 3, 2, 0, 1)                                               \
+    DECL_SWIZZLE(EXT, 1, 2, 0, 3)                                               \
+    DECL_SWIZZLE(EXT, 1, 0, 2, 3)                                               \
+    DECL_SWIZZLE(EXT, 2, 0, 1, 3)                                               \
+    DECL_SWIZZLE(EXT, 2, 3, 1, 0)                                               \
+    DECL_SWIZZLE(EXT, 2, 1, 3, 0)                                               \
+    DECL_SWIZZLE(EXT, 1, 2, 3, 0)                                               \
+    DECL_SWIZZLE(EXT, 1, 3, 2, 0)                                               \
+    DECL_SWIZZLE(EXT, 0, 2, 1, 3)                                               \
+    DECL_SWIZZLE(EXT, 0, 2, 3, 1)                                               \
+    DECL_SWIZZLE(EXT, 0, 3, 1, 2)                                               \
+    DECL_SWIZZLE(EXT, 3, 1, 2, 0)                                               \
+    DECL_SWIZZLE(EXT, 0, 3, 2, 1)                                               \
+    DECL_SWIZZLE(EXT, 0, 0, 0, 3)                                               \
+    DECL_SWIZZLE(EXT, 3, 0, 0, 0)                                               \
+    DECL_SWIZZLE(EXT, 0, 0, 0, 1)                                               \
+    DECL_SWIZZLE(EXT, 1, 0, 0, 0)                                               \
+    DECL_CLEAR_ALPHA(EXT, 0)                                                    \
+    DECL_CLEAR_ALPHA(EXT, 1)                                                    \
+    DECL_CLEAR_ALPHA(EXT, 3)                                                    \
+    DECL_CLEAR_ZERO(EXT, 0)                                                     \
+    DECL_CLEAR_ZERO(EXT, 1)                                                     \
+    DECL_CLEAR_ZERO(EXT, 3)                                                     \
+    DECL_CLEAR(EXT, 1, 1, 1, 0)                                                 \
+    DECL_CLEAR(EXT, 0, 1, 1, 1)                                                 \
+    DECL_CLEAR(EXT, 0, 0, 1, 1)                                                 \
+    DECL_CLEAR(EXT, 1, 0, 0, 1)                                                 \
+    DECL_CLEAR(EXT, 1, 1, 0, 0)                                                 \
+    DECL_CLEAR(EXT, 0, 1, 0, 1)                                                 \
+    DECL_CLEAR(EXT, 1, 0, 1, 0)                                                 \
+    DECL_CLEAR(EXT, 1, 0, 0, 0)                                                 \
+    DECL_CLEAR(EXT, 0, 1, 0, 0)                                                 \
+    DECL_CLEAR(EXT, 0, 0, 1, 0)                                                 \
+                                                                                \
+static const SwsOpTable ops8##EXT = {                                           \
+    .cpu_flags = AV_CPU_FLAG_##FLAG,                                            \
+    .block_size = SIZE,                                                         \
+    .entries = {                                                                \
+        &op_read_planar1##EXT,                                                  \
+        &op_read_planar2##EXT,                                                  \
+        &op_read_planar3##EXT,                                                  \
+        &op_read_planar4##EXT,                                                  \
+        &op_write_planar1##EXT,                                                 \
+        &op_write_planar2##EXT,                                                 \
+        &op_write_planar3##EXT,                                                 \
+        &op_write_planar4##EXT,                                                 \
+        &op_read8_packed2##EXT,                                                 \
+        &op_read8_packed3##EXT,                                                 \
+        &op_read8_packed4##EXT,                                                 \
+        &op_write8_packed2##EXT,                                                \
+        &op_write8_packed3##EXT,                                                \
+        &op_write8_packed4##EXT,                                                \
+        &op_read_nibbles1##EXT,                                                 \
+        &op_read_bits1##EXT,                                                    \
+        &op_write_bits1##EXT,                                                   \
+        &op_expand_bits8##EXT,                                                  \
+        &op_pack_1210##EXT,                                                     \
+        &op_pack_3320##EXT,                                                     \
+        &op_pack_2330##EXT,                                                     \
+        &op_unpack_1210##EXT,                                                   \
+        &op_unpack_3320##EXT,                                                   \
+        &op_unpack_2330##EXT,                                                   \
+        &op_swizzle_3012##EXT,                                                  \
+        &op_swizzle_3021##EXT,                                                  \
+        &op_swizzle_2103##EXT,                                                  \
+        &op_swizzle_3210##EXT,                                                  \
+        &op_swizzle_3102##EXT,                                                  \
+        &op_swizzle_3201##EXT,                                                  \
+        &op_swizzle_1203##EXT,                                                  \
+        &op_swizzle_1023##EXT,                                                  \
+        &op_swizzle_2013##EXT,                                                  \
+        &op_swizzle_2310##EXT,                                                  \
+        &op_swizzle_2130##EXT,                                                  \
+        &op_swizzle_1230##EXT,                                                  \
+        &op_swizzle_1320##EXT,                                                  \
+        &op_swizzle_0213##EXT,                                                  \
+        &op_swizzle_0231##EXT,                                                  \
+        &op_swizzle_0312##EXT,                                                  \
+        &op_swizzle_3120##EXT,                                                  \
+        &op_swizzle_0321##EXT,                                                  \
+        &op_swizzle_0003##EXT,                                                  \
+        &op_swizzle_0001##EXT,                                                  \
+        &op_swizzle_3000##EXT,                                                  \
+        &op_swizzle_1000##EXT,                                                  \
+        &op_clear_alpha0##EXT,                                                  \
+        &op_clear_alpha1##EXT,                                                  \
+        &op_clear_alpha3##EXT,                                                  \
+        &op_clear_zero0##EXT,                                                   \
+        &op_clear_zero1##EXT,                                                   \
+        &op_clear_zero3##EXT,                                                   \
+        REF_PATTERN(clear##EXT, 1, 1, 1, 0),                                    \
+        REF_PATTERN(clear##EXT, 0, 1, 1, 1),                                    \
+        REF_PATTERN(clear##EXT, 0, 0, 1, 1),                                    \
+        REF_PATTERN(clear##EXT, 1, 0, 0, 1),                                    \
+        REF_PATTERN(clear##EXT, 1, 1, 0, 0),                                    \
+        REF_PATTERN(clear##EXT, 0, 1, 0, 1),                                    \
+        REF_PATTERN(clear##EXT, 1, 0, 1, 0),                                    \
+        REF_PATTERN(clear##EXT, 1, 0, 0, 0),                                    \
+        REF_PATTERN(clear##EXT, 0, 1, 0, 0),                                    \
+        REF_PATTERN(clear##EXT, 0, 0, 1, 0),                                    \
+        NULL                                                                    \
+    },                                                                          \
+};
+
+#define DECL_FUNCS_16(SIZE, EXT, FLAG)                                          \
+    DECL_PACKED_RW(EXT, 16)                                                     \
+    DECL_EXPAND_BITS(EXT, 16)                                                   \
+    DECL_PACK_UNPACK(EXT, U16, 4, 4, 4, 0)                                      \
+    DECL_PACK_UNPACK(EXT, U16, 5, 5, 5, 0)                                      \
+    DECL_PACK_UNPACK(EXT, U16, 5, 6, 5, 0)                                      \
+    DECL_SWAP_BYTES(EXT, U16, 1, 0, 0, 0)                                       \
+    DECL_SWAP_BYTES(EXT, U16, 1, 0, 0, 1)                                       \
+    DECL_SWAP_BYTES(EXT, U16, 1, 1, 1, 0)                                       \
+    DECL_SWAP_BYTES(EXT, U16, 1, 1, 1, 1)                                       \
+    DECL_SHIFT16(EXT)                                                           \
+    DECL_CONVERT(EXT,  U8, U16)                                                 \
+    DECL_CONVERT(EXT, U16,  U8)                                                 \
+    DECL_EXPAND(EXT,   U8, U16)                                                 \
+                                                                                \
+static const SwsOpTable ops16##EXT = {                                          \
+    .cpu_flags = AV_CPU_FLAG_##FLAG,                                            \
+    .block_size = SIZE,                                                         \
+    .entries = {                                                                \
+        &op_read16_packed2##EXT,                                                \
+        &op_read16_packed3##EXT,                                                \
+        &op_read16_packed4##EXT,                                                \
+        &op_write16_packed2##EXT,                                               \
+        &op_write16_packed3##EXT,                                               \
+        &op_write16_packed4##EXT,                                               \
+        &op_pack_4440##EXT,                                                     \
+        &op_pack_5550##EXT,                                                     \
+        &op_pack_5650##EXT,                                                     \
+        &op_unpack_4440##EXT,                                                   \
+        &op_unpack_5550##EXT,                                                   \
+        &op_unpack_5650##EXT,                                                   \
+        &op_expand_bits16##EXT,                                                 \
+        REF_COMMON_PATTERNS(swap_bytes_U16##EXT),                               \
+        REF_COMMON_PATTERNS(convert_U8_U16##EXT),                               \
+        REF_COMMON_PATTERNS(convert_U16_U8##EXT),                               \
+        REF_COMMON_PATTERNS(expand_U8_U16##EXT),                                \
+        REF_COMMON_PATTERNS(lshift16##EXT),                                     \
+        REF_COMMON_PATTERNS(rshift16##EXT),                                     \
+        NULL                                                                    \
+    },                                                                          \
+};
+
+#define DECL_FUNCS_32(SIZE, EXT, FLAG)                                          \
+    DECL_PACKED_RW(_m2##EXT, 32)                                                \
+    DECL_PACK_UNPACK(_m2##EXT, U32, 10, 10, 10, 2)                              \
+    DECL_PACK_UNPACK(_m2##EXT, U32, 2, 10, 10, 10)                              \
+    DECL_SWAP_BYTES(_m2##EXT, U32, 1, 0, 0, 0)                                  \
+    DECL_SWAP_BYTES(_m2##EXT, U32, 1, 0, 0, 1)                                  \
+    DECL_SWAP_BYTES(_m2##EXT, U32, 1, 1, 1, 0)                                  \
+    DECL_SWAP_BYTES(_m2##EXT, U32, 1, 1, 1, 1)                                  \
+    DECL_CONVERT(EXT,  U8, U32)                                                 \
+    DECL_CONVERT(EXT, U32,  U8)                                                 \
+    DECL_CONVERT(EXT, U16, U32)                                                 \
+    DECL_CONVERT(EXT, U32, U16)                                                 \
+    DECL_CONVERT(EXT,  U8, F32)                                                 \
+    DECL_CONVERT(EXT, F32,  U8)                                                 \
+    DECL_CONVERT(EXT, U16, F32)                                                 \
+    DECL_CONVERT(EXT, F32, U16)                                                 \
+    DECL_EXPAND(EXT,   U8, U32)                                                 \
+    DECL_MIN_MAX(EXT)                                                           \
+    DECL_SCALE(EXT)                                                             \
+    DECL_DITHER(DECL_COMMON_PATTERNS, EXT, 0)                                   \
+    DECL_DITHER(DECL_ASM, EXT, 1)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 2)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 3)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 4)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 5)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 6)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 7)                                               \
+    DECL_DITHER(DECL_ASM, EXT, 8)                                               \
+    DECL_LINEAR(EXT, luma,      SWS_MASK_LUMA)                                  \
+    DECL_LINEAR(EXT, alpha,     SWS_MASK_ALPHA)                                 \
+    DECL_LINEAR(EXT, lumalpha,  SWS_MASK_LUMA | SWS_MASK_ALPHA)                 \
+    DECL_LINEAR(EXT, dot3,      0x7)                                            \
+    DECL_LINEAR(EXT, row0,      SWS_MASK_ROW(0))                                \
+    DECL_LINEAR(EXT, row0a,     SWS_MASK_ROW(0) | SWS_MASK_ALPHA)               \
+    DECL_LINEAR(EXT, diag3,     SWS_MASK_DIAG3)                                 \
+    DECL_LINEAR(EXT, diag4,     SWS_MASK_DIAG4)                                 \
+    DECL_LINEAR(EXT, diagoff3,  SWS_MASK_DIAG3 | SWS_MASK_OFF3)                 \
+    DECL_LINEAR(EXT, matrix3,   SWS_MASK_MAT3)                                  \
+    DECL_LINEAR(EXT, affine3,   SWS_MASK_MAT3 | SWS_MASK_OFF3)                  \
+    DECL_LINEAR(EXT, affine3a,  SWS_MASK_MAT3 | SWS_MASK_OFF3 | SWS_MASK_ALPHA) \
+    DECL_LINEAR(EXT, matrix4,   SWS_MASK_MAT4)                                  \
+    DECL_LINEAR(EXT, affine4,   SWS_MASK_MAT4 | SWS_MASK_OFF4)                  \
+                                                                                \
+static const SwsOpTable ops32##EXT = {                                          \
+    .cpu_flags = AV_CPU_FLAG_##FLAG,                                            \
+    .block_size = SIZE,                                                         \
+    .entries = {                                                                \
+        &op_read32_packed2_m2##EXT,                                             \
+        &op_read32_packed3_m2##EXT,                                             \
+        &op_read32_packed4_m2##EXT,                                             \
+        &op_write32_packed2_m2##EXT,                                            \
+        &op_write32_packed3_m2##EXT,                                            \
+        &op_write32_packed4_m2##EXT,                                            \
+        &op_pack_1010102_m2##EXT,                                               \
+        &op_pack_2101010_m2##EXT,                                               \
+        &op_unpack_1010102_m2##EXT,                                             \
+        &op_unpack_2101010_m2##EXT,                                             \
+        REF_COMMON_PATTERNS(swap_bytes_U32_m2##EXT),                            \
+        REF_COMMON_PATTERNS(convert_U8_U32##EXT),                               \
+        REF_COMMON_PATTERNS(convert_U32_U8##EXT),                               \
+        REF_COMMON_PATTERNS(convert_U16_U32##EXT),                              \
+        REF_COMMON_PATTERNS(convert_U32_U16##EXT),                              \
+        REF_COMMON_PATTERNS(convert_U8_F32##EXT),                               \
+        REF_COMMON_PATTERNS(convert_F32_U8##EXT),                               \
+        REF_COMMON_PATTERNS(convert_U16_F32##EXT),                              \
+        REF_COMMON_PATTERNS(convert_F32_U16##EXT),                              \
+        REF_COMMON_PATTERNS(expand_U8_U32##EXT),                                \
+        REF_COMMON_PATTERNS(min##EXT),                                          \
+        REF_COMMON_PATTERNS(max##EXT),                                          \
+        REF_COMMON_PATTERNS(scale##EXT),                                        \
+        REF_COMMON_PATTERNS(dither0##EXT),                                      \
+        &op_dither1##EXT,                                                       \
+        &op_dither2##EXT,                                                       \
+        &op_dither3##EXT,                                                       \
+        &op_dither4##EXT,                                                       \
+        &op_dither5##EXT,                                                       \
+        &op_dither6##EXT,                                                       \
+        &op_dither7##EXT,                                                       \
+        &op_dither8##EXT,                                                       \
+        &op_luma##EXT,                                                          \
+        &op_alpha##EXT,                                                         \
+        &op_lumalpha##EXT,                                                      \
+        &op_dot3##EXT,                                                          \
+        &op_row0##EXT,                                                          \
+        &op_row0a##EXT,                                                         \
+        &op_diag3##EXT,                                                         \
+        &op_diag4##EXT,                                                         \
+        &op_diagoff3##EXT,                                                      \
+        &op_matrix3##EXT,                                                       \
+        &op_affine3##EXT,                                                       \
+        &op_affine3a##EXT,                                                      \
+        &op_matrix4##EXT,                                                       \
+        &op_affine4##EXT,                                                       \
+        NULL                                                                    \
+    },                                                                          \
+};
+
+DECL_FUNCS_8(16, _m1_sse4, SSE4)
+DECL_FUNCS_8(32, _m1_avx2, AVX2)
+DECL_FUNCS_8(32, _m2_sse4, SSE4)
+DECL_FUNCS_8(64, _m2_avx2, AVX2)
+
+DECL_FUNCS_16(16, _m1_avx2, AVX2)
+DECL_FUNCS_16(32, _m2_avx2, AVX2)
+
+DECL_FUNCS_32(16, _avx2, AVX2)
+
+static const SwsOpTable *const tables[] = {
+    &ops8_m1_sse4,
+    &ops8_m1_avx2,
+    &ops8_m2_sse4,
+    &ops8_m2_avx2,
+    &ops16_m1_avx2,
+    &ops16_m2_avx2,
+    &ops32_avx2,
+};
+
+static av_const int get_mmsize(const int cpu_flags)
+{
+    if (cpu_flags & AV_CPU_FLAG_AVX512)
+        return 64;
+    else if (cpu_flags & AV_CPU_FLAG_AVX2)
+        return 32;
+    else if (cpu_flags & AV_CPU_FLAG_SSE4)
+        return 16;
+    else
+        return AVERROR(ENOTSUP);
+}
+
+/**
+ * Returns true if the operation's implementation only depends on the block
+ * size, and not the underlying pixel type
+ */
+static bool op_is_type_invariant(const SwsOp *op)
+{
+    switch (op->op) {
+    case SWS_OP_READ:
+    case SWS_OP_WRITE:
+        return !(op->rw.elems > 1 && op->rw.packed) && !op->rw.frac;
+    case SWS_OP_SWIZZLE:
+    case SWS_OP_CLEAR:
+        return true;
+    }
+
+    return false;
+}
+
+static int solve_shuffle(const SwsOpList *ops, int mmsize, SwsCompiledOp *out)
+{
+    uint8_t shuffle[16];
+    int read_bytes, write_bytes;
+    int pixels;
+
+    /* Solve the shuffle mask for one 128-bit lane only */
+    pixels = ff_sws_solve_shuffle(ops, shuffle, 16, 0x80, &read_bytes, &write_bytes);
+    if (pixels < 0)
+        return pixels;
+
+    /* We can't shuffle acress lanes, so restrict the vector size to XMM
+     * whenever the read/write size would be a subset of the full vector */
+    if (read_bytes < 16 || write_bytes < 16)
+        mmsize = 16;
+
+    const int num_lanes = mmsize / 16;
+    const int in_total  = num_lanes * read_bytes;
+    const int out_total = num_lanes * write_bytes;
+    const int read_size = in_total <= 4 ? 4 : /* movd */
+                          in_total <= 8 ? 8 : /* movq */
+                          mmsize;             /* movu */
+
+    *out = (SwsCompiledOp) {
+        .priv        = av_memdup(shuffle, sizeof(shuffle)),
+        .free        = av_free,
+        .slice_align = 1,
+        .block_size  = pixels * num_lanes,
+        .over_read   = read_size - in_total,
+        .over_write  = mmsize - out_total,
+        .cpu_flags   = mmsize > 32 ? AV_CPU_FLAG_AVX512 :
+                       mmsize > 16 ? AV_CPU_FLAG_AVX2 :
+                                     AV_CPU_FLAG_SSE4,
+    };
+
+    if (!out->priv)
+        return AVERROR(ENOMEM);
+
+#define ASSIGN_SHUFFLE_FUNC(IN, OUT, EXT)                                       \
+do {                                                                            \
+    SWS_DECL_FUNC(ff_packed_shuffle##IN##_##OUT##_##EXT);                       \
+    if (in_total == IN && out_total == OUT)                                     \
+        out->func = ff_packed_shuffle##IN##_##OUT##_##EXT;                      \
+} while (0)
+
+    ASSIGN_SHUFFLE_FUNC( 5, 15, sse4);
+    ASSIGN_SHUFFLE_FUNC( 4, 16, sse4);
+    ASSIGN_SHUFFLE_FUNC( 2, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(16,  8, sse4);
+    ASSIGN_SHUFFLE_FUNC(10, 15, sse4);
+    ASSIGN_SHUFFLE_FUNC( 8, 16, sse4);
+    ASSIGN_SHUFFLE_FUNC( 4, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(15, 15, sse4);
+    ASSIGN_SHUFFLE_FUNC(12, 16, sse4);
+    ASSIGN_SHUFFLE_FUNC( 6, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(16, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(16, 16, sse4);
+    ASSIGN_SHUFFLE_FUNC( 8, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(12, 12, sse4);
+    ASSIGN_SHUFFLE_FUNC(32, 32, avx2);
+    ASSIGN_SHUFFLE_FUNC(64, 64, avx512);
+    av_assert1(out->func);
+    return 0;
+}
+
+/* Normalize clear values into 32-bit integer constants */
+static void normalize_clear(SwsOp *op)
+{
+    static_assert(sizeof(uint32_t) == sizeof(int), "int size mismatch");
+    SwsOpPriv priv;
+    union {
+        uint32_t u32;
+        int i;
+    } c;
+
+    ff_sws_setup_q4(op, &priv);
+    for (int i = 0; i < 4; i++) {
+        if (!op->c.q4[i].den)
+            continue;
+        switch (ff_sws_pixel_type_size(op->type)) {
+        case 1: c.u32 = 0x1010101U * priv.u8[i]; break;
+        case 2: c.u32 = (uint32_t)priv.u16[i] << 16 | priv.u16[i]; break;
+        case 4: c.u32 = priv.u32[i]; break;
+        }
+
+        op->c.q4[i].num = c.i;
+        op->c.q4[i].den = 1;
+    }
+}
+
+static int compile(SwsContext *ctx, SwsOpList *ops, SwsCompiledOp *out)
+{
+    const int cpu_flags = av_get_cpu_flags();
+    const int mmsize = get_mmsize(cpu_flags);
+    if (mmsize < 0)
+        return mmsize;
+
+    const SwsOp *read  = ff_sws_op_list_input(ops);
+    const SwsOp *write = ff_sws_op_list_output(ops);
+    av_assert1(write);
+    int ret;
+
+    /* Special fast path for in-place packed shuffle */
+    ret = solve_shuffle(ops, mmsize, out);
+    if (ret != AVERROR(ENOTSUP))
+        return ret;
+
+    SwsOpChain *chain = ff_sws_op_chain_alloc();
+    if (!chain)
+        return AVERROR(ENOMEM);
+
+    *out = (SwsCompiledOp) {
+        .priv = chain,
+        .slice_align = 1,
+        .free = ff_sws_op_chain_free_cb,
+
+        /* Use at most two full YMM regs during the widest precision section */
+        .block_size = 2 * FFMIN(mmsize, 32) / ff_sws_op_list_max_size(ops),
+    };
+
+    /* 3-component reads/writes process one extra garbage word */
+    if (read && read->rw.packed && read->rw.elems == 3)
+        out->over_read = sizeof(uint32_t);
+    if (write->rw.packed && write->rw.elems == 3)
+        out->over_write = sizeof(uint32_t);
+
+
+    /* Make on-stack copy of `ops` to iterate over */
+    SwsOpList rest = *ops;
+    do {
+        int op_block_size = out->block_size;
+        SwsOp *op = &rest.ops[0];
+
+        if (op_is_type_invariant(op)) {
+            if (op->op == SWS_OP_CLEAR)
+                normalize_clear(op);
+            op_block_size *= ff_sws_pixel_type_size(op->type);
+            op->type = SWS_PIXEL_U8;
+        }
+
+        ret = ff_sws_op_compile_tables(tables, FF_ARRAY_ELEMS(tables), &rest,
+                                       op_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;
+    }
+
+#define ASSIGN_PROCESS_FUNC(NAME)                               \
+    do {                                                        \
+        SWS_DECL_FUNC(NAME);                                    \
+        void NAME##_return(void);                               \
+        ret = ff_sws_op_chain_append(chain, NAME##_return,      \
+                                     NULL, &(SwsOpPriv) {0});   \
+        out->func = NAME;                                       \
+    } while (0)
+
+    const int read_planes  = read ? (read->rw.packed ? 1 : read->rw.elems) : 0;
+    const int write_planes = write->rw.packed ? 1 : write->rw.elems;
+    switch (FFMAX(read_planes, write_planes)) {
+    case 1: ASSIGN_PROCESS_FUNC(ff_sws_process1_x86); break;
+    case 2: ASSIGN_PROCESS_FUNC(ff_sws_process2_x86); break;
+    case 3: ASSIGN_PROCESS_FUNC(ff_sws_process3_x86); break;
+    case 4: ASSIGN_PROCESS_FUNC(ff_sws_process4_x86); break;
+    }
+
+    if (ret < 0) {
+        ff_sws_op_chain_free(chain);
+        return ret;
+    }
+
+    out->cpu_flags = chain->cpu_flags;
+    return 0;
+}
+
+const SwsOpBackend backend_x86 = {
+    .name       = "x86",
+    .compile    = compile,
+    .hw_format  = AV_PIX_FMT_NONE,
+};
+
+#endif
diff --git a/libs/ffmpeg/libswscale/x86/ops_common.asm b/libs/ffmpeg/libswscale/x86/ops_common.asm
new file mode 100644
index 000000000000..55398866decf
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/ops_common.asm
@@ -0,0 +1,316 @@
+;******************************************************************************
+;* 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
+;******************************************************************************
+
+%pragma makedep header
+
+%include "libavutil/x86/x86util.asm"
+
+; High-level explanation of how the x86 backend works:
+;
+; sws_processN is the shared entry point for all operation chains. This
+; function is responsible for the block loop, as well as initializing the
+; plane pointers. It will jump directly into the first operation kernel,
+; and each operation kernel will jump directly into the next one, with the
+; final kernel jumping back into the sws_process return point. (See label
+; `sws_process.return` in ops_int.asm)
+;
+; To handle the jump back to the return point, we append an extra address
+; corresponding to the correct sws_process.return label into the SwsOpChain,
+; and have the WRITE kernel jump into it as usual. (See the FINISH macro)
+;
+; Inside an operation chain, we use a custom calling convention to preserve
+; registers between kernels. The exact register allocation is found further
+; below in this file, but we basically reserve (and share) the following
+; registers:
+;
+; - const execq (read-only, shared execution data, see SwsOpExec); stores the
+;   static metadata for this call and describes the image layouts
+;
+; - implq (read-only, operation chain, see SwsOpChain); stores the private data
+;   for each operation as well as the pointer to the next kernel in the sequence.
+;   This register is automatically incremented by the CONTINUE macro, and will
+;   be reset back to the first operation kernel by sws_process.
+;
+; - bxd, yd: current line and block number, used as loop counters in sws_process.
+;   Also used by e.g. the dithering code to do position-dependent dithering.
+;
+; - tmp0, tmp1: two temporary registers which are NOT preserved between kernels
+;
+; - inNq, outNq: plane pointers. These are incremented automatically after the
+;   corresponding read/write operation, by the read/write kernels themselves.
+;   sws_process will take care of resetting these to the next line after the
+;   block loop is done.
+;
+; Additionally, we pass data between kernels by directly keeping them inside
+; vector registers. For this, we reserve the following registers:
+;
+; - mx, my, mz, mw:     low half of the X, Y, Z and W components
+; - mx2, my2, mz2, mw2: high half of the X, Y, Z and W components
+; (As well as sized variants for xmx, ymx, etc.)
+;
+; The "high half" registers are only sometimes used; in order to enable
+; processing more pixels at the same time. See `decl_v2` below, which allows
+; assembling the same operation twice, once with only the lower half (V2=0),
+; and once with both halves (V2=1). The remaining vectors are free for use
+; inside operation kernels, starting from m8.
+;
+; The basic rule is that we always use the full set of both vector registers
+; when processing the largest element size within a pixel chain. For example,
+; if we load 8-bit values and convert them to 32-bit floats internally, then
+; we would have an operation chain which combines an SSE4 V2=0 u8 kernel (128
+; bits = 16 pixels) with an AVX2 V2=1 f32 kernel (512 bits = 16 pixels). This
+; keeps the number of pixels being processed (the block size) constant. The
+; V2 setting is suffixed to the operation name (_m1 or _m2) during name
+; mangling.
+;
+; This design leaves us with the following set of possibilities:
+;
+; SSE4:
+; - max element is 32-bit: currently unsupported
+; - max element is 16-bit: currently unsupported
+; - max element is 8-bit:  block size 32, u8_m2_sse4
+;
+; AVX2:
+; - max element is 32-bit: block size 16, u32_m2_avx2, u16_m1_avx2, u8_m1_sse4
+; - max element is 16-bit: block size 32, u16_m2_avx2, u8_m1_avx2
+; - max element is 8-bit:  block size 64, u8_m2_avx2
+;
+; Meaning we need to cover the following code paths for each bit depth:
+;
+; -  8-bit kernels: m1_sse4, m2_sse4, m1_avx2, m2_avx2
+; - 16-bit kernels: m1_avx2, m2_avx2
+; - 32-bit kernels: m2_avx2
+;
+; This is achieved by macro'ing each operation kernel and declaring it once
+; per SIMD version, and (if needed) once per V2 setting using decl_v2. (See
+; the bottom of ops_int.asm for an example)
+;
+; Finally, we overload some operation kernel to different number of components,
+; using the `decl_pattern` and `decl_common_patterns` macros. Inside these
+; kernels, the variables X, Y, Z and W will be set to 0 or 1 respectively,
+; depending on which components are active for this particular kernel instance.
+; They will receive the _pXYZW prefix during name mangling.
+
+struc SwsOpExec
+    .in0 resq 1
+    .in1 resq 1
+    .in2 resq 1
+    .in3 resq 1
+    .out0 resq 1
+    .out1 resq 1
+    .out2 resq 1
+    .out3 resq 1
+    .in_stride0 resq 1
+    .in_stride1 resq 1
+    .in_stride2 resq 1
+    .in_stride3 resq 1
+    .out_stride0 resq 1
+    .out_stride1 resq 1
+    .out_stride2 resq 1
+    .out_stride3 resq 1
+    .in_bump0 resq 1
+    .in_bump1 resq 1
+    .in_bump2 resq 1
+    .in_bump3 resq 1
+    .out_bump0 resq 1
+    .out_bump1 resq 1
+    .out_bump2 resq 1
+    .out_bump3 resq 1
+    .width resd 1
+    .height resd 1
+    .slice_y resd 1
+    .slice_h resd 1
+    .block_size_in resd 1
+    .block_size_out resd 1
+    .in_sub_y4 resb 4
+    .out_sub_y4 resb 4
+    .in_sub_x4 resb 4
+    .out_sub_x4 resb 4
+    .in_hwframe_ref resq 1
+    .out_hwframe_ref resq 1
+endstruc
+
+struc SwsOpImpl
+    .cont resb 16
+    .priv resb 16
+    .next resb 0
+endstruc
+
+;---------------------------------------------------------
+; Common macros for declaring operations
+
+; Declare an operation kernel with the correct name mangling.
+%macro op 1 ; name
+    %ifdef X
+        %define ADD_PAT(name) p %+ X %+ Y %+ Z %+ W %+ _ %+ name
+    %else
+        %define ADD_PAT(name) name
+    %endif
+
+    %ifdef V2
+        %if V2
+            %define ADD_MUL(name) name %+ _m2
+        %else
+            %define ADD_MUL(name) name %+ _m1
+        %endif
+    %else
+        %define ADD_MUL(name) name
+    %endif
+
+    cglobal ADD_PAT(ADD_MUL(%1)), 0, 0, 0 ; already allocated by entry point
+
+    %undef ADD_PAT
+    %undef ADD_MUL
+%endmacro
+
+; Declare an operation kernel twice, once with V2=0 and once with V2=1
+%macro decl_v2 2+ ; v2, func
+    %xdefine V2 %1
+    %2
+    %undef V2
+%endmacro
+
+; Declare an operation kernel specialized to a given subset of active components
+%macro decl_pattern 5+ ; X, Y, Z, W, func
+    %xdefine X %1
+    %xdefine Y %2
+    %xdefine Z %3
+    %xdefine W %4
+    %5
+    %undef X
+    %undef Y
+    %undef Z
+    %undef W
+%endmacro
+
+; Declare an operation kernel specialized to each common component pattern
+%macro decl_common_patterns 1+ ; func
+    decl_pattern 1, 0, 0, 0, %1 ; y
+    decl_pattern 1, 0, 0, 1, %1 ; ya
+    decl_pattern 1, 1, 1, 0, %1 ; yuv
+    decl_pattern 1, 1, 1, 1, %1 ; yuva
+%endmacro
+
+;---------------------------------------------------------
+; Common names for the internal calling convention
+%define mx      m0
+%define my      m1
+%define mz      m2
+%define mw      m3
+
+%define xmx     xm0
+%define xmy     xm1
+%define xmz     xm2
+%define xmw     xm3
+
+%define ymx     ym0
+%define ymy     ym1
+%define ymz     ym2
+%define ymw     ym3
+
+%define mx2     m4
+%define my2     m5
+%define mz2     m6
+%define mw2     m7
+
+%define xmx2    xm4
+%define xmy2    xm5
+%define xmz2    xm6
+%define xmw2    xm7
+
+%define ymx2    ym4
+%define ymy2    ym5
+%define ymz2    ym6
+%define ymw2    ym7
+
+; Reserved in this order by the signature of SwsOpFunc
+%define execq   r0q
+%define implq   r1q
+%define bxd     r2d
+%define yd      r3d
+
+; Extra registers for free use by kernels, not saved between ops
+%define tmp0q   r4q
+%define tmp1q   r5q
+
+%define tmp0d   r4d
+%define tmp1d   r5d
+
+%define tmp0w   r4w
+%define tmp1w   r5w
+
+; Registers for plane pointers; put at the end (and in ascending plane order)
+; so that we can avoid reserving them when not necessary
+%define out0q   r6q
+%define  in0q   r7q
+%define out1q   r8q
+%define  in1q   r9q
+%define out2q   r10q
+%define  in2q   r11q
+%define out3q   r12q
+%define  in3q   r13q
+
+;---------------------------------------------------------
+; Common macros for linking together different kernels
+
+; Load the next operation kernel's address to a register
+%macro LOAD_CONT 1 ; reg
+    mov %1, [implq + SwsOpImpl.cont]
+%endmacro
+
+; Tail call into the next operation kernel, given that kernel's address
+%macro CONTINUE 1 ; reg
+    add implq, SwsOpImpl.next
+    jmp %1
+    annotate_function_size
+%endmacro
+
+; Convenience macro to load and continue to the next kernel in one step
+%macro CONTINUE 0
+    LOAD_CONT tmp0q
+    CONTINUE tmp0q
+%endmacro
+
+; Final macro to end the operation chain, used by WRITE kernels to jump back
+; to the process function return point. Very similar to CONTINUE, but skips
+; incrementing the implq pointer, and also clears AVX registers to avoid
+; phantom dependencies between loop iterations.
+%macro FINISH 1 ; reg
+    %if vzeroupper_required
+        ; we may jump back into an SSE read, so always zero upper regs here
+        vzeroupper
+    %endif
+    jmp %1
+    annotate_function_size
+%endmacro
+
+; Helper for inline conditionals; used to conditionally include single lines
+%macro IF 2+ ; cond, body
+    %if %1
+        %2
+    %endif
+%endmacro
+
+; Alternate name; for nested usage (to work around NASM limitations)
+%macro IF1 2+
+    %if %1
+        %2
+    %endif
+%endmacro
diff --git a/libs/ffmpeg/libswscale/x86/ops_float.asm b/libs/ffmpeg/libswscale/x86/ops_float.asm
new file mode 100644
index 000000000000..f794b93a8ee2
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/ops_float.asm
@@ -0,0 +1,374 @@
+;******************************************************************************
+;* 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 "libswscale/x86/ops_common.asm"
+%if ARCH_X86_64
+
+SECTION .text
+
+;---------------------------------------------------------
+; Pixel type conversions
+
+%macro conv8to32f 0
+op convert_U8_F32
+        LOAD_CONT tmp0q
+IF X,   vpsrldq xmx2, xmx, 8
+IF Y,   vpsrldq xmy2, xmy, 8
+IF Z,   vpsrldq xmz2, xmz, 8
+IF W,   vpsrldq xmw2, xmw, 8
+IF X,   pmovzxbd mx, xmx
+IF Y,   pmovzxbd my, xmy
+IF Z,   pmovzxbd mz, xmz
+IF W,   pmovzxbd mw, xmw
+IF X,   pmovzxbd mx2, xmx2
+IF Y,   pmovzxbd my2, xmy2
+IF Z,   pmovzxbd mz2, xmz2
+IF W,   pmovzxbd mw2, xmw2
+IF X,   vcvtdq2ps mx, mx
+IF Y,   vcvtdq2ps my, my
+IF Z,   vcvtdq2ps mz, mz
+IF W,   vcvtdq2ps mw, mw
+IF X,   vcvtdq2ps mx2, mx2
+IF Y,   vcvtdq2ps my2, my2
+IF Z,   vcvtdq2ps mz2, mz2
+IF W,   vcvtdq2ps mw2, mw2
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv16to32f 0
+op convert_U16_F32
+        LOAD_CONT tmp0q
+IF X,   vextracti128 xmx2, mx, 1
+IF Y,   vextracti128 xmy2, my, 1
+IF Z,   vextracti128 xmz2, mz, 1
+IF W,   vextracti128 xmw2, mw, 1
+IF X,   pmovzxwd mx, xmx
+IF Y,   pmovzxwd my, xmy
+IF Z,   pmovzxwd mz, xmz
+IF W,   pmovzxwd mw, xmw
+IF X,   pmovzxwd mx2, xmx2
+IF Y,   pmovzxwd my2, xmy2
+IF Z,   pmovzxwd mz2, xmz2
+IF W,   pmovzxwd mw2, xmw2
+IF X,   vcvtdq2ps mx, mx
+IF Y,   vcvtdq2ps my, my
+IF Z,   vcvtdq2ps mz, mz
+IF W,   vcvtdq2ps mw, mw
+IF X,   vcvtdq2ps mx2, mx2
+IF Y,   vcvtdq2ps my2, my2
+IF Z,   vcvtdq2ps mz2, mz2
+IF W,   vcvtdq2ps mw2, mw2
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv32fto8 0
+op convert_F32_U8
+        LOAD_CONT tmp0q
+IF X,   cvttps2dq mx, mx
+IF Y,   cvttps2dq my, my
+IF Z,   cvttps2dq mz, mz
+IF W,   cvttps2dq mw, mw
+IF X,   cvttps2dq mx2, mx2
+IF Y,   cvttps2dq my2, my2
+IF Z,   cvttps2dq mz2, mz2
+IF W,   cvttps2dq mw2, mw2
+IF X,   packusdw mx, mx2
+IF Y,   packusdw my, my2
+IF Z,   packusdw mz, mz2
+IF W,   packusdw mw, mw2
+IF X,   vextracti128 xmx2, mx, 1
+IF Y,   vextracti128 xmy2, my, 1
+IF Z,   vextracti128 xmz2, mz, 1
+IF W,   vextracti128 xmw2, mw, 1
+        vzeroupper
+IF X,   packuswb xmx, xmx2
+IF Y,   packuswb xmy, xmy2
+IF Z,   packuswb xmz, xmz2
+IF W,   packuswb xmw, xmw2
+IF X,   vpshufd xmx, xmx, q3120
+IF Y,   vpshufd xmy, xmy, q3120
+IF Z,   vpshufd xmz, xmz, q3120
+IF W,   vpshufd xmw, xmw, q3120
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv32fto16 0
+op convert_F32_U16
+        LOAD_CONT tmp0q
+IF X,   cvttps2dq mx, mx
+IF Y,   cvttps2dq my, my
+IF Z,   cvttps2dq mz, mz
+IF W,   cvttps2dq mw, mw
+IF X,   cvttps2dq mx2, mx2
+IF Y,   cvttps2dq my2, my2
+IF Z,   cvttps2dq mz2, mz2
+IF W,   cvttps2dq mw2, mw2
+IF X,   packusdw mx, mx2
+IF Y,   packusdw my, my2
+IF Z,   packusdw mz, mz2
+IF W,   packusdw mw, mw2
+IF X,   vpermq mx, mx, q3120
+IF Y,   vpermq my, my, q3120
+IF Z,   vpermq mz, mz, q3120
+IF W,   vpermq mw, mw, q3120
+        CONTINUE tmp0q
+%endmacro
+
+%macro min_max 0
+op min
+IF X,   vbroadcastss m8,  [implq + SwsOpImpl.priv + 0]
+IF Y,   vbroadcastss m9,  [implq + SwsOpImpl.priv + 4]
+IF Z,   vbroadcastss m10, [implq + SwsOpImpl.priv + 8]
+IF W,   vbroadcastss m11, [implq + SwsOpImpl.priv + 12]
+        LOAD_CONT tmp0q
+IF X,   minps mx, mx, m8
+IF Y,   minps my, my, m9
+IF Z,   minps mz, mz, m10
+IF W,   minps mw, mw, m11
+IF X,   minps mx2, m8
+IF Y,   minps my2, m9
+IF Z,   minps mz2, m10
+IF W,   minps mw2, m11
+        CONTINUE tmp0q
+
+op max
+IF X,   vbroadcastss m8,  [implq + SwsOpImpl.priv + 0]
+IF Y,   vbroadcastss m9,  [implq + SwsOpImpl.priv + 4]
+IF Z,   vbroadcastss m10, [implq + SwsOpImpl.priv + 8]
+IF W,   vbroadcastss m11, [implq + SwsOpImpl.priv + 12]
+        LOAD_CONT tmp0q
+IF X,   maxps mx, m8
+IF Y,   maxps my, m9
+IF Z,   maxps mz, m10
+IF W,   maxps mw, m11
+IF X,   maxps mx2, m8
+IF Y,   maxps my2, m9
+IF Z,   maxps mz2, m10
+IF W,   maxps mw2, m11
+        CONTINUE tmp0q
+%endmacro
+
+%macro scale 0
+op scale
+        vbroadcastss m8, [implq + SwsOpImpl.priv]
+        LOAD_CONT tmp0q
+IF X,   mulps mx, m8
+IF Y,   mulps my, m8
+IF Z,   mulps mz, m8
+IF W,   mulps mw, m8
+IF X,   mulps mx2, m8
+IF Y,   mulps my2, m8
+IF Z,   mulps mz2, m8
+IF W,   mulps mw2, m8
+        CONTINUE tmp0q
+%endmacro
+
+%macro dither0 0
+op dither0
+        ; constant offset for all channels
+        vbroadcastss m8, [implq + SwsOpImpl.priv]
+        LOAD_CONT tmp0q
+IF X,   addps mx, m8
+IF Y,   addps my, m8
+IF Z,   addps mz, m8
+IF W,   addps mw, m8
+IF X,   addps mx2, m8
+IF Y,   addps my2, m8
+IF Z,   addps mz2, m8
+IF W,   addps mw2, m8
+        CONTINUE tmp0q
+%endmacro
+
+%macro dither_row 5 ; size_log2, comp_idx, matrix, out, out2
+        mov tmp0w, [implq + SwsOpImpl.priv + (4 + %2) * 2] ; priv.u16[4 + i]
+        ; test is tmp0w < 0
+        test tmp0w, tmp0w
+        js .skip%2
+%if %1 == 1
+        vbroadcastsd m8, [%3 + tmp0q]
+        addps %4, m8
+        addps %5, m8
+%elif %1 == 2
+        VBROADCASTI128 m8, [%3 + tmp0q]
+        addps %4, m8
+        addps %5, m8
+%else
+        addps %4, [%3 + tmp0q]
+        addps %5, [%3 + tmp0q + mmsize * ((4 << %1) > mmsize)]
+%endif
+.skip%2:
+%endmacro
+
+%macro dither 1 ; size_log2
+op dither%1
+        ; dither matrix is stored indirectly at the private data address
+        mov tmp1q, [implq + SwsOpImpl.priv]
+        ; add y offset. note that for 2x2, we would only need to look at the
+        ; sign of `y`, but this special case is ignored for simplicity reasons
+        ; (and because the current upstream format code never generates matrices
+        ; that small)
+        mov tmp0d, yd
+        and tmp0d, (1 << %1) - 1
+        shl tmp0d, %1 + 2 ; * sizeof(float)
+        add tmp1q, tmp0q
+    %if (4 << %1) > 2 * mmsize
+        ; need to add in x offset
+        mov tmp0d, bxd
+        shl tmp0d, 6 ; sizeof(float[16])
+        and tmp0d, (4 << %1) - 1
+        add tmp1q, tmp0q
+    %endif
+        dither_row %1, 0, tmp1q, mx, mx2
+        dither_row %1, 1, tmp1q, my, my2
+        dither_row %1, 2, tmp1q, mz, mz2
+        dither_row %1, 3, tmp1q, mw, mw2
+        CONTINUE
+%endmacro
+
+%macro dither_fns 0
+        decl_common_patterns dither0
+        dither 1
+        dither 2
+        dither 3
+        dither 4
+        dither 5
+        dither 6
+        dither 7
+        dither 8
+%endmacro
+
+%xdefine MASK(I, J)  (1 << (5 * (I) + (J)))
+%xdefine MASK_OFF(I) MASK(I, 4)
+%xdefine MASK_ROW(I) (0x1F << (5 * (I)))
+%xdefine MASK_COL(J) (0x8421 << J)
+%xdefine MASK_ALL    (1 << 20) - 1
+%xdefine MASK_LUMA   MASK(0, 0) | MASK_OFF(0)
+%xdefine MASK_ALPHA  MASK(3, 3) | MASK_OFF(3)
+%xdefine MASK_DIAG3  MASK(0, 0) | MASK(1, 1) | MASK(2, 2)
+%xdefine MASK_OFF3   MASK_OFF(0) | MASK_OFF(1) | MASK_OFF(2)
+%xdefine MASK_MAT3   MASK(0, 0) | MASK(0, 1) | MASK(0, 2) |\
+                     MASK(1, 0) | MASK(1, 1) | MASK(1, 2) |\
+                     MASK(2, 0) | MASK(2, 1) | MASK(2, 2)
+%xdefine MASK_DIAG4  MASK_DIAG3 | MASK(3, 3)
+%xdefine MASK_OFF4   MASK_OFF3 | MASK_OFF(3)
+%xdefine MASK_MAT4   MASK_ALL & ~MASK_OFF4
+
+%macro linear_row 7 ; res, x, y, z, w, row, mask
+%define COL(J) ((%7) & MASK(%6, J)) ; true if mask contains component J
+%define NOP(J) (J == %6 && !COL(J)) ; true if J is untouched input component
+
+    ; load weights
+    IF COL(0),  vbroadcastss m12,  [tmp0q + %6 * 20 + 0]
+    IF COL(1),  vbroadcastss m13,  [tmp0q + %6 * 20 + 4]
+    IF COL(2),  vbroadcastss m14,  [tmp0q + %6 * 20 + 8]
+    IF COL(3),  vbroadcastss m15,  [tmp0q + %6 * 20 + 12]
+
+    ; initialize result vector as appropriate
+    %if COL(4) ; offset
+        vbroadcastss %1, [tmp0q + %6 * 20 + 16]
+    %elif NOP(0)
+        ; directly reuse first component vector if possible
+        mova %1, %2
+    %else
+        xorps %1, %1
+    %endif
+
+    IF COL(0),  mulps m12, %2
+    IF COL(1),  mulps m13, %3
+    IF COL(2),  mulps m14, %4
+    IF COL(3),  mulps m15, %5
+    IF COL(0),  addps %1, m12
+    IF NOP(0) && COL(4), addps %1, %3 ; first vector was not reused
+    IF COL(1),  addps %1, m13
+    IF NOP(1),  addps %1, %3
+    IF COL(2),  addps %1, m14
+    IF NOP(2),  addps %1, %4
+    IF COL(3),  addps %1, m15
+    IF NOP(3),  addps %1, %5
+%endmacro
+
+%macro linear_inner 5 ; x, y, z, w, mask
+    %define ROW(I) ((%5) & MASK_ROW(I))
+    IF1 ROW(0), linear_row m8,  %1, %2, %3, %4, 0, %5
+    IF1 ROW(1), linear_row m9,  %1, %2, %3, %4, 1, %5
+    IF1 ROW(2), linear_row m10, %1, %2, %3, %4, 2, %5
+    IF1 ROW(3), linear_row m11, %1, %2, %3, %4, 3, %5
+    IF ROW(0),  mova %1, m8
+    IF ROW(1),  mova %2, m9
+    IF ROW(2),  mova %3, m10
+    IF ROW(3),  mova %4, m11
+%endmacro
+
+%macro linear_mask 2 ; name, mask
+op %1
+        mov tmp0q, [implq + SwsOpImpl.priv] ; address of matrix
+        linear_inner mx,  my,  mz,  mw,  %2
+        linear_inner mx2, my2, mz2, mw2, %2
+        CONTINUE
+%endmacro
+
+; specialized functions for very simple cases
+%macro linear_dot3 0
+op dot3
+        mov tmp0q, [implq + SwsOpImpl.priv]
+        vbroadcastss m12,  [tmp0q + 0]
+        vbroadcastss m13,  [tmp0q + 4]
+        vbroadcastss m14,  [tmp0q + 8]
+        LOAD_CONT tmp0q
+        mulps mx, m12
+        mulps m8, my, m13
+        mulps m9, mz, m14
+        addps mx, m8
+        addps mx, m9
+        mulps mx2, m12
+        mulps m10, my2, m13
+        mulps m11, mz2, m14
+        addps mx2, m10
+        addps mx2, m11
+        CONTINUE tmp0q
+%endmacro
+
+%macro linear_fns 0
+        linear_dot3
+        linear_mask luma,       MASK_LUMA
+        linear_mask alpha,      MASK_ALPHA
+        linear_mask lumalpha,   MASK_LUMA | MASK_ALPHA
+        linear_mask row0,       MASK_ROW(0)
+        linear_mask row0a,      MASK_ROW(0) | MASK_ALPHA
+        linear_mask diag3,      MASK_DIAG3
+        linear_mask diag4,      MASK_DIAG4
+        linear_mask diagoff3,   MASK_DIAG3 | MASK_OFF3
+        linear_mask matrix3,    MASK_MAT3
+        linear_mask affine3,    MASK_MAT3 | MASK_OFF3
+        linear_mask affine3a,   MASK_MAT3 | MASK_OFF3 | MASK_ALPHA
+        linear_mask matrix4,    MASK_MAT4
+        linear_mask affine4,    MASK_MAT4 | MASK_OFF4
+%endmacro
+
+INIT_YMM avx2
+decl_common_patterns conv8to32f
+decl_common_patterns conv16to32f
+decl_common_patterns conv32fto8
+decl_common_patterns conv32fto16
+decl_common_patterns min_max
+decl_common_patterns scale
+dither_fns
+linear_fns
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/ops_int.asm b/libs/ffmpeg/libswscale/x86/ops_int.asm
new file mode 100644
index 000000000000..b4ca9ce2eff4
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/ops_int.asm
@@ -0,0 +1,1075 @@
+;******************************************************************************
+;* 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 "libswscale/x86/ops_common.asm"
+%if ARCH_X86_64
+
+SECTION_RODATA
+
+align 16
+expand16_shuf:  db   0,  0,  2,  2,  4,  4,  6,  6,  8,  8, 10, 10, 12, 12, 14, 14
+expand32_shuf:  db   0,  0,  0,  0,  4,  4,  4,  4,  8,  8,  8,  8, 12, 12, 12, 12
+
+read8_unpack2:  db   0,  2,  4,  6,  8, 10, 12, 14,  1,  3,  5,  7,  9, 11, 13, 15
+read8_unpack3:  db   0,  3,  6,  9,  1,  4,  7, 10,  2,  5,  8, 11, -1, -1, -1, -1
+read8_unpack4:  db   0,  4,  8, 12,  1,  5,  9, 13,  2,  6, 10, 14,  3,  7, 11, 15
+read16_unpack2: db   0,  1,  4,  5,  8,  9, 12, 13,  2,  3,  6,  7, 10, 11, 14, 15
+read16_unpack3: db   0,  1,  6,  7,  2,  3,  8,  9,  4,  5, 10, 11, -1, -1, -1, -1
+read16_unpack4: db   0,  1,  8,  9,  2,  3, 10, 11,  4,  5, 12, 13,  6,  7, 14, 15
+write8_pack2:   db   0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+write8_pack3:   db   0,  4,  8,  1,  5,  9,  2,  6, 10,  3,  7, 11, -1, -1, -1, -1
+write16_pack3:  db   0,  1,  4,  5,  8,  9,  2,  3,  6,  7, 10, 11, -1, -1, -1, -1
+
+%define write8_pack4  read8_unpack4
+%define write16_pack4 read16_unpack2
+%define write16_pack2 read16_unpack4
+
+align 32
+bits_shuf:      db   0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1,  1,  1,  1, \
+                     2,  2,  2,  2,  2,  2,  2,  2,  3,  3,  3,  3,  3,  3,  3,  3
+bits_mask:      db 128, 64, 32, 16,  8,  4,  2,  1,128, 64, 32, 16,  8,  4,  2,  1
+bits_reverse:   db   7,  6,  5,  4,  3,  2,  1,  0, 15, 14, 13, 12, 11, 10,  9,  8,
+
+align 32
+mask1: times 32 db 0x01
+mask2: times 32 db 0x03
+mask3: times 32 db 0x07
+mask4: times 32 db 0x0F
+
+const1b equ mask1
+const1w: times 16 dw 0x01
+
+SECTION .text
+
+;---------------------------------------------------------
+; Global entry point. See `ops_common.asm` for info.
+
+%macro process_fn 1 ; number of planes
+cglobal sws_process%1_x86, 6, 6 + 2 * %1, 16
+            ; Args:
+            ;   execq, implq, bxd, yd as defined in ops_common.int
+            ;   bx_end and y_end are initially in tmp0d / tmp1d
+            ;   (see SwsOpFunc signature)
+            ;
+            ; Stack layout:
+            ;   [rsp +  0] = [qword] impl->cont (address of first kernel)
+            ;   [rsp +  8] = [qword] &impl[1]   (restore implq after chain)
+            ;   [rsp + 16] = [dword] bx start   (restore after line finish)
+            ;   [rsp + 20] = [dword] bx end     (loop counter limit)
+            ;   [rsp + 24] = [dword] y end      (loop counter limit)
+            sub rsp, 32
+            mov [rsp + 16], bxd
+            mov [rsp + 20], tmp0d ; bx_end
+            mov [rsp + 24], tmp1d ; y_end
+            mov tmp0q, [implq + SwsOpImpl.cont]
+            add implq, SwsOpImpl.next
+            mov [rsp +  0], tmp0q
+            mov [rsp +  8], implq
+
+            ; load plane pointers
+            mov in0q,  [execq + SwsOpExec.in0]
+IF %1 > 1,  mov in1q,  [execq + SwsOpExec.in1]
+IF %1 > 2,  mov in2q,  [execq + SwsOpExec.in2]
+IF %1 > 3,  mov in3q,  [execq + SwsOpExec.in3]
+            mov out0q, [execq + SwsOpExec.out0]
+IF %1 > 1,  mov out1q, [execq + SwsOpExec.out1]
+IF %1 > 2,  mov out2q, [execq + SwsOpExec.out2]
+IF %1 > 3,  mov out3q, [execq + SwsOpExec.out3]
+            jmp [rsp] ; call into op chain
+
+; Declare a separate global label for the return point, so that we can append
+; it to the list of op function pointers from the C code, effectively ensuring
+; that we end up here again after the op chain finishes processing a line.
+; (See also: cglobal_label in x86inc.asm)
+%if FORMAT_ELF
+    global current_function %+ _return:function hidden
+%elif FORMAT_MACHO && HAVE_PRIVATE_EXTERN
+    global current_function %+ _return:private_extern
+%else
+    global current_function %+ _return
+%endif
+align function_align
+current_function %+ _return:
+
+            ; op chain always returns back here
+            mov implq, [rsp + 8]
+            inc bxd
+            cmp bxd, [rsp + 20]
+            jne .continue
+            ; end of line
+            inc yd
+            cmp yd, [rsp + 24]
+            je .end
+            ; bump addresses to point to start of next line
+            add in0q,  [execq + SwsOpExec.in_bump0]
+IF %1 > 1,  add in1q,  [execq + SwsOpExec.in_bump1]
+IF %1 > 2,  add in2q,  [execq + SwsOpExec.in_bump2]
+IF %1 > 3,  add in3q,  [execq + SwsOpExec.in_bump3]
+            add out0q, [execq + SwsOpExec.out_bump0]
+IF %1 > 1,  add out1q, [execq + SwsOpExec.out_bump1]
+IF %1 > 2,  add out2q, [execq + SwsOpExec.out_bump2]
+IF %1 > 3,  add out3q, [execq + SwsOpExec.out_bump3]
+            mov bxd, [rsp + 16]
+.continue:
+            jmp [rsp]
+.end:
+            add rsp, 32
+            RET
+%endmacro
+
+process_fn 1
+process_fn 2
+process_fn 3
+process_fn 4
+
+;---------------------------------------------------------
+; Packed shuffle fast-path
+
+; This is a special entry point for handling a subset of operation chains
+; that can be reduced down to a single `pshufb` shuffle mask. For more details
+; about when this works, refer to the documentation of `ff_sws_solve_shuffle`.
+;
+; We specialize this function for every possible combination of pixel strides.
+; For example, gray -> gray16 is classified as an "8, 16" operation because it
+; takes 8 bytes and expands them out to 16 bytes in each application of the
+; 128-bit shuffle mask.
+;
+; Since pshufb can't shuffle across lanes, we only instantiate SSE4 versions for
+; all shuffles that are not a clean multiple of 128 bits (e.g. rgb24 -> rgb0).
+; For the clean multiples (e.g. rgba -> argb), we also define AVX2 and AVX512
+; versions that can handle a larger number of bytes at once.
+
+%macro packed_shuffle 2 ; size_in, size_out
+cglobal packed_shuffle%1_%2, 6, 10, 2, \
+    exec, shuffle, bx, y, bxend, yend, src, dst, src_stride, dst_stride
+            mov srcq, [execq + SwsOpExec.in0]
+            mov dstq, [execq + SwsOpExec.out0]
+            mov src_strideq, [execq + SwsOpExec.in_stride0]
+            mov dst_strideq, [execq + SwsOpExec.out_stride0]
+            VBROADCASTI128 m1, [shuffleq]
+            sub bxendd, bxd
+            sub yendd, yd
+            ; reuse now-unneeded regs
+    %define srcidxq execq
+            imul srcidxq, bxendq, -%1
+%if %1 = %2
+    %define dstidxq srcidxq
+%else
+    %define dstidxq shuffleq ; no longer needed reg
+            imul dstidxq, bxendq, -%2
+%endif
+            sub srcq, srcidxq
+            sub dstq, dstidxq
+.loop:
+    %if %1 <= 4
+            movd m0, [srcq + srcidxq]
+    %elif %1 <= 8
+            movq m0, [srcq + srcidxq]
+    %else
+            movu m0, [srcq + srcidxq]
+    %endif
+            pshufb m0, m1
+            movu [dstq + dstidxq], m0
+            add srcidxq, %1
+IF %1 != %2,add dstidxq, %2
+            jnz .loop
+            add srcq, src_strideq
+            add dstq, dst_strideq
+            imul srcidxq, bxendq, -%1
+IF %1 != %2,imul dstidxq, bxendq, -%2
+            dec yendd
+            jnz .loop
+            RET
+%endmacro
+
+INIT_XMM sse4
+packed_shuffle  5, 15 ;  8 -> 24
+packed_shuffle  4, 16 ;  8 -> 32, 16 -> 64
+packed_shuffle  2, 12 ;  8 -> 48
+packed_shuffle 16,  8 ; 16 -> 8
+packed_shuffle 10, 15 ; 16 -> 24
+packed_shuffle  8, 16 ; 16 -> 32, 32 -> 64
+packed_shuffle  4, 12 ; 16 -> 48
+packed_shuffle 15, 15 ; 24 -> 24
+packed_shuffle 12, 16 ; 24 -> 32
+packed_shuffle  6, 12 ; 24 -> 48
+packed_shuffle 16, 12 ; 32 -> 24, 64 -> 48
+packed_shuffle 16, 16 ; 32 -> 32, 64 -> 64
+packed_shuffle  8, 12 ; 32 -> 48
+packed_shuffle 12, 12 ; 48 -> 48
+
+INIT_YMM avx2
+packed_shuffle 32, 32
+
+INIT_ZMM avx512
+packed_shuffle 64, 64
+
+;---------------------------------------------------------
+; Planar reads / writes
+
+%macro read_planar 1 ; elems
+op read_planar%1
+            movu mx, [in0q]
+IF %1 > 1,  movu my, [in1q]
+IF %1 > 2,  movu mz, [in2q]
+IF %1 > 3,  movu mw, [in3q]
+%if V2
+            movu mx2, [in0q + mmsize]
+IF %1 > 1,  movu my2, [in1q + mmsize]
+IF %1 > 2,  movu mz2, [in2q + mmsize]
+IF %1 > 3,  movu mw2, [in3q + mmsize]
+%endif
+            LOAD_CONT tmp0q
+            add in0q, mmsize * (1 + V2)
+IF %1 > 1,  add in1q, mmsize * (1 + V2)
+IF %1 > 2,  add in2q, mmsize * (1 + V2)
+IF %1 > 3,  add in3q, mmsize * (1 + V2)
+            CONTINUE tmp0q
+%endmacro
+
+%macro write_planar 1 ; elems
+op write_planar%1
+            LOAD_CONT tmp0q
+            movu [out0q], mx
+IF %1 > 1,  movu [out1q], my
+IF %1 > 2,  movu [out2q], mz
+IF %1 > 3,  movu [out3q], mw
+%if V2
+            movu [out0q + mmsize], mx2
+IF %1 > 1,  movu [out1q + mmsize], my2
+IF %1 > 2,  movu [out2q + mmsize], mz2
+IF %1 > 3,  movu [out3q + mmsize], mw2
+%endif
+            add out0q, mmsize * (1 + V2)
+IF %1 > 1,  add out1q, mmsize * (1 + V2)
+IF %1 > 2,  add out2q, mmsize * (1 + V2)
+IF %1 > 3,  add out3q, mmsize * (1 + V2)
+            FINISH tmp0q
+%endmacro
+
+%macro read_packed2 1 ; depth
+op read%1_packed2
+            movu m8,  [in0q + 0*mmsize]
+            movu m9,  [in0q + 1*mmsize]
+    IF V2,  movu m10, [in0q + 2*mmsize]
+    IF V2,  movu m11, [in0q + 3*mmsize]
+IF %1 < 32, VBROADCASTI128 m12, [read%1_unpack2]
+            LOAD_CONT tmp0q
+            add in0q, mmsize * (2 + V2 * 2)
+%if %1 == 32
+            shufps m8, m8, q3120
+            shufps m9, m9, q3120
+    IF V2,  shufps m10, m10, q3120
+    IF V2,  shufps m11, m11, q3120
+%else
+            pshufb m8, m12              ; { X0 Y0 | X1 Y1 }
+            pshufb m9, m12              ; { X2 Y2 | X3 Y3 }
+    IF V2,  pshufb m10, m12
+    IF V2,  pshufb m11, m12
+%endif
+            unpcklpd mx, m8, m9         ; { X0 X2 | X1 X3 }
+            unpckhpd my, m8, m9         ; { Y0 Y2 | Y1 Y3 }
+    IF V2,  unpcklpd mx2, m10, m11
+    IF V2,  unpckhpd my2, m10, m11
+%if cpuflag(avx2)
+            vpermq mx, mx, q3120       ; { X0 X1 | X2 X3 }
+            vpermq my, my, q3120       ; { Y0 Y1 | Y2 Y3 }
+    IF V2,  vpermq mx2, mx2, q3120
+    IF V2,  vpermq my2, my2, q3120
+%endif
+            CONTINUE tmp0q
+%endmacro
+
+%macro write_packed2 1 ; depth
+op write%1_packed2
+IF %1 < 32, VBROADCASTI128 m12, [write%1_pack2]
+            LOAD_CONT tmp0q
+%if cpuflag(avx2)
+            vpermq mx, mx, q3120       ; { X0 X2 | X1 X3 }
+            vpermq my, my, q3120       ; { Y0 Y2 | Y1 Y3 }
+    IF V2,  vpermq mx2, mx2, q3120
+    IF V2,  vpermq my2, my2, q3120
+%endif
+            unpcklpd m8, mx, my        ; { X0 Y0 | X1 Y1 }
+            unpckhpd m9, mx, my        ; { X2 Y2 | X3 Y3 }
+    IF V2,  unpcklpd m10, mx2, my2
+    IF V2,  unpckhpd m11, mx2, my2
+%if %1 == 32
+            shufps m8, m8, q3120
+            shufps m9, m9, q3120
+    IF V2,  shufps m10, m10, q3120
+    IF V2,  shufps m11, m11, q3120
+%else
+            pshufb m8, m12
+            pshufb m9, m12
+    IF V2,  pshufb m10, m12
+    IF V2,  pshufb m11, m12
+%endif
+            movu [out0q + 0*mmsize], m8
+            movu [out0q + 1*mmsize], m9
+IF V2,      movu [out0q + 2*mmsize], m10
+IF V2,      movu [out0q + 3*mmsize], m11
+            add out0q, mmsize * (2 + V2 * 2)
+            FINISH tmp0q
+%endmacro
+
+; helper macro reused for both 3 and 4 component packed reads
+%macro read_packed_inner 7 ; x, y, z, w, addr, num, depth
+            movu xm8,  [%5 + 0  * %6]
+            movu xm9,  [%5 + 4  * %6]
+            movu xm10, [%5 + 8  * %6]
+            movu xm11, [%5 + 12 * %6]
+    %if cpuflag(avx2)
+            vinserti128 m8,  m8,  [%5 + 16 * %6], 1
+            vinserti128 m9,  m9,  [%5 + 20 * %6], 1
+            vinserti128 m10, m10, [%5 + 24 * %6], 1
+            vinserti128 m11, m11, [%5 + 28 * %6], 1
+    %endif
+    %if %7 == 32
+            mova %1, m8
+            mova %2, m9
+            mova %3, m10
+            mova %4, m11
+    %else
+            pshufb %1, m8,  m12         ; { X0 Y0 Z0 W0 | X4 Y4 Z4 W4 }
+            pshufb %2, m9,  m12         ; { X1 Y1 Z1 W1 | X5 Y5 Z5 W5 }
+            pshufb %3, m10, m12         ; { X2 Y2 Z2 W2 | X6 Y6 Z6 W6 }
+            pshufb %4, m11, m12         ; { X3 Y3 Z3 W3 | X7 Y7 Z7 W7 }
+    %endif
+            punpckldq m8,  %1, %2       ; { X0 X1 Y0 Y1 | X4 X5 Y4 Y5 }
+            punpckldq m9,  %3, %4       ; { X2 X3 Y2 Y3 | X6 X7 Y6 Y7 }
+            punpckhdq m10, %1, %2       ; { Z0 Z1 W0 W1 | Z4 Z5 W4 W5 }
+            punpckhdq m11, %3, %4       ; { Z2 Z3 W2 W3 | Z6 Z7 W6 W7 }
+            punpcklqdq %1, m8, m9       ; { X0 X1 X2 X3 | X4 X5 X6 X7 }
+            punpckhqdq %2, m8, m9       ; { Y0 Y1 Y2 Y3 | Y4 Y5 Y6 Y7 }
+            punpcklqdq %3, m10, m11     ; { Z0 Z1 Z2 Z3 | Z4 Z5 Z6 Z7 }
+IF %6 > 3,  punpckhqdq %4, m10, m11     ; { W0 W1 W2 W3 | W4 W5 W6 W7 }
+%endmacro
+
+%macro read_packed 2 ; num, depth
+op read%2_packed%1
+IF %2 < 32, VBROADCASTI128 m12, [read%2_unpack%1]
+            LOAD_CONT tmp0q
+            read_packed_inner mx, my, mz, mw, in0q, %1, %2
+IF1 V2,     read_packed_inner mx2, my2, mz2, mw2, in0q + %1 * mmsize, %1, %2
+            add in0q, %1 * mmsize * (1 + V2)
+            CONTINUE tmp0q
+%endmacro
+
+%macro write_packed_inner 7 ; x, y, z, w, addr, num, depth
+        punpckldq m8,  %1, %2       ; { X0 Y0 X1 Y1 | X4 Y4 X5 Y5 }
+        punpckldq m9,  %3, %4       ; { Z0 W0 Z1 W1 | Z4 W4 Z5 W5 }
+        punpckhdq m10, %1, %2       ; { X2 Y2 X3 Y3 | X6 Y6 X7 Y7 }
+        punpckhdq m11, %3, %4       ; { Z2 W2 Z3 W3 | Z6 W6 Z7 W7 }
+        punpcklqdq %1, m8, m9       ; { X0 Y0 Z0 W0 | X4 Y4 Z4 W4 }
+        punpckhqdq %2, m8, m9       ; { X1 Y1 Z1 W1 | X5 Y5 Z5 W5 }
+        punpcklqdq %3, m10, m11     ; { X2 Y2 Z2 W2 | X6 Y6 Z6 W6 }
+        punpckhqdq %4, m10, m11     ; { X3 Y3 Z3 W3 | X7 Y7 Z7 W7 }
+    %if %7 == 32
+        mova m8,  %1
+        mova m9,  %2
+        mova m10, %3
+        mova m11, %4
+    %else
+        pshufb m8,  %1, m12
+        pshufb m9,  %2, m12
+        pshufb m10, %3, m12
+        pshufb m11, %4, m12
+    %endif
+        movu [%5 +  0*%6], xm8
+        movu [%5 +  4*%6], xm9
+        movu [%5 +  8*%6], xm10
+        movu [%5 + 12*%6], xm11
+    %if cpuflag(avx2)
+        vextracti128 [%5 + 16*%6], m8, 1
+        vextracti128 [%5 + 20*%6], m9, 1
+        vextracti128 [%5 + 24*%6], m10, 1
+        vextracti128 [%5 + 28*%6], m11, 1
+    %endif
+%endmacro
+
+%macro write_packed 2 ; num, depth
+op write%2_packed%1
+IF %2 < 32, VBROADCASTI128 m12, [write%2_pack%1]
+            LOAD_CONT tmp0q
+            write_packed_inner mx, my, mz, mw, out0q, %1, %2
+IF1 V2,     write_packed_inner mx2, my2, mz2, mw2, out0q + %1 * mmsize, %1, %2
+            add out0q, %1 * mmsize * (1 + V2)
+            FINISH tmp0q
+%endmacro
+
+%macro rw_packed 1 ; depth
+        read_packed2 %1
+        read_packed 3, %1
+        read_packed 4, %1
+        write_packed2 %1
+        write_packed 3, %1
+        write_packed 4, %1
+%endmacro
+
+%macro read_nibbles 0
+op read_nibbles1
+%if cpuflag(avx2)
+        movu xmx,  [in0q]
+IF V2,  movu xmx2, [in0q + 16]
+%else
+        movq xmx,  [in0q]
+IF V2,  movq xmx2, [in0q + 8]
+%endif
+        VBROADCASTI128 m8, [mask4]
+        LOAD_CONT tmp0q
+        add in0q, (mmsize >> 1) * (1 + V2)
+        pmovzxbw mx, xmx
+IF V2,  pmovzxbw mx2, xmx2
+        psllw my, mx, 8
+IF V2,  psllw my2, mx2, 8
+        psrlw mx, 4
+IF V2,  psrlw mx2, 4
+        pand my, m8
+IF V2,  pand my2, m8
+        por mx, my
+IF V2,  por mx2, my2
+        CONTINUE tmp0q
+%endmacro
+
+%macro read_bits 0
+op read_bits1
+%if cpuflag(avx2)
+        vpbroadcastd mx,  [in0q]
+IF V2,  vpbroadcastd mx2, [in0q + 4]
+%else
+        movd mx, [in0q]
+IF V2,  movd mx2, [in0q + 2]
+%endif
+        mova m8, [bits_shuf]
+        VBROADCASTI128 m9,  [bits_mask]
+        VBROADCASTI128 m10, [const1b]
+        LOAD_CONT tmp0q
+        add in0q, (mmsize >> 3) * (1 + V2)
+        pshufb mx,  m8
+IF V2,  pshufb mx2, m8
+        pand mx,  m9
+IF V2,  pand mx2, m9
+        pcmpeqb mx,  m9
+IF V2,  pcmpeqb mx2, m9
+        pand mx,  m10
+IF V2,  pand mx2, m10
+        CONTINUE tmp0q
+%endmacro
+
+; TODO: write_nibbles
+
+%macro write_bits 0
+op write_bits1
+        VBROADCASTI128 m8, [bits_reverse]
+        psllw mx,  7
+IF V2,  psllw mx2, 7
+        pshufb mx,  m8
+IF V2,  pshufb mx2, m8
+        pmovmskb tmp0d, mx
+IF V2,  pmovmskb tmp1d, mx2
+        mov [out0q],     tmp0d
+IF V2,  mov [out0q + (mmsize >> 3)], tmp1d
+        LOAD_CONT tmp0q
+        add out0q, (mmsize >> 3) * (1 + V2)
+        FINISH tmp0q
+%endmacro
+
+;--------------------------
+; Pixel packing / unpacking
+
+%macro pack_generic 3-4 0 ; x, y, z, w
+op pack_%1%2%3%4
+        ; pslld works for all sizes because the input should not overflow
+IF %2,  pslld mx, %4+%3+%2
+IF %3,  pslld my, %4+%3
+IF %4,  pslld mz, %4
+IF %2,  por mx, my
+IF %3,  por mx, mz
+IF %4,  por mx, mw
+    %if V2
+IF %2,  pslld mx2, %4+%3+%2
+IF %3,  pslld my2, %4+%3
+IF %4,  pslld mz2, %4
+IF %2,  por mx2, my2
+IF %3,  por mx2, mz2
+IF %4,  por mx2, mw2
+    %endif
+        CONTINUE
+%endmacro
+
+%macro unpack 5-6 0 ; type, bits, x, y, z, w
+op unpack_%3%4%5%6
+        ; clear high bits by shifting left
+IF %6,  vpsll%1 mw, mx, %2 - (%6)
+IF %5,  vpsll%1 mz, mx, %2 - (%6+%5)
+IF %4,  vpsll%1 my, mx, %2 - (%6+%5+%4)
+        psrl%1 mx, %4+%5+%6
+IF %4,  psrl%1 my, %2 - %4
+IF %5,  psrl%1 mz, %2 - %5
+IF %6,  psrl%1 mw, %2 - %6
+    %if V2
+IF %6,  vpsll%1 mw2, mx2, %2 - (%6)
+IF %5,  vpsll%1 mz2, mx2, %2 - (%6+%5)
+IF %4,  vpsll%1 my2, mx2, %2 - (%6+%5+%4)
+        psrl%1 mx2, %4+%5+%6
+IF %4,  psrl%1 my2, %2 - %4
+IF %5,  psrl%1 mz2, %2 - %5
+IF %6,  psrl%1 mw2, %2 - %6
+    %endif
+        CONTINUE
+%endmacro
+
+%macro unpack8 3 ; x, y, z
+op unpack_%1%2%3 %+ 0
+        pand mz, mx, [mask%3]
+        psrld my, mx, %3
+        psrld mx, %3+%2
+        pand my, [mask%2]
+        pand mx, [mask%1]
+    %if V2
+        pand mz2, mx2, [mask%3]
+        psrld my2, mx2, %3
+        psrld mx2, %3+%2
+        pand my2, [mask%2]
+        pand mx2, [mask%1]
+    %endif
+        CONTINUE
+%endmacro
+
+;---------------------------------------------------------
+; Generic byte order shuffle (packed swizzle, endian, etc)
+
+%macro shuffle 0
+op shuffle
+        VBROADCASTI128 m8, [implq + SwsOpImpl.priv]
+        LOAD_CONT tmp0q
+IF X,   pshufb mx, m8
+IF Y,   pshufb my, m8
+IF Z,   pshufb mz, m8
+IF W,   pshufb mw, m8
+%if V2
+IF X,   pshufb mx2, m8
+IF Y,   pshufb my2, m8
+IF Z,   pshufb mz2, m8
+IF W,   pshufb mw2, m8
+%endif
+        CONTINUE tmp0q
+%endmacro
+
+;---------------------------------------------------------
+; Clearing
+
+%macro clear_alpha 3 ; idx, vreg, vreg2
+op clear_alpha%1
+        LOAD_CONT tmp0q
+        pcmpeqb %2, %2
+IF V2,  mova %3, %2
+        CONTINUE tmp0q
+%endmacro
+
+%macro clear_zero 3 ; idx, vreg, vreg2
+op clear_zero%1
+        LOAD_CONT tmp0q
+        pxor %2, %2
+IF V2,  mova %3, %2
+        CONTINUE tmp0q
+%endmacro
+
+; note: the pattern is inverted for these functions; i.e. X=1 implies that we
+; *keep* the X component, not that we clear it
+%macro clear_generic 0
+op clear
+            LOAD_CONT tmp0q
+%if cpuflag(avx2)
+    IF !X,  vpbroadcastd mx, [implq + SwsOpImpl.priv + 0]
+    IF !Y,  vpbroadcastd my, [implq + SwsOpImpl.priv + 4]
+    IF !Z,  vpbroadcastd mz, [implq + SwsOpImpl.priv + 8]
+    IF !W,  vpbroadcastd mw, [implq + SwsOpImpl.priv + 12]
+%else ; !cpuflag(avx2)
+    IF !X,  movd mx, [implq + SwsOpImpl.priv + 0]
+    IF !Y,  movd my, [implq + SwsOpImpl.priv + 4]
+    IF !Z,  movd mz, [implq + SwsOpImpl.priv + 8]
+    IF !W,  movd mw, [implq + SwsOpImpl.priv + 12]
+    IF !X,  pshufd mx, mx, 0
+    IF !Y,  pshufd my, my, 0
+    IF !Z,  pshufd mz, mz, 0
+    IF !W,  pshufd mw, mw, 0
+%endif
+%if V2
+    IF !X,  mova mx2, mx
+    IF !Y,  mova my2, my
+    IF !Z,  mova mz2, mz
+    IF !W,  mova mw2, mw
+%endif
+            CONTINUE tmp0q
+%endmacro
+
+%macro clear_funcs 0
+        decl_pattern 1, 1, 1, 0, clear_generic
+        decl_pattern 0, 1, 1, 1, clear_generic
+        decl_pattern 0, 0, 1, 1, clear_generic
+        decl_pattern 1, 0, 1, 1, clear_generic
+        decl_pattern 1, 0, 0, 1, clear_generic
+        decl_pattern 1, 1, 0, 0, clear_generic
+        decl_pattern 0, 1, 0, 1, clear_generic
+        decl_pattern 1, 0, 1, 0, clear_generic
+        decl_pattern 1, 0, 0, 0, clear_generic
+        decl_pattern 0, 1, 0, 0, clear_generic
+        decl_pattern 0, 0, 1, 0, clear_generic
+%endmacro
+
+;---------------------------------------------------------
+; Swizzling and duplicating
+
+; mA := mB, mB := mC, ... mX := mA across both halves
+%macro vrotate 2-* ; A, B, C, ...
+    %rep %0
+        %assign rot_a %1 + 4
+        %assign rot_b %2 + 4
+        mova m%1, m%2
+        IF V2, mova m%[rot_a], m%[rot_b]
+    %rotate 1
+    %endrep
+    %undef rot_a
+    %undef rot_b
+%endmacro
+
+%macro swizzle_funcs 0
+op swizzle_3012
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3, 2, 1
+    CONTINUE tmp0q
+
+op swizzle_3021
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3, 1
+    CONTINUE tmp0q
+
+op swizzle_2103
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 2
+    CONTINUE tmp0q
+
+op swizzle_3210
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3
+    vrotate 8, 1, 2
+    CONTINUE tmp0q
+
+op swizzle_3102
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3, 2
+    CONTINUE tmp0q
+
+op swizzle_3201
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3, 1, 2
+    CONTINUE tmp0q
+
+op swizzle_1203
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 1, 2
+    CONTINUE tmp0q
+
+op swizzle_1023
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 1
+    CONTINUE tmp0q
+
+op swizzle_2013
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 2, 1
+    CONTINUE tmp0q
+
+op swizzle_2310
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 2, 1, 3
+    CONTINUE tmp0q
+
+op swizzle_2130
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 2, 3
+    CONTINUE tmp0q
+
+op swizzle_1230
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 1, 2, 3
+    CONTINUE tmp0q
+
+op swizzle_1320
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 1, 3
+    CONTINUE tmp0q
+
+op swizzle_0213
+    LOAD_CONT tmp0q
+    vrotate 8, 1, 2
+    CONTINUE tmp0q
+
+op swizzle_0231
+    LOAD_CONT tmp0q
+    vrotate 8, 1, 2, 3
+    CONTINUE tmp0q
+
+op swizzle_0312
+    LOAD_CONT tmp0q
+    vrotate 8, 1, 3, 2
+    CONTINUE tmp0q
+
+op swizzle_3120
+    LOAD_CONT tmp0q
+    vrotate 8, 0, 3
+    CONTINUE tmp0q
+
+op swizzle_0321
+    LOAD_CONT tmp0q
+    vrotate 8, 1, 3
+    CONTINUE tmp0q
+
+op swizzle_0003
+    LOAD_CONT tmp0q
+    mova my, mx
+    mova mz, mx
+%if V2
+    mova my2, mx2
+    mova mz2, mx2
+%endif
+    CONTINUE tmp0q
+
+op swizzle_0001
+    LOAD_CONT tmp0q
+    mova mw, my
+    mova mz, mx
+    mova my, mx
+%if V2
+    mova mw2, my2
+    mova mz2, mx2
+    mova my2, mx2
+%endif
+    CONTINUE tmp0q
+
+op swizzle_3000
+    LOAD_CONT tmp0q
+    mova my, mx
+    mova mz, mx
+    mova mx, mw
+    mova mw, my
+%if V2
+    mova my2, mx2
+    mova mz2, mx2
+    mova mx2, mw2
+    mova mw2, my2
+%endif
+    CONTINUE tmp0q
+
+op swizzle_1000
+    LOAD_CONT tmp0q
+    mova mz, mx
+    mova mw, mx
+    mova mx, my
+    mova my, mz
+%if V2
+    mova mz2, mx2
+    mova mw2, mx2
+    mova mx2, my2
+    mova my2, mz2
+%endif
+    CONTINUE tmp0q
+%endmacro
+
+;---------------------------------------------------------
+; Pixel type conversions
+
+%macro conv8to16 1 ; type
+op %1_U8_U16
+            LOAD_CONT tmp0q
+%if V2
+    %if cpuflag(avx2)
+    IF X,   vextracti128 xmx2, mx, 1
+    IF Y,   vextracti128 xmy2, my, 1
+    IF Z,   vextracti128 xmz2, mz, 1
+    IF W,   vextracti128 xmw2, mw, 1
+    %else
+    IF X,   psrldq xmx2, mx, 8
+    IF Y,   psrldq xmy2, my, 8
+    IF Z,   psrldq xmz2, mz, 8
+    IF W,   psrldq xmw2, mw, 8
+    %endif
+    IF X,   pmovzxbw mx2, xmx2
+    IF Y,   pmovzxbw my2, xmy2
+    IF Z,   pmovzxbw mz2, xmz2
+    IF W,   pmovzxbw mw2, xmw2
+%endif ; V2
+    IF X,   pmovzxbw mx, xmx
+    IF Y,   pmovzxbw my, xmy
+    IF Z,   pmovzxbw mz, xmz
+    IF W,   pmovzxbw mw, xmw
+
+%ifidn %1, expand
+            VBROADCASTI128 m8, [expand16_shuf]
+    %if V2
+    IF X,   pshufb mx2, m8
+    IF Y,   pshufb my2, m8
+    IF Z,   pshufb mz2, m8
+    IF W,   pshufb mw2, m8
+    %endif
+    IF X,   pshufb mx, m8
+    IF Y,   pshufb my, m8
+    IF Z,   pshufb mz, m8
+    IF W,   pshufb mw, m8
+%endif ; expand
+            CONTINUE tmp0q
+%endmacro
+
+%macro conv16to8 0
+op convert_U16_U8
+        LOAD_CONT tmp0q
+%if V2
+        ; this code technically works for the !V2 case as well, but slower
+IF X,   packuswb mx, mx2
+IF Y,   packuswb my, my2
+IF Z,   packuswb mz, mz2
+IF W,   packuswb mw, mw2
+IF X,   vpermq mx, mx, q3120
+IF Y,   vpermq my, my, q3120
+IF Z,   vpermq mz, mz, q3120
+IF W,   vpermq mw, mw, q3120
+%else
+IF X,   vextracti128  xm8, mx, 1
+IF Y,   vextracti128  xm9, my, 1
+IF Z,   vextracti128 xm10, mz, 1
+IF W,   vextracti128 xm11, mw, 1
+        vzeroupper
+IF X,   packuswb xmx, xm8
+IF Y,   packuswb xmy, xm9
+IF Z,   packuswb xmz, xm10
+IF W,   packuswb xmw, xm11
+%endif
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv8to32 1 ; type
+op %1_U8_U32
+        LOAD_CONT tmp0q
+IF X,   psrldq xmx2, xmx, 8
+IF Y,   psrldq xmy2, xmy, 8
+IF Z,   psrldq xmz2, xmz, 8
+IF W,   psrldq xmw2, xmw, 8
+IF X,   pmovzxbd mx, xmx
+IF Y,   pmovzxbd my, xmy
+IF Z,   pmovzxbd mz, xmz
+IF W,   pmovzxbd mw, xmw
+IF X,   pmovzxbd mx2, xmx2
+IF Y,   pmovzxbd my2, xmy2
+IF Z,   pmovzxbd mz2, xmz2
+IF W,   pmovzxbd mw2, xmw2
+%ifidn %1, expand
+        VBROADCASTI128 m8, [expand32_shuf]
+IF X,   pshufb mx, m8
+IF Y,   pshufb my, m8
+IF Z,   pshufb mz, m8
+IF W,   pshufb mw, m8
+IF X,   pshufb mx2, m8
+IF Y,   pshufb my2, m8
+IF Z,   pshufb mz2, m8
+IF W,   pshufb mw2, m8
+%endif ; expand
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv32to8 0
+op convert_U32_U8
+        LOAD_CONT tmp0q
+IF X,   packusdw mx, mx2
+IF Y,   packusdw my, my2
+IF Z,   packusdw mz, mz2
+IF W,   packusdw mw, mw2
+IF X,   vextracti128 xmx2, mx, 1
+IF Y,   vextracti128 xmy2, my, 1
+IF Z,   vextracti128 xmz2, mz, 1
+IF W,   vextracti128 xmw2, mw, 1
+        vzeroupper
+IF X,   packuswb xmx, xmx2
+IF Y,   packuswb xmy, xmy2
+IF Z,   packuswb xmz, xmz2
+IF W,   packuswb xmw, xmw2
+IF X,   vpshufd xmx, xmx, q3120
+IF Y,   vpshufd xmy, xmy, q3120
+IF Z,   vpshufd xmz, xmz, q3120
+IF W,   vpshufd xmw, xmw, q3120
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv16to32 0
+op convert_U16_U32
+        LOAD_CONT tmp0q
+IF X,   vextracti128 xmx2, mx, 1
+IF Y,   vextracti128 xmy2, my, 1
+IF Z,   vextracti128 xmz2, mz, 1
+IF W,   vextracti128 xmw2, mw, 1
+IF X,   pmovzxwd mx, xmx
+IF Y,   pmovzxwd my, xmy
+IF Z,   pmovzxwd mz, xmz
+IF W,   pmovzxwd mw, xmw
+IF X,   pmovzxwd mx2, xmx2
+IF Y,   pmovzxwd my2, xmy2
+IF Z,   pmovzxwd mz2, xmz2
+IF W,   pmovzxwd mw2, xmw2
+        CONTINUE tmp0q
+%endmacro
+
+%macro conv32to16 0
+op convert_U32_U16
+        LOAD_CONT tmp0q
+IF X,   packusdw mx, mx2
+IF Y,   packusdw my, my2
+IF Z,   packusdw mz, mz2
+IF W,   packusdw mw, mw2
+IF X,   vpermq mx, mx, q3120
+IF Y,   vpermq my, my, q3120
+IF Z,   vpermq mz, mz, q3120
+IF W,   vpermq mw, mw, q3120
+        CONTINUE tmp0q
+%endmacro
+
+;---------------------------------------------------------
+; Shifting and scaling
+
+%macro lshift16 0
+op lshift16
+        vmovq xm8, [implq + SwsOpImpl.priv]
+        LOAD_CONT tmp0q
+IF X,   psllw mx, xm8
+IF Y,   psllw my, xm8
+IF Z,   psllw mz, xm8
+IF W,   psllw mw, xm8
+%if V2
+IF X,   psllw mx2, xm8
+IF Y,   psllw my2, xm8
+IF Z,   psllw mz2, xm8
+IF W,   psllw mw2, xm8
+%endif
+        CONTINUE tmp0q
+%endmacro
+
+%macro rshift16 0
+op rshift16
+        vmovq xm8, [implq + SwsOpImpl.priv]
+        LOAD_CONT tmp0q
+IF X,   psrlw mx, xm8
+IF Y,   psrlw my, xm8
+IF Z,   psrlw mz, xm8
+IF W,   psrlw mw, xm8
+%if V2
+IF X,   psrlw mx2, xm8
+IF Y,   psrlw my2, xm8
+IF Z,   psrlw mz2, xm8
+IF W,   psrlw mw2, xm8
+%endif
+        CONTINUE tmp0q
+%endmacro
+
+; special cases for expanding bits to full range
+%macro expand_bits 2 ; bits, suffix
+op expand_bits%1
+        mova m8, [const1%2]
+        LOAD_CONT tmp0q
+        pcmpeq%2 mx, m8
+IF V2,  pcmpeq%2 mx2, m8
+        CONTINUE tmp0q
+%endmacro
+
+;---------------------------------------------------------
+; Macro instantiations for kernel functions
+
+%macro funcs_u8 0
+    read_planar 1
+    read_planar 2
+    read_planar 3
+    read_planar 4
+    write_planar 1
+    write_planar 2
+    write_planar 3
+    write_planar 4
+
+    rw_packed 8
+    read_nibbles
+    read_bits
+    write_bits
+    expand_bits 8, b
+
+    pack_generic 1, 2, 1
+    pack_generic 3, 3, 2
+    pack_generic 2, 3, 3
+    unpack8 1, 2, 1
+    unpack8 3, 3, 2
+    unpack8 2, 3, 3
+
+    clear_alpha 0, mx, mx2
+    clear_alpha 1, my, my2
+    clear_alpha 3, mw, mw2
+    clear_zero  0, mx, mx2
+    clear_zero  1, my, my2
+    clear_zero  3, mw, mw2
+    clear_funcs
+    swizzle_funcs
+
+    decl_common_patterns shuffle
+%endmacro
+
+%macro funcs_u16 0
+    rw_packed 16
+    expand_bits 16, w
+    pack_generic  4, 4, 4
+    pack_generic  5, 5, 5
+    pack_generic  5, 6, 5
+    unpack w, 16, 4, 4, 4
+    unpack w, 16, 5, 5, 5
+    unpack w, 16, 5, 6, 5
+    decl_common_patterns conv8to16 convert
+    decl_common_patterns conv8to16 expand
+    decl_common_patterns conv16to8
+    decl_common_patterns lshift16
+    decl_common_patterns rshift16
+%endmacro
+
+INIT_XMM sse4
+decl_v2 0, funcs_u8
+decl_v2 1, funcs_u8
+
+INIT_YMM avx2
+decl_v2 0, funcs_u8
+decl_v2 1, funcs_u8
+decl_v2 0, funcs_u16
+decl_v2 1, funcs_u16
+
+INIT_YMM avx2
+decl_v2 1, rw_packed 32
+decl_v2 1, pack_generic  10, 10, 10,  2
+decl_v2 1, pack_generic   2, 10, 10, 10
+decl_v2 1, unpack d, 32, 10, 10, 10,  2
+decl_v2 1, unpack d, 32,  2, 10, 10, 10
+decl_common_patterns conv8to32 convert
+decl_common_patterns conv8to32 expand
+decl_common_patterns conv32to8
+decl_common_patterns conv16to32
+decl_common_patterns conv32to16
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/output.asm b/libs/ffmpeg/libswscale/x86/output.asm
new file mode 100644
index 000000000000..f2e884780aad
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/output.asm
@@ -0,0 +1,973 @@
+;******************************************************************************
+;* x86-optimized vertical line scaling functions
+;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@gmail.com>
+;*                    Kieran Kunhya <kieran@kunhya.com>
+;*           (c) 2020 Nelson Gomez <nelson.gomez@microsoft.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/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+minshort:      times 8 dw 0x8000
+yuv2yuvX_16_start:  times 4 dd 0x4000 - 0x40000000
+yuv2yuvX_10_start:  times 4 dd 0x10000
+yuv2yuvX_9_start:   times 4 dd 0x20000
+yuv2yuvX_10_upper:  times 8 dw 0x3ff
+yuv2yuvX_9_upper:   times 8 dw 0x1ff
+pd_4:          times 4 dd 4
+pd_4min0x40000:times 4 dd 4 - (0x40000)
+pw_16:         times 8 dw 16
+pw_32:         times 8 dw 32
+pd_255:        times 8 dd 255
+pw_512:        times 8 dw 512
+pw_1024:       times 8 dw 1024
+pd_65535_invf:             times 8 dd 0x37800080 ;1.0/65535.0
+pd_yuv2gbrp16_start:       times 8 dd -0x40000000
+pd_yuv2gbrp_y_start:       times 8 dd  (1 << 9)
+pd_yuv2gbrp_uv_start:      times 8 dd  ((1 << 9) - (128 << 19))
+pd_yuv2gbrp_a_start:       times 8 dd  (1 << 18)
+pd_yuv2gbrp16_offset:      times 8 dd  0x10000  ;(1 << 16)
+pd_yuv2gbrp16_round13:     times 8 dd  0xE0002000  ;(1 << 13) - (1 << 29)
+pd_yuv2gbrp16_a_offset:    times 8 dd  0x20002000
+pd_yuv2gbrp16_upper30:     times 8 dd  0x3FFFFFFF ;(1<<30) - 1
+pd_yuv2gbrp16_upper27:     times 8 dd  0x07FFFFFF ;(1<<27) - 1
+pd_yuv2gbrp16_upper16:     times 8 dd  0x0000FFFF ;(1<<16) - 1
+pd_yuv2gbrp16_upperC:      times 8 dd  0xC0000000
+pd_yuv2gbrp_debias:        times 8 dd  0x00008000 ;(1 << 29 - 14)
+pb_pack_shuffle8:       db  0,  4,  8, 12, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                            0,  4,  8, 12, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1
+pb_pack_shuffle16le:    db  0,  1,  4,  5, \
+                            8,  9, 12, 13, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                            0,  1,  4,  5, \
+                            8,  9, 12, 13
+pb_pack_shuffle16be:    db  1,  0,  5,  4, \
+                            9,  8, 13, 12, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                           -1, -1, -1, -1, \
+                            1,  0,  5,  4, \
+                            9,  8, 13, 12
+pb_shuffle32be:         db  3,  2,  1,  0, \
+                            7,  6,  5,  4, \
+                           11, 10,  9,  8, \
+                           15, 14, 13, 12, \
+                            3,  2,  1,  0, \
+                            7,  6,  5,  4, \
+                           11, 10,  9,  8, \
+                           15, 14, 13, 12
+yuv2nv12_shuffle_mask: times 2 db 0,  4,  8, 12, \
+                                 -1, -1, -1, -1, \
+                                 -1, -1, -1, -1, \
+                                 -1, -1, -1, -1
+yuv2nv21_shuffle_mask: times 2 db 4,  0, 12,  8, \
+                                 -1, -1, -1, -1, \
+                                 -1, -1, -1, -1, \
+                                 -1, -1, -1, -1
+yuv2nv12_permute_mask: dd 0, 4, 1, 2, 3, 5, 6, 7
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; vertical line scaling
+;
+; void yuv2plane1_<output_size>_<opt>(const int16_t *src, uint8_t *dst, int dstW,
+;                                     const uint8_t *dither, int offset)
+; and
+; void yuv2planeX_<output_size>_<opt>(const int16_t *filter, int filterSize,
+;                                     const int16_t **src, uint8_t *dst, int dstW,
+;                                     const uint8_t *dither, int offset)
+;
+; Scale one or $filterSize lines of source data to generate one line of output
+; data. The input is 15 bits in int16_t if $output_size is [8,10] and 19 bits in
+; int32_t if $output_size is 16. $filter is 12 bits. $filterSize is a multiple
+; of 2. $offset is either 0 or 3. $dither holds 8 values.
+;-----------------------------------------------------------------------------
+%macro yuv2planeX_mainloop 2
+.pixelloop_%2:
+%assign %%i 0
+    ; the rep here is for the 8-bit output MMX case, where dither covers
+    ; 8 pixels but we can only handle 2 pixels per register, and thus 4
+    ; pixels per iteration. In order to not have to keep track of where
+    ; we are w.r.t. dithering, we unroll the MMX/8-bit loop x2.
+%if %1 == 8
+%assign %%repcnt 16/mmsize
+%else
+%assign %%repcnt 1
+%endif
+
+%rep %%repcnt
+
+%if %1 == 8
+%if ARCH_X86_32
+    mova            m2, [rsp+mmsize*(0+%%i)]
+    mova            m1, [rsp+mmsize*(1+%%i)]
+%else ; x86-64
+    mova            m2,  m8
+    mova            m1,  m_dith
+%endif ; x86-32/64
+%else ; %1 == 9/10/16
+    mova            m1, [yuv2yuvX_%1_start]
+    mova            m2,  m1
+%endif ; %1 == 8/9/10/16
+    movsx     cntr_reg,  fltsizem
+.filterloop_%2_ %+ %%i:
+    ; input pixels
+    mov             r6, [srcq+gprsize*cntr_reg-2*gprsize]
+%if %1 == 16
+    mova            m3, [r6+r5*4]
+    mova            m5, [r6+r5*4+mmsize]
+%else ; %1 == 8/9/10
+    mova            m3, [r6+r5*2]
+%endif ; %1 == 8/9/10/16
+    mov             r6, [srcq+gprsize*cntr_reg-gprsize]
+%if %1 == 16
+    mova            m4, [r6+r5*4]
+    mova            m6, [r6+r5*4+mmsize]
+%else ; %1 == 8/9/10
+    mova            m4, [r6+r5*2]
+%endif ; %1 == 8/9/10/16
+
+    ; coefficients
+    movd            m0, [filterq+2*cntr_reg-4] ; coeff[0], coeff[1]
+%if %1 == 16
+    pshuflw         m7,  m0,  0          ; coeff[0]
+    pshuflw         m0,  m0,  0x55       ; coeff[1]
+    pmovsxwd        m7,  m7              ; word -> dword
+    pmovsxwd        m0,  m0              ; word -> dword
+
+    pmulld          m3,  m7
+    pmulld          m5,  m7
+    pmulld          m4,  m0
+    pmulld          m6,  m0
+
+    paddd           m2,  m3
+    paddd           m1,  m5
+    paddd           m2,  m4
+    paddd           m1,  m6
+%else ; %1 == 10/9/8
+    punpcklwd       m5,  m3,  m4
+    punpckhwd       m3,  m4
+    SPLATD          m0
+
+    pmaddwd         m5,  m0
+    pmaddwd         m3,  m0
+
+    paddd           m2,  m5
+    paddd           m1,  m3
+%endif ; %1 == 8/9/10/16
+
+    sub       cntr_reg,  2
+    jg .filterloop_%2_ %+ %%i
+
+%if %1 == 16
+    psrad           m2,  31 - %1
+    psrad           m1,  31 - %1
+%else ; %1 == 10/9/8
+    psrad           m2,  27 - %1
+    psrad           m1,  27 - %1
+%endif ; %1 == 8/9/10/16
+
+%if %1 == 8
+    packssdw        m2,  m1
+    packuswb        m2,  m2
+    movh   [dstq+r5*1],  m2
+%else ; %1 == 9/10/16
+%if %1 == 16
+    packssdw        m2,  m1
+    paddw           m2, [minshort]
+%else ; %1 == 9/10
+%if cpuflag(sse4)
+    packusdw        m2,  m1
+%else ; mmxext/sse2
+    packssdw        m2,  m1
+    pmaxsw          m2,  m6
+%endif ; mmxext/sse2/sse4/avx
+    pminsw          m2, [yuv2yuvX_%1_upper]
+%endif ; %1 == 9/10/16
+    mov%2   [dstq+r5*2],  m2
+%endif ; %1 == 8/9/10/16
+
+    add             r5,  mmsize/2
+    sub             wd,  mmsize/2
+
+%assign %%i %%i+2
+%endrep
+    jg .pixelloop_%2
+%endmacro
+
+%macro yuv2planeX_fn 3
+
+%if ARCH_X86_32
+%define cntr_reg fltsizeq
+%define movsx mov
+%else
+%define cntr_reg r7
+%define movsx movsxd
+%endif
+
+cglobal yuv2planeX_%1, %3, 8, %2, filter, fltsize, src, dst, w, dither, offset
+%if %1 == 8 || %1 == 9 || %1 == 10
+    pxor            m6,  m6
+%endif ; %1 == 8/9/10
+
+%if %1 == 8
+%if ARCH_X86_32
+%assign pad 0x2c - (stack_offset & 15)
+    SUB             rsp, pad
+%define m_dith m7
+%else ; x86-64
+%define m_dith m9
+%endif ; x86-32
+
+    ; create registers holding dither
+    movq        m_dith, [ditherq]        ; dither
+    test        offsetd, offsetd
+    jz              .no_rot
+%if mmsize == 16
+    punpcklqdq  m_dith,  m_dith
+%endif ; mmsize == 16
+    PALIGNR     m_dith,  m_dith,  3,  m0
+.no_rot:
+%if mmsize == 16
+    punpcklbw   m_dith,  m6
+%if ARCH_X86_64
+    punpcklwd       m8,  m_dith,  m6
+    pslld           m8,  12
+%else ; x86-32
+    punpcklwd       m5,  m_dith,  m6
+    pslld           m5,  12
+%endif ; x86-32/64
+    punpckhwd   m_dith,  m6
+    pslld       m_dith,  12
+%if ARCH_X86_32
+    mova      [rsp+ 0],  m5
+    mova      [rsp+16],  m_dith
+%endif
+%else ; mmsize == 8
+    punpcklbw       m5,  m_dith,  m6
+    punpckhbw   m_dith,  m6
+    punpcklwd       m4,  m5,  m6
+    punpckhwd       m5,  m6
+    punpcklwd       m3,  m_dith,  m6
+    punpckhwd   m_dith,  m6
+    pslld           m4,  12
+    pslld           m5,  12
+    pslld           m3,  12
+    pslld       m_dith,  12
+    mova      [rsp+ 0],  m4
+    mova      [rsp+ 8],  m5
+    mova      [rsp+16],  m3
+    mova      [rsp+24],  m_dith
+%endif ; mmsize == 8/16
+%endif ; %1 == 8
+
+    xor             r5,  r5
+
+%if mmsize == 8 || %1 == 8
+    yuv2planeX_mainloop %1, a
+%else ; mmsize == 16
+    test          dstq, 15
+    jnz .unaligned
+    yuv2planeX_mainloop %1, a
+    RET
+.unaligned:
+    yuv2planeX_mainloop %1, u
+%endif ; mmsize == 8/16
+
+%if %1 == 8
+%if ARCH_X86_32
+    ADD             rsp, pad
+    RET
+%else ; x86-64
+    RET
+%endif ; x86-32/64
+%else ; %1 == 9/10/16
+    RET
+%endif ; %1 == 8/9/10/16
+%endmacro
+
+%if ARCH_X86_32 && HAVE_ALIGNED_STACK == 0
+INIT_MMX mmxext
+yuv2planeX_fn  8,  0, 7
+%endif
+
+INIT_XMM sse2
+yuv2planeX_fn  8, 10, 7
+yuv2planeX_fn  9,  7, 5
+yuv2planeX_fn 10,  7, 5
+
+INIT_XMM sse4
+yuv2planeX_fn  8, 10, 7
+yuv2planeX_fn  9,  7, 5
+yuv2planeX_fn 10,  7, 5
+yuv2planeX_fn 16,  8, 5
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+yuv2planeX_fn  8, 10, 7
+yuv2planeX_fn  9,  7, 5
+yuv2planeX_fn 10,  7, 5
+%endif
+
+; %1=outout-bpc, %2=alignment (u/a)
+%macro yuv2plane1_mainloop 2
+.loop_%2:
+%if %1 == 8
+    paddsw          m0, m2, [srcq+wq*2+mmsize*0]
+    paddsw          m1, m3, [srcq+wq*2+mmsize*1]
+    psraw           m0, 7
+    psraw           m1, 7
+    packuswb        m0, m1
+    mov%2    [dstq+wq], m0
+%elif %1 == 16
+    paddd           m0, m4, [srcq+wq*4+mmsize*0]
+    paddd           m1, m4, [srcq+wq*4+mmsize*1]
+    paddd           m2, m4, [srcq+wq*4+mmsize*2]
+    paddd           m3, m4, [srcq+wq*4+mmsize*3]
+    psrad           m0, 3
+    psrad           m1, 3
+    psrad           m2, 3
+    psrad           m3, 3
+%if cpuflag(sse4) ; avx/sse4
+    packusdw        m0, m1
+    packusdw        m2, m3
+%else ; mmx/sse2
+    packssdw        m0, m1
+    packssdw        m2, m3
+    paddw           m0, m5
+    paddw           m2, m5
+%endif ; mmx/sse2/sse4/avx
+    mov%2    [dstq+wq*2+mmsize*0], m0
+    mov%2    [dstq+wq*2+mmsize*1], m2
+%else ; %1 == 9/10
+    paddsw          m0, m2, [srcq+wq*2+mmsize*0]
+    paddsw          m1, m2, [srcq+wq*2+mmsize*1]
+    psraw           m0, 15 - %1
+    psraw           m1, 15 - %1
+    pmaxsw          m0, m4
+    pmaxsw          m1, m4
+    pminsw          m0, m3
+    pminsw          m1, m3
+    mov%2    [dstq+wq*2+mmsize*0], m0
+    mov%2    [dstq+wq*2+mmsize*1], m1
+%endif
+    add             wq, mmsize
+    jl .loop_%2
+%endmacro
+
+%macro yuv2plane1_fn 3
+cglobal yuv2plane1_%1, %3, %3, %2, src, dst, w, dither, offset
+    movsxdifnidn    wq, wd
+    add             wq, mmsize - 1
+    and             wq, ~(mmsize - 1)
+%if %1 == 8
+    add           dstq, wq
+%else ; %1 != 8
+    lea           dstq, [dstq+wq*2]
+%endif ; %1 == 8
+%if %1 == 16
+    lea           srcq, [srcq+wq*4]
+%else ; %1 != 16
+    lea           srcq, [srcq+wq*2]
+%endif ; %1 == 16
+    neg             wq
+
+%if %1 == 8
+    pxor            m4, m4               ; zero
+
+    ; create registers holding dither
+    movq            m3, [ditherq]        ; dither
+    test       offsetd, offsetd
+    jz              .no_rot
+    punpcklqdq      m3, m3
+    PALIGNR         m3, m3, 3, m2
+.no_rot:
+    punpcklbw       m3, m4
+    mova            m2, m3
+%elif %1 == 9
+    pxor            m4, m4
+    mova            m3, [pw_512]
+    mova            m2, [pw_32]
+%elif %1 == 10
+    pxor            m4, m4
+    mova            m3, [pw_1024]
+    mova            m2, [pw_16]
+%else ; %1 == 16
+%if cpuflag(sse4) ; sse4/avx
+    mova            m4, [pd_4]
+%else ; sse2
+    mova            m4, [pd_4min0x40000]
+    mova            m5, [minshort]
+%endif ; sse2/sse4/avx
+%endif ; %1 == ..
+
+    ; actual pixel scaling
+    test          dstq, 15
+    jnz .unaligned
+    yuv2plane1_mainloop %1, a
+    RET
+.unaligned:
+    yuv2plane1_mainloop %1, u
+    RET
+%endmacro
+
+INIT_XMM sse2
+yuv2plane1_fn  8, 5, 5
+yuv2plane1_fn  9, 5, 3
+yuv2plane1_fn 10, 5, 3
+yuv2plane1_fn 16, 6, 3
+
+INIT_XMM sse4
+yuv2plane1_fn 16, 5, 3
+
+%if HAVE_AVX_EXTERNAL
+INIT_XMM avx
+yuv2plane1_fn  8, 5, 5
+yuv2plane1_fn  9, 5, 3
+yuv2plane1_fn 10, 5, 3
+yuv2plane1_fn 16, 5, 3
+%endif
+
+%undef movsx
+
+;-----------------------------------------------------------------------------
+; AVX2 yuv2nv12cX implementation
+;
+; void ff_yuv2nv12cX_avx2(enum AVPixelFormat format, const uint8_t *dither,
+;                         const int16_t *filter, int filterSize,
+;                         const int16_t **u, const int16_t **v,
+;                         uint8_t *dst, int dstWidth)
+;
+; void ff_yuv2nv21cX_avx2(enum AVPixelFormat format, const uint8_t *dither,
+;                         const int16_t *filter, int filterSize,
+;                         const int16_t **u, const int16_t **v,
+;                         uint8_t *dst, int dstWidth)
+;-----------------------------------------------------------------------------
+
+%if ARCH_X86_64
+%macro yuv2nv12cX_fn 1
+cglobal %1cX, 8, 11, 13, tmp1, dither, filter, filterSize, u, v, dst, dstWidth
+
+    mov tmp1q, qword [ditherq]
+    movq xm0, tmp1q
+    ror tmp1q, 24
+    movq xm1, tmp1q
+
+    pmovzxbd m0, xm0
+    pslld m0, m0, 12                        ; ditherLo
+    pmovzxbd m1, xm1
+    pslld m1, m1, 12                        ; ditherHi
+
+    pxor m9, m9                             ; uint8_min dwords
+    mova m10, [pd_255]                      ; uint8_max dwords
+    mova m11, [%1_shuffle_mask]             ; shuffle_mask
+    mova m12, [yuv2nv12_permute_mask]       ; permute mask
+
+    DEFINE_ARGS tmp1, tmp2, filter, filterSize, u, v, dst, dstWidth
+
+    xor r8q, r8q
+
+nv12_outer_%1:
+    mova m2, m0                             ; resultLo
+    mova m3, m1                             ; resultHi
+    xor r9q, r9q
+
+nv12_inner_%1:
+    movsx r10d, word [filterq + (2 * r9q)]
+    movd xm4, r10d
+    vpbroadcastd m4, xm4                    ; filter
+
+    mov tmp1q, [uq + (gprsize * r9q)]
+    mova xm7, oword [tmp1q + 2 * r8q]
+
+    mov tmp2q, [vq + (gprsize * r9q)]
+    mova xm8, oword [tmp2q + 2 * r8q]
+
+    punpcklwd xm5, xm7, xm8
+    pmovsxwd m5, xm5                        ; multiplicandsLo
+    punpckhwd xm6, xm7, xm8
+    pmovsxwd m6, xm6                        ; multiplicandsHi
+
+    pmulld m7, m5, m4                       ; mulResultLo
+    pmulld m8, m6, m4                       ; mulResultHi
+    paddd m2, m2, m7                        ; resultLo += mulResultLo
+    paddd m3, m3, m8                        ; resultHi += mulResultHi
+
+    inc r9d
+    cmp r9d, filterSized
+    jl nv12_inner_%1
+    ; end of inner loop
+
+    psrad m2, m2, 19
+    psrad m3, m3, 19
+
+    ; Vectorized av_clip_uint8
+    pmaxsd m2, m2, m9
+    pmaxsd m3, m3, m9
+    pminsd m2, m2, m10
+    pminsd m3, m3, m10
+
+    ; At this point we have clamped uint8s arranged in this order:
+    ;     m2: u1  0  0  0  v1  0  0  0  [...]
+    ;     m3: u5  0  0  0  v5  0  0  0  [...]
+    ;
+    ; First, we shuffle the bytes to make the bytes semi-contiguous.
+    ; AVX-2 doesn't have cross-lane shuffling, so we'll end up with:
+    ;     m2: u1  v1  u2  v2  0  0  0  0  0  0  0  0  u3  v3  u4  v4
+    ;     m3: u5  v5  u6  v6  0  0  0  0  0  0  0  0  u7  v7  u8  v8
+    pshufb m2, m2, m11
+    pshufb m3, m3, m11
+
+    ; To fix the cross-lane shuffling issue, we'll then use cross-lane
+    ; permutation to combine the two segments
+    vpermd m2, m12, m2
+    vpermd m3, m12, m3
+
+    ; Now we have the final results in the lower 8 bytes of each register
+    movq [dstq], xm2
+    movq [dstq + 8], xm3
+
+    add r8d, 8
+    add dstq, 16
+
+    cmp r8d, dstWidthd
+    jl nv12_outer_%1
+    RET
+%endmacro
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+yuv2nv12cX_fn yuv2nv12
+yuv2nv12cX_fn yuv2nv21
+%endif
+%endif ; ARCH_X86_64
+
+;-----------------------------------------------------------------------------
+; planar grb yuv2anyX functions
+; void ff_yuv2<gbr_format>_full_X_<opt>(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)
+;-----------------------------------------------------------------------------
+
+%if ARCH_X86_64
+struc SwsInternal
+    .padding:           resb 40348 ; offsetof(SwsInternal, yuv2rgb_y_offset)
+    .yuv2rgb_y_offset:  resd 1
+    .yuv2rgb_y_coeff:   resd 1
+    .yuv2rgb_v2r_coeff: resd 1
+    .yuv2rgb_v2g_coeff: resd 1
+    .yuv2rgb_u2g_coeff: resd 1
+    .yuv2rgb_u2b_coeff: resd 1
+endstruc
+
+%define R m0
+%define G m1
+%define B m2
+%define A m3
+
+%define Y m4
+%define U m5
+%define V m6
+
+; Clip a signed integer to an unsigned power of two range.
+; av_clip_uintp2
+; 1 - dest
+; 2 - bit position to clip at
+%macro CLIPP2 2
+    ; (~a) >> 31 & ((1<<p) - 1);
+    pcmpeqb m4, m4
+    pxor m4, %1
+    psrad m4, 31
+    movu m5, [pd_yuv2gbrp16_upper%2]
+    pand m4, m5
+
+    ; (a & ~((1<<p) - 1)) == 0
+    pandn m5, %1
+    pxor m6, m6
+    pcmpeqd m5, m6
+%if cpuflag(avx2)
+    vpblendvb %1, m4, %1, m5
+%else
+    pxor %1, m4
+    pand %1, m5
+    pxor %1, m4
+%endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+%macro LOAD16 2
+    %if cpuflag(avx2)
+        movu xm%1, %2
+        vpmovsxwd m%1, xm%1
+    %elif cpuflag(sse4)
+        movsd m%1, %2
+        pmovsxwd m%1, m%1
+    %else
+        movsd m%1, %2
+        punpcklwd m%1, m%1
+        psrad m%1, 16 ; sign extend
+    %endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - depth
+%macro LOAD_PIXELS 3
+    mov ptrq, [%2 + jq*8]
+%if %3 >= 16
+    movu m%1, [ptrq + xq*4]
+%else
+    LOAD16 %1, [ptrq + xq*2]
+%endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+%macro STORE8 2
+    mov ptrq, %1
+    %if mmsize > 16
+        pshufb m%2, [pb_pack_shuffle8]
+        vextractf128 xm4, m%2, 1
+        por xm%2, xm4
+        movq [ptrq + xq], xm%2
+    %else
+        %if cpuflag(sse4)
+            pshufb m%2, [pb_pack_shuffle8]
+        %else
+            psrldq m4, m%2, 3
+            por m%2, m4
+            psrldq m4, m%2, 6
+            por m%2, m4
+        %endif
+        movd [ptrq + xq], m%2
+    %endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - is big endian
+%macro STORE16 3
+    mov ptrq, %1
+    %if mmsize > 16
+        %if %3 ; bigendian
+            pshufb m%2, [pb_pack_shuffle16be]
+        %else
+            pshufb m%2, [pb_pack_shuffle16le]
+        %endif
+        vpermq m%2, m%2, (3 << 6 | 0 << 4 | 3 << 2 | 0 << 0)
+        movu [ptrq + xq*2], xm%2
+    %else
+        %if cpuflag(sse4) && %3 ; bigendian
+            pshufb m%2, [pb_pack_shuffle16be]
+        %elif cpuflag(sse4)
+            pshufb m%2, [pb_pack_shuffle16le]
+        %else
+            pshuflw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+            pshufhw m%2, m%2, (1 << 6 | 1 << 4 | 2 << 2 | 0 << 0)
+            pshufd  m%2, m%2, (3 << 6 | 3 << 4 | 2 << 2 | 0 << 0)
+            %if %3 ; bigendian
+                psrlw  m4, m%2, 8
+                psllw  m%2, 8
+                por m%2, m4
+            %endif
+        %endif
+        movq [ptrq + xq*2], m%2
+    %endif
+%endmacro
+
+%macro SWAP32 1
+%if mmsize > 16 || cpuflag(sse4)
+    pshufb m%1, [pb_shuffle32be]
+%else
+    psrlw  m4, m%1, 8
+    psllw  m%1, 8
+    por m%1, m4
+    pshuflw m%1, m%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
+    pshufhw m%1, m%1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0)
+%endif
+%endmacro
+
+; 1 - dest
+; 2 - source
+; 3 - depth
+; 4 - is big endian
+%macro STORE_PIXELS 4
+%if %3 > 16
+    %if %4
+        SWAP32 %2
+    %endif
+    mov ptrq, %1
+    movu [ptrq + xq*4], m%2
+%elif %3 > 8
+    STORE16 %1, %2, %4
+%else
+    STORE8 %1, %2
+%endif
+%endmacro
+
+%macro PMULLO 3
+%if cpuflag(sse4) || mmsize > 16
+    pmulld %1, %2, %3
+%else
+    %ifidni %1, %2
+    %else
+        mova %1, %2
+    %endif
+    pshufd m7, %1, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0) ; 0xb1
+    pshufd m8, %3, (2 << 6 | 3 << 4 | 0 << 2 | 1 << 0) ; 0xb1
+    pmuludq m7, m8
+    pshufd  m7, m7, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0) ; 0xd8
+    pmuludq %1, %3
+    pshufd  %1, %1, (3 << 6 | 1 << 4 | 2 << 2 | 0 << 0) ; 0xd8
+    punpckldq %1, m7
+%endif
+%endmacro
+
+; 1 - name
+; 2 - depth
+; 3 - has alpha
+; 3 - is big endian
+; 5 - is float
+%macro yuv2gbrp_fn 5
+%define DEPTH %2
+%define HAS_ALPHA %3
+%define IS_BE %4
+%define FLOAT %5
+%define SH (22 + 8 - DEPTH)
+
+%if DEPTH >= 16
+    %define RGB_SHIFT 14
+    %define A_SHIFT 14
+%elif 22 != SH
+    %define RGB_SHIFT SH
+    %define A_SHIFT (SH-3)
+%else
+    %define RGB_SHIFT 22
+    %define A_SHIFT 19
+%endif
+
+%if DEPTH >= 16
+    %define YUV_SHIFT 14
+    %define Y_START  m9
+    %define Y_ROUND [pd_yuv2gbrp16_round13]
+    %define UV_START m9
+    %define A_START  m9
+    %define A_CLIP2P 30
+%else
+    %define YUV_SHIFT 10
+    %define Y_START  [pd_yuv2gbrp_y_start]
+    %define Y_ROUND  m9
+    %define UV_START [pd_yuv2gbrp_uv_start]
+    %define A_START  [pd_yuv2gbrp_a_start]
+    %define A_CLIP2P 27
+%endif
+
+cglobal yuv2%1_full_X, 12, 14, 16, ptr, lumFilter, lumSrcx, lumFilterSize, chrFilter, chrUSrcx, chrVSrcx, chrFilterSize, alpSrcx, dest, dstW, y, x, j
+    VBROADCASTSS m10, dword [ptrq + SwsInternal.yuv2rgb_y_offset]
+    VBROADCASTSS m11, dword [ptrq + SwsInternal.yuv2rgb_y_coeff]
+    VBROADCASTSS m12, dword [ptrq + SwsInternal.yuv2rgb_v2r_coeff]
+    VBROADCASTSS m13, dword [ptrq + SwsInternal.yuv2rgb_v2g_coeff]
+    VBROADCASTSS m14, dword [ptrq + SwsInternal.yuv2rgb_u2g_coeff]
+    VBROADCASTSS m15, dword [ptrq + SwsInternal.yuv2rgb_u2b_coeff]
+
+%if DEPTH >= 16
+    movu m9, [pd_yuv2gbrp16_start]
+%else
+    mov xq, (1 << (SH-1))
+    movq xm9, xq
+    VBROADCASTSS m9, xm9
+%endif
+    xor xq, xq
+
+    %%loop_x:
+        movu Y, Y_START
+        movu U, UV_START
+        movu V, UV_START
+
+        xor jq, jq
+        %%loop_luma:
+            movsx ptrd, word [lumFilterq + jq*2]
+            movd xm0, ptrd
+            VBROADCASTSS m0, xm0
+            LOAD_PIXELS 1, lumSrcxq, DEPTH
+            PMULLO m1, m1, m0
+            paddd Y, m1
+            inc jd
+            cmp jd, lumFilterSized
+            jl %%loop_luma
+
+%if HAS_ALPHA
+        cmp alpSrcxq, 0
+        je %%skip_alpha_load
+            xor jq, jq
+            movu A, A_START
+            %%loop_alpha:
+                movsx ptrd, word [lumFilterq + jq*2]
+                movd xm0, ptrd
+                VBROADCASTSS m0, xm0
+                LOAD_PIXELS 1, alpSrcxq, DEPTH
+                PMULLO m1, m1, m0
+                paddd A, m1
+                inc jd
+                cmp jd, lumFilterSized
+                jl %%loop_alpha
+%if DEPTH >= 16
+            psrad A, 1
+            paddd A, [pd_yuv2gbrp16_a_offset]
+%endif
+        %%skip_alpha_load:
+%endif
+        xor jq, jq
+        %%loop_chr:
+            movsx ptrd, word [chrFilterq + jq*2]
+            movd xm0, ptrd
+            VBROADCASTSS m0, xm0
+            LOAD_PIXELS 1, chrUSrcxq, DEPTH
+            LOAD_PIXELS 2, chrVSrcxq, DEPTH
+            PMULLO m1, m1, m0
+            PMULLO m2, m2, m0
+            paddd U, m1
+            paddd V, m2
+            inc jd
+            cmp jd, chrFilterSized
+            jl %%loop_chr
+
+        psrad Y, YUV_SHIFT
+%if  DEPTH >= 16
+        paddd Y, [pd_yuv2gbrp16_offset]
+%endif
+        psrad U, YUV_SHIFT
+        psrad V, YUV_SHIFT
+
+        psubd  Y, m10    ; yuv2rgb_y_offset
+        PMULLO Y, Y, m11 ; yuv2rgb_y_coeff
+        paddd  Y, Y_ROUND
+
+        PMULLO R, V, m12 ; yuv2rgb_v2r_coeff
+        PMULLO B, U, m15 ; yuv2rgb_u2b_coeff
+
+        PMULLO U, U, m14 ; yuv2rgb_u2g_coeff
+        PMULLO V, V, m13 ; yuv2rgb_v2g_coeff
+        paddd G, U, V
+        paddd R, Y
+        paddd G, Y
+        paddd B, Y
+
+%if  DEPTH < 16
+        CLIPP2 R, 30
+        CLIPP2 G, 30
+        CLIPP2 B, 30
+%endif
+
+        psrad R, RGB_SHIFT
+        psrad G, RGB_SHIFT
+        psrad B, RGB_SHIFT
+
+%if  DEPTH >= 16
+        paddd R, [pd_yuv2gbrp_debias]
+        paddd G, [pd_yuv2gbrp_debias]
+        paddd B, [pd_yuv2gbrp_debias]
+
+        CLIPP2 R, 16
+        CLIPP2 G, 16
+        CLIPP2 B, 16
+%endif
+
+%if FLOAT
+        cvtdq2ps R, R
+        cvtdq2ps G, G
+        cvtdq2ps B, B
+        mulps R, [pd_65535_invf]
+        mulps G, [pd_65535_invf]
+        mulps B, [pd_65535_invf]
+%endif
+        STORE_PIXELS [destq +  0], 1, DEPTH, IS_BE ; G
+        STORE_PIXELS [destq +  8], 2, DEPTH, IS_BE ; B
+        STORE_PIXELS [destq + 16], 0, DEPTH, IS_BE ; R
+
+%if HAS_ALPHA
+        cmp alpSrcxq, 0
+        je %%skip_alpha_store
+            CLIPP2 A, A_CLIP2P
+            psrad A, A_SHIFT
+%if FLOAT
+            cvtdq2ps A, A
+            mulps A, [pd_65535_invf]
+%endif
+            STORE_PIXELS [destq + 24], 3, DEPTH, IS_BE
+        %%skip_alpha_store:
+%endif
+        add xq, mmsize/4
+        cmp xd, dstWd
+        jl %%loop_x
+
+    RET
+%endmacro
+
+%macro yuv2gbrp_fn_decl 2
+INIT_%1 %2
+yuv2gbrp_fn gbrp,        8, 0, 0, 0
+yuv2gbrp_fn gbrap,       8, 1, 0, 0
+yuv2gbrp_fn gbrp9le,     9, 0, 0, 0
+yuv2gbrp_fn gbrp10le,   10, 0, 0, 0
+yuv2gbrp_fn gbrap10le,  10, 1, 0, 0
+yuv2gbrp_fn gbrp12le,   12, 0, 0, 0
+yuv2gbrp_fn gbrap12le,  12, 1, 0, 0
+yuv2gbrp_fn gbrp14le,   14, 0, 0, 0
+yuv2gbrp_fn gbrp16le,   16, 0, 0, 0
+yuv2gbrp_fn gbrap16le,  16, 1, 0, 0
+yuv2gbrp_fn gbrpf32le,  32, 0, 0, 1
+yuv2gbrp_fn gbrapf32le, 32, 1, 0, 1
+
+yuv2gbrp_fn gbrp9be,     9, 0, 1, 0
+yuv2gbrp_fn gbrp10be,   10, 0, 1, 0
+yuv2gbrp_fn gbrap10be,  10, 1, 1, 0
+yuv2gbrp_fn gbrp12be,   12, 0, 1, 0
+yuv2gbrp_fn gbrap12be,  12, 1, 1, 0
+yuv2gbrp_fn gbrp14be,   14, 0, 1, 0
+yuv2gbrp_fn gbrp16be,   16, 0, 1, 0
+yuv2gbrp_fn gbrap16be,  16, 1, 1, 0
+yuv2gbrp_fn gbrpf32be,  32, 0, 1, 1
+yuv2gbrp_fn gbrapf32be, 32, 1, 1, 1
+%endmacro
+
+yuv2gbrp_fn_decl XMM, sse2
+yuv2gbrp_fn_decl XMM, sse4
+
+%if HAVE_AVX2_EXTERNAL
+yuv2gbrp_fn_decl YMM, avx2
+%endif
+
+%endif ; ARCH_X86_64
diff --git a/libs/ffmpeg/libswscale/x86/range_convert.asm b/libs/ffmpeg/libswscale/x86/range_convert.asm
new file mode 100644
index 000000000000..e5b8866a1f2b
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/range_convert.asm
@@ -0,0 +1,201 @@
+;******************************************************************************
+;* Copyright (c) 2024 Ramiro Polla
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General 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/x86/x86util.asm"
+
+SECTION_RODATA
+pack19:             times 4 dd (1 << 19) - 1
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; lumConvertRange
+;
+; void ff_lumRangeToJpeg{8,16}_<opt>(int16_t *dst, int width,
+;                                    uint32_t coeff, int64_t offset);
+; void ff_lumRangeFromJpeg{8,16}_<opt>(int16_t *dst, int width,
+;                                      uint32_t coeff, int64_t offset);
+;
+;-----------------------------------------------------------------------------
+
+%macro LUMCONVERTRANGE 2
+cglobal lumRange%1Jpeg%2, 4, 4, 5, dst, width, coeff, offset
+    shl          widthd, %2 >> 3
+    movd            xm2, coeffd
+    VBROADCASTSS     m2, xm2
+%if ARCH_X86_64
+    movq            xm3, offsetq
+%else
+    movq            xm3, offsetm
+%endif
+%if %2 == 16
+    VBROADCASTSD     m3, xm3
+%ifidni %1,To
+    VBROADCASTI128   m4, [pack19]
+%endif
+%elif %2 == 8
+    VBROADCASTSS     m3, xm3
+    pxor             m4, m4
+%endif ; %2 == 8/16
+    add            dstq, widthq
+    neg          widthq
+.loop:
+    movu             m0, [dstq+widthq]
+%if %2 == 16
+    pshufd           m1, m0, 0xb1
+    pmuldq           m0, m2
+    pmuldq           m1, m2
+    paddq            m0, m3
+    paddq            m1, m3
+    psrlq            m0, 18
+    psrlq            m1, 18
+    pshufd           m0, m0, 0xd8
+    pshufd           m1, m1, 0xd8
+    punpckldq        m0, m1
+%ifidni %1,To
+    PMINSD           m0, m4, m1
+%endif
+%elif %2 == 8
+    punpckhwd        m1, m0, m4
+    punpcklwd        m0, m4
+    pmaddwd          m0, m2
+    pmaddwd          m1, m2
+    paddd            m0, m3
+    paddd            m1, m3
+    psrad            m0, 14
+    psrad            m1, 14
+    packssdw         m0, m1
+%endif ; %2 == 8/16
+    movu  [dstq+widthq], m0
+    add          widthq, mmsize
+    jl .loop
+    RET
+%endmacro
+
+;-----------------------------------------------------------------------------
+; chrConvertRange
+;
+; void ff_chrRangeToJpeg{8,16}_<opt>(int16_t *dstU, int16_t *dstV, int width,
+;                                    uint32_t coeff, int64_t offset);
+; void ff_chrRangeFromJpeg{8,16}_<opt>(int16_t *dstU, int16_t *dstV, int width,
+;                                      uint32_t coeff, int64_t offset);
+;
+;-----------------------------------------------------------------------------
+
+%macro CHRCONVERTRANGE 2
+cglobal chrRange%1Jpeg%2, 5, 5, 7, dstU, dstV, width, coeff, offset
+    shl          widthd, %2 >> 3
+    movd            xm4, coeffd
+    VBROADCASTSS     m4, xm4
+%if ARCH_X86_64
+    movq            xm5, offsetq
+%else
+    movq            xm5, offsetm
+%endif
+%if %2 == 16
+    VBROADCASTSD     m5, xm5
+%ifidni %1,To
+    VBROADCASTI128   m6, [pack19]
+%endif
+%elif %2 == 8
+    VBROADCASTSS     m5, xm5
+    pxor             m6, m6
+%endif ; %2 == 8/16
+    add           dstUq, widthq
+    add           dstVq, widthq
+    neg          widthq
+.loop:
+    movu             m0, [dstUq+widthq]
+    movu             m2, [dstVq+widthq]
+%if %2 == 16
+    pshufd           m1, m0, 0xb1
+    pshufd           m3, m2, 0xb1
+    pmuldq           m0, m4
+    pmuldq           m1, m4
+    pmuldq           m2, m4
+    pmuldq           m3, m4
+    paddq            m0, m5
+    paddq            m1, m5
+    paddq            m2, m5
+    paddq            m3, m5
+    psrlq            m0, 18
+    psrlq            m1, 18
+    psrlq            m2, 18
+    psrlq            m3, 18
+    pshufd           m0, m0, 0xd8
+    pshufd           m1, m1, 0xd8
+    pshufd           m2, m2, 0xd8
+    pshufd           m3, m3, 0xd8
+    punpckldq        m0, m1
+    punpckldq        m2, m3
+%ifidni %1,To
+    PMINSD           m0, m6, m1
+    PMINSD           m2, m6, m3
+%endif
+%elif %2 == 8
+    punpckhwd        m1, m0, m6
+    punpckhwd        m3, m2, m6
+    punpcklwd        m0, m6
+    punpcklwd        m2, m6
+    pmaddwd          m0, m4
+    pmaddwd          m1, m4
+    pmaddwd          m2, m4
+    pmaddwd          m3, m4
+    paddd            m0, m5
+    paddd            m1, m5
+    paddd            m2, m5
+    paddd            m3, m5
+    psrad            m0, 14
+    psrad            m1, 14
+    psrad            m2, 14
+    psrad            m3, 14
+    packssdw         m0, m1
+    packssdw         m2, m3
+%endif ; %2 == 8/16
+    movu [dstUq+widthq], m0
+    movu [dstVq+widthq], m2
+    add          widthq, mmsize
+    jl .loop
+    RET
+%endmacro
+
+INIT_XMM sse2
+LUMCONVERTRANGE To,    8
+CHRCONVERTRANGE To,    8
+LUMCONVERTRANGE From,  8
+CHRCONVERTRANGE From,  8
+
+INIT_XMM sse4
+LUMCONVERTRANGE To,   16
+CHRCONVERTRANGE To,   16
+LUMCONVERTRANGE From, 16
+CHRCONVERTRANGE From, 16
+
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+LUMCONVERTRANGE To,    8
+LUMCONVERTRANGE To,   16
+CHRCONVERTRANGE To,    8
+CHRCONVERTRANGE To,   16
+LUMCONVERTRANGE From,  8
+LUMCONVERTRANGE From, 16
+CHRCONVERTRANGE From,  8
+CHRCONVERTRANGE From, 16
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/rgb2rgb.c b/libs/ffmpeg/libswscale/x86/rgb2rgb.c
new file mode 100644
index 000000000000..00682ae6359a
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/rgb2rgb.c
@@ -0,0 +1,2212 @@
+/*
+ * 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <stdint.h>
+
+#include "libavutil/attributes.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/cpu.h"
+#include "libavutil/bswap.h"
+#include "libavutil/mem_internal.h"
+
+#include "libswscale/rgb2rgb.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+
+#if HAVE_INLINE_ASM
+#include "libavutil/x86/asm.h"
+
+DECLARE_ASM_CONST(8, uint64_t, mmx_ff)       = 0x00000000000000FFULL;
+DECLARE_ASM_CONST(8, uint64_t, mmx_null)     = 0x0000000000000000ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask32a)      = 0xFF000000FF000000ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask3216br)   = 0x00F800F800F800F8ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask3216g)    = 0x0000FC000000FC00ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask3215g)    = 0x0000F8000000F800ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul3216)      = 0x2000000420000004ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul3215)      = 0x2000000820000008ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask24b)      = 0x00FF0000FF0000FFULL;
+DECLARE_ASM_CONST(8, uint64_t, mask24g)      = 0xFF0000FF0000FF00ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask24r)      = 0x0000FF0000FF0000ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask24l)      = 0x0000000000FFFFFFULL;
+DECLARE_ASM_CONST(8, uint64_t, mask24h)      = 0x0000FFFFFF000000ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask15b)      = 0x001F001F001F001FULL; /* 00000000 00011111  xxB */
+DECLARE_ASM_CONST(8, uint64_t, mask15rg)     = 0x7FE07FE07FE07FE0ULL; /* 01111111 11100000  RGx */
+DECLARE_ASM_CONST(8, uint64_t, mask15s)      = 0xFFE0FFE0FFE0FFE0ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask15g)      = 0x03E003E003E003E0ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask15r)      = 0x7C007C007C007C00ULL;
+#define mask16b mask15b
+DECLARE_ASM_CONST(8, uint64_t, mask16g)      = 0x07E007E007E007E0ULL;
+DECLARE_ASM_CONST(8, uint64_t, mask16r)      = 0xF800F800F800F800ULL;
+#define red_16mask mask3215g
+DECLARE_ASM_CONST(8, uint64_t, green_16mask) = 0x000007e0000007e0ULL;
+DECLARE_ASM_CONST(8, uint64_t, blue_16mask)  = 0x0000001f0000001fULL;
+DECLARE_ASM_CONST(8, uint64_t, red_15mask)   = 0x00007c0000007c00ULL;
+DECLARE_ASM_CONST(8, uint64_t, green_15mask) = 0x000003e0000003e0ULL;
+#define blue_15mask blue_16mask
+DECLARE_ASM_CONST(8, uint64_t, mul15_mid)    = 0x4200420042004200ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul15_hi)     = 0x0210021002100210ULL;
+DECLARE_ASM_CONST(8, uint64_t, mul16_mid)    = 0x2080208020802080ULL;
+
+#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))
+
+// MMXEXT versions
+#define PREFETCH "prefetchnta"
+#define PAVGB     "pavgb"
+#define MOVNTQ "movntq"
+#define SFENCE "sfence"
+
+#define EMMS     "emms"
+
+static inline void rgb24tobgr32_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    uint8_t *dest = dst;
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    mm_end = end - 23;
+    __asm__ volatile("movq        %0, %%mm7"::"m"(mask32a):"memory");
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "punpckldq  3(%1), %%mm0    \n\t"
+            "movd       6(%1), %%mm1    \n\t"
+            "punpckldq  9(%1), %%mm1    \n\t"
+            "movd      12(%1), %%mm2    \n\t"
+            "punpckldq 15(%1), %%mm2    \n\t"
+            "movd      18(%1), %%mm3    \n\t"
+            "punpckldq 21(%1), %%mm3    \n\t"
+            "por        %%mm7, %%mm0    \n\t"
+            "por        %%mm7, %%mm1    \n\t"
+            "por        %%mm7, %%mm2    \n\t"
+            "por        %%mm7, %%mm3    \n\t"
+            MOVNTQ"     %%mm0,   (%0)   \n\t"
+            MOVNTQ"     %%mm1,  8(%0)   \n\t"
+            MOVNTQ"     %%mm2, 16(%0)   \n\t"
+            MOVNTQ"     %%mm3, 24(%0)"
+            :: "r"(dest), "r"(s)
+            :"memory");
+        dest += 32;
+        s += 24;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        *dest++ = *s++;
+        *dest++ = *s++;
+        *dest++ = *s++;
+        *dest++ = 255;
+    }
+}
+
+#define STORE_BGR24_MMX \
+            "psrlq         $8, %%mm2    \n\t" \
+            "psrlq         $8, %%mm3    \n\t" \
+            "psrlq         $8, %%mm6    \n\t" \
+            "psrlq         $8, %%mm7    \n\t" \
+            "pand "MANGLE(mask24l)", %%mm0\n\t" \
+            "pand "MANGLE(mask24l)", %%mm1\n\t" \
+            "pand "MANGLE(mask24l)", %%mm4\n\t" \
+            "pand "MANGLE(mask24l)", %%mm5\n\t" \
+            "pand "MANGLE(mask24h)", %%mm2\n\t" \
+            "pand "MANGLE(mask24h)", %%mm3\n\t" \
+            "pand "MANGLE(mask24h)", %%mm6\n\t" \
+            "pand "MANGLE(mask24h)", %%mm7\n\t" \
+            "por        %%mm2, %%mm0    \n\t" \
+            "por        %%mm3, %%mm1    \n\t" \
+            "por        %%mm6, %%mm4    \n\t" \
+            "por        %%mm7, %%mm5    \n\t" \
+ \
+            "movq       %%mm1, %%mm2    \n\t" \
+            "movq       %%mm4, %%mm3    \n\t" \
+            "psllq        $48, %%mm2    \n\t" \
+            "psllq        $32, %%mm3    \n\t" \
+            "por        %%mm2, %%mm0    \n\t" \
+            "psrlq        $16, %%mm1    \n\t" \
+            "psrlq        $32, %%mm4    \n\t" \
+            "psllq        $16, %%mm5    \n\t" \
+            "por        %%mm3, %%mm1    \n\t" \
+            "por        %%mm5, %%mm4    \n\t" \
+ \
+            MOVNTQ"     %%mm0,   (%0)    \n\t" \
+            MOVNTQ"     %%mm1,  8(%0)    \n\t" \
+            MOVNTQ"     %%mm4, 16(%0)"
+
+
+static inline void rgb32tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    uint8_t *dest = dst;
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    mm_end = end - 31;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movq        (%1), %%mm0    \n\t"
+            "movq       8(%1), %%mm1    \n\t"
+            "movq      16(%1), %%mm4    \n\t"
+            "movq      24(%1), %%mm5    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm1, %%mm3    \n\t"
+            "movq       %%mm4, %%mm6    \n\t"
+            "movq       %%mm5, %%mm7    \n\t"
+            STORE_BGR24_MMX
+            :: "r"(dest), "r"(s)
+              NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
+            :"memory");
+        dest += 24;
+        s += 32;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        *dest++ = *s++;
+        *dest++ = *s++;
+        *dest++ = *s++;
+        s++;
+    }
+}
+
+/*
+ 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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    register const uint8_t* s=src;
+    register uint8_t* d=dst;
+    register const uint8_t *end;
+    const uint8_t *mm_end;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s));
+    __asm__ volatile("movq        %0, %%mm4"::"m"(mask15s));
+    mm_end = end - 15;
+    while (s<mm_end) {
+        __asm__ volatile(
+            PREFETCH" 32(%1)        \n\t"
+            "movq      (%1), %%mm0  \n\t"
+            "movq     8(%1), %%mm2  \n\t"
+            "movq     %%mm0, %%mm1  \n\t"
+            "movq     %%mm2, %%mm3  \n\t"
+            "pand     %%mm4, %%mm0  \n\t"
+            "pand     %%mm4, %%mm2  \n\t"
+            "paddw    %%mm1, %%mm0  \n\t"
+            "paddw    %%mm3, %%mm2  \n\t"
+            MOVNTQ"   %%mm0,  (%0)  \n\t"
+            MOVNTQ"   %%mm2, 8(%0)"
+            :: "r"(d), "r"(s)
+        );
+        d+=16;
+        s+=16;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    register const uint8_t* s=src;
+    register uint8_t* d=dst;
+    register const uint8_t *end;
+    const uint8_t *mm_end;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s));
+    __asm__ volatile("movq        %0, %%mm7"::"m"(mask15rg));
+    __asm__ volatile("movq        %0, %%mm6"::"m"(mask15b));
+    mm_end = end - 15;
+    while (s<mm_end) {
+        __asm__ volatile(
+            PREFETCH" 32(%1)        \n\t"
+            "movq      (%1), %%mm0  \n\t"
+            "movq     8(%1), %%mm2  \n\t"
+            "movq     %%mm0, %%mm1  \n\t"
+            "movq     %%mm2, %%mm3  \n\t"
+            "psrlq       $1, %%mm0  \n\t"
+            "psrlq       $1, %%mm2  \n\t"
+            "pand     %%mm7, %%mm0  \n\t"
+            "pand     %%mm7, %%mm2  \n\t"
+            "pand     %%mm6, %%mm1  \n\t"
+            "pand     %%mm6, %%mm3  \n\t"
+            "por      %%mm1, %%mm0  \n\t"
+            "por      %%mm3, %%mm2  \n\t"
+            MOVNTQ"   %%mm0,  (%0)  \n\t"
+            MOVNTQ"   %%mm2, 8(%0)"
+            :: "r"(d), "r"(s)
+        );
+        d+=16;
+        s+=16;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    mm_end = end - 15;
+    __asm__ volatile(
+        "movq           %3, %%mm5   \n\t"
+        "movq           %4, %%mm6   \n\t"
+        "movq           %5, %%mm7   \n\t"
+        "jmp 2f                     \n\t"
+        ".p2align        4          \n\t"
+        "1:                         \n\t"
+        PREFETCH"   32(%1)          \n\t"
+        "movd         (%1), %%mm0   \n\t"
+        "movd        4(%1), %%mm3   \n\t"
+        "punpckldq   8(%1), %%mm0   \n\t"
+        "punpckldq  12(%1), %%mm3   \n\t"
+        "movq        %%mm0, %%mm1   \n\t"
+        "movq        %%mm3, %%mm4   \n\t"
+        "pand        %%mm6, %%mm0   \n\t"
+        "pand        %%mm6, %%mm3   \n\t"
+        "pmaddwd     %%mm7, %%mm0   \n\t"
+        "pmaddwd     %%mm7, %%mm3   \n\t"
+        "pand        %%mm5, %%mm1   \n\t"
+        "pand        %%mm5, %%mm4   \n\t"
+        "por         %%mm1, %%mm0   \n\t"
+        "por         %%mm4, %%mm3   \n\t"
+        "psrld          $5, %%mm0   \n\t"
+        "pslld         $11, %%mm3   \n\t"
+        "por         %%mm3, %%mm0   \n\t"
+        MOVNTQ"      %%mm0, (%0)    \n\t"
+        "add           $16,  %1     \n\t"
+        "add            $8,  %0     \n\t"
+        "2:                         \n\t"
+        "cmp            %2,  %1     \n\t"
+        " jb            1b          \n\t"
+        : "+r" (d), "+r"(s)
+        : "r" (mm_end), "m" (mask3216g), "m" (mask3216br), "m" (mul3216)
+    );
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq          %0, %%mm7    \n\t"
+        "movq          %1, %%mm6    \n\t"
+        ::"m"(red_16mask),"m"(green_16mask));
+    mm_end = end - 15;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "movd       4(%1), %%mm3    \n\t"
+            "punpckldq  8(%1), %%mm0    \n\t"
+            "punpckldq 12(%1), %%mm3    \n\t"
+            "movq       %%mm0, %%mm1    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm3, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "psllq         $8, %%mm0    \n\t"
+            "psllq         $8, %%mm3    \n\t"
+            "pand       %%mm7, %%mm0    \n\t"
+            "pand       %%mm7, %%mm3    \n\t"
+            "psrlq         $5, %%mm1    \n\t"
+            "psrlq         $5, %%mm4    \n\t"
+            "pand       %%mm6, %%mm1    \n\t"
+            "pand       %%mm6, %%mm4    \n\t"
+            "psrlq        $19, %%mm2    \n\t"
+            "psrlq        $19, %%mm5    \n\t"
+            "pand          %2, %%mm2    \n\t"
+            "pand          %2, %%mm5    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            "psllq        $16, %%mm3    \n\t"
+            "por        %%mm3, %%mm0    \n\t"
+            MOVNTQ"     %%mm0, (%0)     \n\t"
+            :: "r"(d),"r"(s),"m"(blue_16mask):"memory");
+        d += 4;
+        s += 16;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    mm_end = end - 15;
+    __asm__ volatile(
+        "movq           %3, %%mm5   \n\t"
+        "movq           %4, %%mm6   \n\t"
+        "movq           %5, %%mm7   \n\t"
+        "jmp            2f          \n\t"
+        ".p2align        4          \n\t"
+        "1:                         \n\t"
+        PREFETCH"   32(%1)          \n\t"
+        "movd         (%1), %%mm0   \n\t"
+        "movd        4(%1), %%mm3   \n\t"
+        "punpckldq   8(%1), %%mm0   \n\t"
+        "punpckldq  12(%1), %%mm3   \n\t"
+        "movq        %%mm0, %%mm1   \n\t"
+        "movq        %%mm3, %%mm4   \n\t"
+        "pand        %%mm6, %%mm0   \n\t"
+        "pand        %%mm6, %%mm3   \n\t"
+        "pmaddwd     %%mm7, %%mm0   \n\t"
+        "pmaddwd     %%mm7, %%mm3   \n\t"
+        "pand        %%mm5, %%mm1   \n\t"
+        "pand        %%mm5, %%mm4   \n\t"
+        "por         %%mm1, %%mm0   \n\t"
+        "por         %%mm4, %%mm3   \n\t"
+        "psrld          $6, %%mm0   \n\t"
+        "pslld         $10, %%mm3   \n\t"
+        "por         %%mm3, %%mm0   \n\t"
+        MOVNTQ"      %%mm0, (%0)    \n\t"
+        "add           $16,  %1     \n\t"
+        "add            $8,  %0     \n\t"
+        "2:                         \n\t"
+        "cmp            %2,  %1     \n\t"
+        " jb            1b          \n\t"
+        : "+r" (d), "+r"(s)
+        : "r" (mm_end), "m" (mask3215g), "m" (mask3216br), "m" (mul3215)
+    );
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq          %0, %%mm7    \n\t"
+        "movq          %1, %%mm6    \n\t"
+        ::"m"(red_15mask),"m"(green_15mask));
+    mm_end = end - 15;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "movd       4(%1), %%mm3    \n\t"
+            "punpckldq  8(%1), %%mm0    \n\t"
+            "punpckldq 12(%1), %%mm3    \n\t"
+            "movq       %%mm0, %%mm1    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm3, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "psllq         $7, %%mm0    \n\t"
+            "psllq         $7, %%mm3    \n\t"
+            "pand       %%mm7, %%mm0    \n\t"
+            "pand       %%mm7, %%mm3    \n\t"
+            "psrlq         $6, %%mm1    \n\t"
+            "psrlq         $6, %%mm4    \n\t"
+            "pand       %%mm6, %%mm1    \n\t"
+            "pand       %%mm6, %%mm4    \n\t"
+            "psrlq        $19, %%mm2    \n\t"
+            "psrlq        $19, %%mm5    \n\t"
+            "pand          %2, %%mm2    \n\t"
+            "pand          %2, %%mm5    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            "psllq        $16, %%mm3    \n\t"
+            "por        %%mm3, %%mm0    \n\t"
+            MOVNTQ"     %%mm0, (%0)     \n\t"
+            ::"r"(d),"r"(s),"m"(blue_15mask):"memory");
+        d += 4;
+        s += 16;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq         %0, %%mm7     \n\t"
+        "movq         %1, %%mm6     \n\t"
+        ::"m"(red_16mask),"m"(green_16mask));
+    mm_end = end - 11;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "movd       3(%1), %%mm3    \n\t"
+            "punpckldq  6(%1), %%mm0    \n\t"
+            "punpckldq  9(%1), %%mm3    \n\t"
+            "movq       %%mm0, %%mm1    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm3, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "psrlq         $3, %%mm0    \n\t"
+            "psrlq         $3, %%mm3    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %2, %%mm3    \n\t"
+            "psrlq         $5, %%mm1    \n\t"
+            "psrlq         $5, %%mm4    \n\t"
+            "pand       %%mm6, %%mm1    \n\t"
+            "pand       %%mm6, %%mm4    \n\t"
+            "psrlq         $8, %%mm2    \n\t"
+            "psrlq         $8, %%mm5    \n\t"
+            "pand       %%mm7, %%mm2    \n\t"
+            "pand       %%mm7, %%mm5    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            "psllq        $16, %%mm3    \n\t"
+            "por        %%mm3, %%mm0    \n\t"
+            MOVNTQ"     %%mm0, (%0)     \n\t"
+            ::"r"(d),"r"(s),"m"(blue_16mask):"memory");
+        d += 4;
+        s += 12;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq         %0, %%mm7     \n\t"
+        "movq         %1, %%mm6     \n\t"
+        ::"m"(red_16mask),"m"(green_16mask));
+    mm_end = end - 15;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "movd       3(%1), %%mm3    \n\t"
+            "punpckldq  6(%1), %%mm0    \n\t"
+            "punpckldq  9(%1), %%mm3    \n\t"
+            "movq       %%mm0, %%mm1    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm3, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "psllq         $8, %%mm0    \n\t"
+            "psllq         $8, %%mm3    \n\t"
+            "pand       %%mm7, %%mm0    \n\t"
+            "pand       %%mm7, %%mm3    \n\t"
+            "psrlq         $5, %%mm1    \n\t"
+            "psrlq         $5, %%mm4    \n\t"
+            "pand       %%mm6, %%mm1    \n\t"
+            "pand       %%mm6, %%mm4    \n\t"
+            "psrlq        $19, %%mm2    \n\t"
+            "psrlq        $19, %%mm5    \n\t"
+            "pand          %2, %%mm2    \n\t"
+            "pand          %2, %%mm5    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            "psllq        $16, %%mm3    \n\t"
+            "por        %%mm3, %%mm0    \n\t"
+            MOVNTQ"     %%mm0, (%0)     \n\t"
+            ::"r"(d),"r"(s),"m"(blue_16mask):"memory");
+        d += 4;
+        s += 12;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq          %0, %%mm7    \n\t"
+        "movq          %1, %%mm6    \n\t"
+        ::"m"(red_15mask),"m"(green_15mask));
+    mm_end = end - 11;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movd        (%1), %%mm0    \n\t"
+            "movd       3(%1), %%mm3    \n\t"
+            "punpckldq  6(%1), %%mm0    \n\t"
+            "punpckldq  9(%1), %%mm3    \n\t"
+            "movq       %%mm0, %%mm1    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm3, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "psrlq         $3, %%mm0    \n\t"
+            "psrlq         $3, %%mm3    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %2, %%mm3    \n\t"
+            "psrlq         $6, %%mm1    \n\t"
+            "psrlq         $6, %%mm4    \n\t"
+            "pand       %%mm6, %%mm1    \n\t"
+            "pand       %%mm6, %%mm4    \n\t"
+            "psrlq         $9, %%mm2    \n\t"
+            "psrlq         $9, %%mm5    \n\t"
+            "pand       %%mm7, %%mm2    \n\t"
+            "pand       %%mm7, %%mm5    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            "psllq        $16, %%mm3    \n\t"
+            "por        %%mm3, %%mm0    \n\t"
+            MOVNTQ"     %%mm0, (%0)     \n\t"
+            ::"r"(d),"r"(s),"m"(blue_15mask):"memory");
+        d += 4;
+        s += 12;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint8_t *s = src;
+    const uint8_t *end;
+    const uint8_t *mm_end;
+    uint16_t *d = (uint16_t *)dst;
+    end = s + src_size;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*src):"memory");
+    __asm__ volatile(
+        "movq         %0, %%mm7     \n\t"
+        "movq         %1, %%mm6     \n\t"
+        ::"m"(red_15mask),"m"(green_15mask));
+    mm_end = end - 15;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH" 32(%1)            \n\t"
+            "movd       (%1), %%mm0     \n\t"
+            "movd      3(%1), %%mm3     \n\t"
+            "punpckldq 6(%1), %%mm0     \n\t"
+            "punpckldq 9(%1), %%mm3     \n\t"
+            "movq      %%mm0, %%mm1     \n\t"
+            "movq      %%mm0, %%mm2     \n\t"
+            "movq      %%mm3, %%mm4     \n\t"
+            "movq      %%mm3, %%mm5     \n\t"
+            "psllq        $7, %%mm0     \n\t"
+            "psllq        $7, %%mm3     \n\t"
+            "pand      %%mm7, %%mm0     \n\t"
+            "pand      %%mm7, %%mm3     \n\t"
+            "psrlq        $6, %%mm1     \n\t"
+            "psrlq        $6, %%mm4     \n\t"
+            "pand      %%mm6, %%mm1     \n\t"
+            "pand      %%mm6, %%mm4     \n\t"
+            "psrlq       $19, %%mm2     \n\t"
+            "psrlq       $19, %%mm5     \n\t"
+            "pand         %2, %%mm2     \n\t"
+            "pand         %2, %%mm5     \n\t"
+            "por       %%mm1, %%mm0     \n\t"
+            "por       %%mm4, %%mm3     \n\t"
+            "por       %%mm2, %%mm0     \n\t"
+            "por       %%mm5, %%mm3     \n\t"
+            "psllq       $16, %%mm3     \n\t"
+            "por       %%mm3, %%mm0     \n\t"
+            MOVNTQ"    %%mm0, (%0)      \n\t"
+            ::"r"(d),"r"(s),"m"(blue_15mask):"memory");
+        d += 4;
+        s += 12;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    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_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint16_t *end;
+    const uint16_t *mm_end;
+    uint8_t *d = dst;
+    const uint16_t *s = (const uint16_t*)src;
+    end = s + src_size/2;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    mm_end = end - 7;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movq        (%1), %%mm0    \n\t"
+            "movq        (%1), %%mm1    \n\t"
+            "movq        (%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            "movq       %%mm0, %%mm3    \n\t"
+            "movq       %%mm1, %%mm4    \n\t"
+            "movq       %%mm2, %%mm5    \n\t"
+            "punpcklwd     %5, %%mm0    \n\t"
+            "punpcklwd     %5, %%mm1    \n\t"
+            "punpcklwd     %5, %%mm2    \n\t"
+            "punpckhwd     %5, %%mm3    \n\t"
+            "punpckhwd     %5, %%mm4    \n\t"
+            "punpckhwd     %5, %%mm5    \n\t"
+            "psllq         $8, %%mm1    \n\t"
+            "psllq        $16, %%mm2    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "psllq         $8, %%mm4    \n\t"
+            "psllq        $16, %%mm5    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+
+            "movq       %%mm0, %%mm6    \n\t"
+            "movq       %%mm3, %%mm7    \n\t"
+
+            "movq       8(%1), %%mm0    \n\t"
+            "movq       8(%1), %%mm1    \n\t"
+            "movq       8(%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            "movq       %%mm0, %%mm3    \n\t"
+            "movq       %%mm1, %%mm4    \n\t"
+            "movq       %%mm2, %%mm5    \n\t"
+            "punpcklwd     %5, %%mm0    \n\t"
+            "punpcklwd     %5, %%mm1    \n\t"
+            "punpcklwd     %5, %%mm2    \n\t"
+            "punpckhwd     %5, %%mm3    \n\t"
+            "punpckhwd     %5, %%mm4    \n\t"
+            "punpckhwd     %5, %%mm5    \n\t"
+            "psllq         $8, %%mm1    \n\t"
+            "psllq        $16, %%mm2    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "psllq         $8, %%mm4    \n\t"
+            "psllq        $16, %%mm5    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+
+            :"=m"(*d)
+            :"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r), "m"(mmx_null)
+             NAMED_CONSTRAINTS_ADD(mul15_mid,mul15_hi)
+            :"memory");
+        /* borrowed 32 to 24 */
+        __asm__ volatile(
+            "movq       %%mm0, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "movq       %%mm6, %%mm0    \n\t"
+            "movq       %%mm7, %%mm1    \n\t"
+
+            "movq       %%mm4, %%mm6    \n\t"
+            "movq       %%mm5, %%mm7    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm1, %%mm3    \n\t"
+
+            STORE_BGR24_MMX
+
+            :: "r"(d), "m"(*s)
+              NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
+            :"memory");
+        d += 24;
+        s += 8;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        register uint16_t bgr;
+        bgr = *s++;
+        *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+        *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7);
+        *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
+    }
+}
+
+static inline void rgb16tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint16_t *end;
+    const uint16_t *mm_end;
+    uint8_t *d = (uint8_t *)dst;
+    const uint16_t *s = (const uint16_t *)src;
+    end = s + src_size/2;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    mm_end = end - 7;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movq        (%1), %%mm0    \n\t"
+            "movq        (%1), %%mm1    \n\t"
+            "movq        (%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "psrlq         $1, %%mm2    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul16_mid)", %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            "movq       %%mm0, %%mm3    \n\t"
+            "movq       %%mm1, %%mm4    \n\t"
+            "movq       %%mm2, %%mm5    \n\t"
+            "punpcklwd     %5, %%mm0    \n\t"
+            "punpcklwd     %5, %%mm1    \n\t"
+            "punpcklwd     %5, %%mm2    \n\t"
+            "punpckhwd     %5, %%mm3    \n\t"
+            "punpckhwd     %5, %%mm4    \n\t"
+            "punpckhwd     %5, %%mm5    \n\t"
+            "psllq         $8, %%mm1    \n\t"
+            "psllq        $16, %%mm2    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "psllq         $8, %%mm4    \n\t"
+            "psllq        $16, %%mm5    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+
+            "movq       %%mm0, %%mm6    \n\t"
+            "movq       %%mm3, %%mm7    \n\t"
+
+            "movq       8(%1), %%mm0    \n\t"
+            "movq       8(%1), %%mm1    \n\t"
+            "movq       8(%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "psrlq         $1, %%mm2    \n\t"
+            "pmulhw        "MANGLE(mul15_mid)", %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul16_mid)", %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            "movq       %%mm0, %%mm3    \n\t"
+            "movq       %%mm1, %%mm4    \n\t"
+            "movq       %%mm2, %%mm5    \n\t"
+            "punpcklwd     %5, %%mm0    \n\t"
+            "punpcklwd     %5, %%mm1    \n\t"
+            "punpcklwd     %5, %%mm2    \n\t"
+            "punpckhwd     %5, %%mm3    \n\t"
+            "punpckhwd     %5, %%mm4    \n\t"
+            "punpckhwd     %5, %%mm5    \n\t"
+            "psllq         $8, %%mm1    \n\t"
+            "psllq        $16, %%mm2    \n\t"
+            "por        %%mm1, %%mm0    \n\t"
+            "por        %%mm2, %%mm0    \n\t"
+            "psllq         $8, %%mm4    \n\t"
+            "psllq        $16, %%mm5    \n\t"
+            "por        %%mm4, %%mm3    \n\t"
+            "por        %%mm5, %%mm3    \n\t"
+            :"=m"(*d)
+            :"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mmx_null)
+             NAMED_CONSTRAINTS_ADD(mul15_mid,mul16_mid,mul15_hi)
+            :"memory");
+        /* borrowed 32 to 24 */
+        __asm__ volatile(
+            "movq       %%mm0, %%mm4    \n\t"
+            "movq       %%mm3, %%mm5    \n\t"
+            "movq       %%mm6, %%mm0    \n\t"
+            "movq       %%mm7, %%mm1    \n\t"
+
+            "movq       %%mm4, %%mm6    \n\t"
+            "movq       %%mm5, %%mm7    \n\t"
+            "movq       %%mm0, %%mm2    \n\t"
+            "movq       %%mm1, %%mm3    \n\t"
+
+            STORE_BGR24_MMX
+
+            :: "r"(d), "m"(*s)
+              NAMED_CONSTRAINTS_ADD(mask24l,mask24h)
+            :"memory");
+        d += 24;
+        s += 8;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        register uint16_t bgr;
+        bgr = *s++;
+        *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+        *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9);
+        *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
+    }
+}
+
+/*
+ * mm0 = 00 B3 00 B2 00 B1 00 B0
+ * mm1 = 00 G3 00 G2 00 G1 00 G0
+ * mm2 = 00 R3 00 R2 00 R1 00 R0
+ * mm6 = FF FF FF FF FF FF FF FF
+ * mm7 = 00 00 00 00 00 00 00 00
+ */
+#define PACK_RGB32 \
+    "packuswb   %%mm7, %%mm0    \n\t" /* 00 00 00 00 B3 B2 B1 B0 */ \
+    "packuswb   %%mm7, %%mm1    \n\t" /* 00 00 00 00 G3 G2 G1 G0 */ \
+    "packuswb   %%mm7, %%mm2    \n\t" /* 00 00 00 00 R3 R2 R1 R0 */ \
+    "punpcklbw  %%mm1, %%mm0    \n\t" /* G3 B3 G2 B2 G1 B1 G0 B0 */ \
+    "punpcklbw  %%mm6, %%mm2    \n\t" /* FF R3 FF R2 FF R1 FF R0 */ \
+    "movq       %%mm0, %%mm3    \n\t"                               \
+    "punpcklwd  %%mm2, %%mm0    \n\t" /* FF R1 G1 B1 FF R0 G0 B0 */ \
+    "punpckhwd  %%mm2, %%mm3    \n\t" /* FF R3 G3 B3 FF R2 G2 B2 */ \
+    MOVNTQ"     %%mm0,  (%0)    \n\t"                               \
+    MOVNTQ"     %%mm3, 8(%0)    \n\t"                               \
+
+static inline void rgb15to32_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint16_t *end;
+    const uint16_t *mm_end;
+    uint8_t *d = dst;
+    const uint16_t *s = (const uint16_t *)src;
+    end = s + src_size/2;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    __asm__ volatile("pxor    %%mm7,%%mm7    \n\t":::"memory");
+    __asm__ volatile("pcmpeqd %%mm6,%%mm6    \n\t":::"memory");
+    mm_end = end - 3;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movq        (%1), %%mm0    \n\t"
+            "movq        (%1), %%mm1    \n\t"
+            "movq        (%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "pmulhw        %5, %%mm0    \n\t"
+            "pmulhw        %5, %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            PACK_RGB32
+            ::"r"(d),"r"(s),"m"(mask15b),"m"(mask15g),"m"(mask15r) ,"m"(mul15_mid)
+              NAMED_CONSTRAINTS_ADD(mul15_hi)
+            :"memory");
+        d += 16;
+        s += 4;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        register uint16_t bgr;
+        bgr = *s++;
+        *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+        *d++ = ((bgr&0x3E0)>>2) | ((bgr&0x3E0)>>7);
+        *d++ = ((bgr&0x7C00)>>7) | ((bgr&0x7C00)>>12);
+        *d++ = 255;
+    }
+}
+
+static inline void rgb16to32_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    const uint16_t *end;
+    const uint16_t *mm_end;
+    uint8_t *d = dst;
+    const uint16_t *s = (const uint16_t*)src;
+    end = s + src_size/2;
+    __asm__ volatile(PREFETCH"    %0"::"m"(*s):"memory");
+    __asm__ volatile("pxor    %%mm7,%%mm7    \n\t":::"memory");
+    __asm__ volatile("pcmpeqd %%mm6,%%mm6    \n\t":::"memory");
+    mm_end = end - 3;
+    while (s < mm_end) {
+        __asm__ volatile(
+            PREFETCH"  32(%1)           \n\t"
+            "movq        (%1), %%mm0    \n\t"
+            "movq        (%1), %%mm1    \n\t"
+            "movq        (%1), %%mm2    \n\t"
+            "pand          %2, %%mm0    \n\t"
+            "pand          %3, %%mm1    \n\t"
+            "pand          %4, %%mm2    \n\t"
+            "psllq         $5, %%mm0    \n\t"
+            "psrlq         $1, %%mm2    \n\t"
+            "pmulhw        %5, %%mm0    \n\t"
+            "pmulhw        "MANGLE(mul16_mid)", %%mm1    \n\t"
+            "pmulhw        "MANGLE(mul15_hi)", %%mm2    \n\t"
+            PACK_RGB32
+            ::"r"(d),"r"(s),"m"(mask16b),"m"(mask16g),"m"(mask16r),"m"(mul15_mid)
+              NAMED_CONSTRAINTS_ADD(mul16_mid,mul15_hi)
+            :"memory");
+        d += 16;
+        s += 4;
+    }
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+    while (s < end) {
+        register uint16_t bgr;
+        bgr = *s++;
+        *d++ = ((bgr&0x1F)<<3) | ((bgr&0x1F)>>2);
+        *d++ = ((bgr&0x7E0)>>3) | ((bgr&0x7E0)>>9);
+        *d++ = ((bgr&0xF800)>>8) | ((bgr&0xF800)>>13);
+        *d++ = 255;
+    }
+}
+
+static inline void rgb24tobgr24_mmxext(const uint8_t *src, uint8_t *dst, int src_size)
+{
+    x86_reg mmx_size= 23 - src_size;
+    __asm__ volatile (
+        "test             %%"FF_REG_a", %%"FF_REG_a"    \n\t"
+        "jns                     2f                     \n\t"
+        "movq     "MANGLE(mask24r)", %%mm5              \n\t"
+        "movq     "MANGLE(mask24g)", %%mm6              \n\t"
+        "movq     "MANGLE(mask24b)", %%mm7              \n\t"
+        ".p2align                 4                     \n\t"
+        "1:                                             \n\t"
+        PREFETCH" 32(%1, %%"FF_REG_a")                  \n\t"
+        "movq    (%1, %%"FF_REG_a"), %%mm0              \n\t" // BGR BGR BG
+        "movq    (%1, %%"FF_REG_a"), %%mm1              \n\t" // BGR BGR BG
+        "movq   2(%1, %%"FF_REG_a"), %%mm2              \n\t" // R BGR BGR B
+        "psllq                  $16, %%mm0              \n\t" // 00 BGR BGR
+        "pand                 %%mm5, %%mm0              \n\t"
+        "pand                 %%mm6, %%mm1              \n\t"
+        "pand                 %%mm7, %%mm2              \n\t"
+        "por                  %%mm0, %%mm1              \n\t"
+        "por                  %%mm2, %%mm1              \n\t"
+        "movq   6(%1, %%"FF_REG_a"), %%mm0              \n\t" // BGR BGR BG
+        MOVNTQ"               %%mm1,(%2, %%"FF_REG_a")  \n\t" // RGB RGB RG
+        "movq   8(%1, %%"FF_REG_a"), %%mm1              \n\t" // R BGR BGR B
+        "movq  10(%1, %%"FF_REG_a"), %%mm2              \n\t" // GR BGR BGR
+        "pand                 %%mm7, %%mm0              \n\t"
+        "pand                 %%mm5, %%mm1              \n\t"
+        "pand                 %%mm6, %%mm2              \n\t"
+        "por                  %%mm0, %%mm1              \n\t"
+        "por                  %%mm2, %%mm1              \n\t"
+        "movq  14(%1, %%"FF_REG_a"), %%mm0              \n\t" // R BGR BGR B
+        MOVNTQ"               %%mm1, 8(%2, %%"FF_REG_a")\n\t" // B RGB RGB R
+        "movq  16(%1, %%"FF_REG_a"), %%mm1              \n\t" // GR BGR BGR
+        "movq  18(%1, %%"FF_REG_a"), %%mm2              \n\t" // BGR BGR BG
+        "pand                 %%mm6, %%mm0              \n\t"
+        "pand                 %%mm7, %%mm1              \n\t"
+        "pand                 %%mm5, %%mm2              \n\t"
+        "por                  %%mm0, %%mm1              \n\t"
+        "por                  %%mm2, %%mm1              \n\t"
+        MOVNTQ"               %%mm1, 16(%2, %%"FF_REG_a") \n\t"
+        "add                    $24, %%"FF_REG_a"       \n\t"
+        " js                     1b                     \n\t"
+        "2:                                             \n\t"
+        : "+a" (mmx_size)
+        : "r" (src-mmx_size), "r"(dst-mmx_size)
+          NAMED_CONSTRAINTS_ADD(mask24r,mask24g,mask24b)
+    );
+
+    __asm__ volatile(SFENCE:::"memory");
+    __asm__ volatile(EMMS:::"memory");
+
+    if (mmx_size==23) return; //finished, was multiple of 8
+
+    src+= src_size;
+    dst+= src_size;
+    src_size= 23-mmx_size;
+    src-= src_size;
+    dst-= src_size;
+    for (unsigned i = 0; i < src_size; i +=3) {
+        register uint8_t x;
+        x          = src[i + 2];
+        dst[i + 1] = src[i + 1];
+        dst[i + 2] = src[i + 0];
+        dst[i + 0] = x;
+    }
+}
+
+static inline void yuvPlanartoyuy2_mmxext(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)
+{
+    const x86_reg chromWidth= width>>1;
+    for (int y = 0; y < height; y++) {
+        //FIXME handle 2 lines at once (fewer prefetches, reuse some chroma, but very likely memory-limited anyway)
+        __asm__ volatile(
+            "xor                 %%"FF_REG_a", %%"FF_REG_a" \n\t"
+            ".p2align                    4              \n\t"
+            "1:                                         \n\t"
+            PREFETCH" 32(%1, %%"FF_REG_a", 2)           \n\t"
+            PREFETCH" 32(%2, %%"FF_REG_a")              \n\t"
+            PREFETCH" 32(%3, %%"FF_REG_a")              \n\t"
+            "movq       (%2, %%"FF_REG_a"), %%mm0       \n\t" // U(0)
+            "movq                    %%mm0, %%mm2       \n\t" // U(0)
+            "movq       (%3, %%"FF_REG_a"), %%mm1       \n\t" // V(0)
+            "punpcklbw               %%mm1, %%mm0       \n\t" // UVUV UVUV(0)
+            "punpckhbw               %%mm1, %%mm2       \n\t" // UVUV UVUV(8)
+
+            "movq     (%1, %%"FF_REG_a",2), %%mm3       \n\t" // Y(0)
+            "movq    8(%1, %%"FF_REG_a",2), %%mm5       \n\t" // Y(8)
+            "movq                    %%mm3, %%mm4       \n\t" // Y(0)
+            "movq                    %%mm5, %%mm6       \n\t" // Y(8)
+            "punpcklbw               %%mm0, %%mm3       \n\t" // YUYV YUYV(0)
+            "punpckhbw               %%mm0, %%mm4       \n\t" // YUYV YUYV(4)
+            "punpcklbw               %%mm2, %%mm5       \n\t" // YUYV YUYV(8)
+            "punpckhbw               %%mm2, %%mm6       \n\t" // YUYV YUYV(12)
+
+            MOVNTQ"                  %%mm3,   (%0, %%"FF_REG_a", 4)    \n\t"
+            MOVNTQ"                  %%mm4,  8(%0, %%"FF_REG_a", 4)    \n\t"
+            MOVNTQ"                  %%mm5, 16(%0, %%"FF_REG_a", 4)    \n\t"
+            MOVNTQ"                  %%mm6, 24(%0, %%"FF_REG_a", 4)    \n\t"
+
+            "add                        $8, %%"FF_REG_a" \n\t"
+            "cmp                        %4, %%"FF_REG_a" \n\t"
+            " jb                        1b               \n\t"
+            ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth)
+            : "%"FF_REG_a
+        );
+        if ((y&(vertLumPerChroma-1)) == vertLumPerChroma-1) {
+            usrc += chromStride;
+            vsrc += chromStride;
+        }
+        ysrc += lumStride;
+        dst  += dstStride;
+    }
+    __asm__(EMMS"       \n\t"
+            SFENCE"     \n\t"
+            :::"memory");
+}
+
+/**
+ * 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_mmxext(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_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 2);
+}
+
+static inline void yuvPlanartouyvy_mmxext(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)
+{
+    const x86_reg chromWidth= width>>1;
+    for (int y = 0; y < height; y++) {
+        //FIXME handle 2 lines at once (fewer prefetches, reuse some chroma, but very likely memory-limited anyway)
+        __asm__ volatile(
+            "xor             %%"FF_REG_a", %%"FF_REG_a" \n\t"
+            ".p2align                   4               \n\t"
+            "1:                                         \n\t"
+            PREFETCH" 32(%1, %%"FF_REG_a", 2)           \n\t"
+            PREFETCH" 32(%2, %%"FF_REG_a")              \n\t"
+            PREFETCH" 32(%3, %%"FF_REG_a")              \n\t"
+            "movq      (%2, %%"FF_REG_a"), %%mm0        \n\t" // U(0)
+            "movq                   %%mm0, %%mm2        \n\t" // U(0)
+            "movq      (%3, %%"FF_REG_a"), %%mm1        \n\t" // V(0)
+            "punpcklbw              %%mm1, %%mm0        \n\t" // UVUV UVUV(0)
+            "punpckhbw              %%mm1, %%mm2        \n\t" // UVUV UVUV(8)
+
+            "movq    (%1, %%"FF_REG_a",2), %%mm3        \n\t" // Y(0)
+            "movq   8(%1, %%"FF_REG_a",2), %%mm5        \n\t" // Y(8)
+            "movq                   %%mm0, %%mm4        \n\t" // Y(0)
+            "movq                   %%mm2, %%mm6        \n\t" // Y(8)
+            "punpcklbw              %%mm3, %%mm0        \n\t" // YUYV YUYV(0)
+            "punpckhbw              %%mm3, %%mm4        \n\t" // YUYV YUYV(4)
+            "punpcklbw              %%mm5, %%mm2        \n\t" // YUYV YUYV(8)
+            "punpckhbw              %%mm5, %%mm6        \n\t" // YUYV YUYV(12)
+
+            MOVNTQ"                 %%mm0,   (%0, %%"FF_REG_a", 4)     \n\t"
+            MOVNTQ"                 %%mm4,  8(%0, %%"FF_REG_a", 4)     \n\t"
+            MOVNTQ"                 %%mm2, 16(%0, %%"FF_REG_a", 4)     \n\t"
+            MOVNTQ"                 %%mm6, 24(%0, %%"FF_REG_a", 4)     \n\t"
+
+            "add                       $8, %%"FF_REG_a" \n\t"
+            "cmp                       %4, %%"FF_REG_a" \n\t"
+            " jb                       1b               \n\t"
+            ::"r"(dst), "r"(ysrc), "r"(usrc), "r"(vsrc), "g" (chromWidth)
+            : "%"FF_REG_a
+        );
+        if ((y&(vertLumPerChroma-1)) == vertLumPerChroma-1) {
+            usrc += chromStride;
+            vsrc += chromStride;
+        }
+        ysrc += lumStride;
+        dst += dstStride;
+    }
+    __asm__(EMMS"       \n\t"
+            SFENCE"     \n\t"
+            :::"memory");
+}
+
+/**
+ * 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_mmxext(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_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 2);
+}
+
+/**
+ * Width should be a multiple of 16.
+ */
+static inline void yuv422ptouyvy_mmxext(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_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 1);
+}
+
+/**
+ * Width should be a multiple of 16.
+ */
+static inline void yuv422ptoyuy2_mmxext(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_mmxext(ysrc, usrc, vsrc, dst, width, height, lumStride, chromStride, dstStride, 1);
+}
+
+static inline void planar2x_mmxext(const uint8_t *src, uint8_t *dst, int srcWidth, int srcHeight, int srcStride, int dstStride)
+{
+    dst[0]= src[0];
+
+    // first line
+    for (int 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 (int y = 1; y < srcHeight; y++) {
+        x86_reg mmxSize= srcWidth&~15;
+
+        if (mmxSize) {
+        __asm__ volatile(
+            "mov                       %4, %%"FF_REG_a" \n\t"
+            "movq        "MANGLE(mmx_ff)", %%mm0    \n\t"
+            "movq      (%0, %%"FF_REG_a"), %%mm4    \n\t"
+            "movq                   %%mm4, %%mm2    \n\t"
+            "psllq                     $8, %%mm4    \n\t"
+            "pand                   %%mm0, %%mm2    \n\t"
+            "por                    %%mm2, %%mm4    \n\t"
+            "movq      (%1, %%"FF_REG_a"), %%mm5    \n\t"
+            "movq                   %%mm5, %%mm3    \n\t"
+            "psllq                     $8, %%mm5    \n\t"
+            "pand                   %%mm0, %%mm3    \n\t"
+            "por                    %%mm3, %%mm5    \n\t"
+            "1:                                     \n\t"
+            "movq      (%0, %%"FF_REG_a"), %%mm0    \n\t"
+            "movq      (%1, %%"FF_REG_a"), %%mm1    \n\t"
+            "movq     1(%0, %%"FF_REG_a"), %%mm2    \n\t"
+            "movq     1(%1, %%"FF_REG_a"), %%mm3    \n\t"
+            PAVGB"                  %%mm0, %%mm5    \n\t"
+            PAVGB"                  %%mm0, %%mm3    \n\t"
+            PAVGB"                  %%mm0, %%mm5    \n\t"
+            PAVGB"                  %%mm0, %%mm3    \n\t"
+            PAVGB"                  %%mm1, %%mm4    \n\t"
+            PAVGB"                  %%mm1, %%mm2    \n\t"
+            PAVGB"                  %%mm1, %%mm4    \n\t"
+            PAVGB"                  %%mm1, %%mm2    \n\t"
+            "movq                   %%mm5, %%mm7    \n\t"
+            "movq                   %%mm4, %%mm6    \n\t"
+            "punpcklbw              %%mm3, %%mm5    \n\t"
+            "punpckhbw              %%mm3, %%mm7    \n\t"
+            "punpcklbw              %%mm2, %%mm4    \n\t"
+            "punpckhbw              %%mm2, %%mm6    \n\t"
+            MOVNTQ"                 %%mm5,  (%2, %%"FF_REG_a", 2)  \n\t"
+            MOVNTQ"                 %%mm7, 8(%2, %%"FF_REG_a", 2)  \n\t"
+            MOVNTQ"                 %%mm4,  (%3, %%"FF_REG_a", 2)  \n\t"
+            MOVNTQ"                 %%mm6, 8(%3, %%"FF_REG_a", 2)  \n\t"
+            "add                       $8, %%"FF_REG_a"            \n\t"
+            "movq    -1(%0, %%"FF_REG_a"), %%mm4    \n\t"
+            "movq    -1(%1, %%"FF_REG_a"), %%mm5    \n\t"
+            " js                       1b           \n\t"
+            :: "r" (src + mmxSize  ), "r" (src + srcStride + mmxSize  ),
+               "r" (dst + mmxSize*2), "r" (dst + dstStride + mmxSize*2),
+               "g" (-mmxSize)
+               NAMED_CONSTRAINTS_ADD(mmx_ff)
+            : "%"FF_REG_a
+        );
+        } else {
+            mmxSize = 1;
+            dst[0]         = (src[0] * 3 + src[srcStride]) >> 2;
+            dst[dstStride] = (src[0] + 3 * src[srcStride]) >> 2;
+        }
+
+        for (int x = mmxSize - 1; x < srcWidth - 1; x++) {
+            dst[2*x          +1]= (3*src[x+0] +   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]= (3*src[x+1] +   src[x+srcStride  ])>>2;
+        }
+        dst[srcWidth*2 -1            ]= (3*src[srcWidth-1] +   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 (int 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];
+
+    __asm__ volatile(EMMS"       \n\t"
+                     SFENCE"     \n\t"
+                     :::"memory");
+}
+
+/**
+ * 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.)
+ * Chrominance data is only taken from every second line,
+ * others are ignored in the C version.
+ * FIXME: Write HQ version.
+ */
+#if ARCH_X86_32 && HAVE_7REGS
+DECLARE_ASM_CONST(8, uint64_t, bgr2YOffset)  = 0x1010101010101010ULL;
+DECLARE_ASM_CONST(8, uint64_t, bgr2UVOffset) = 0x8080808080808080ULL;
+DECLARE_ASM_CONST(8, uint64_t, w1111)        = 0x0001000100010001ULL;
+
+static inline void rgb24toyv12_mmxext(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)
+{
+#define BGR2Y_IDX "16*4+16*32"
+#define BGR2U_IDX "16*4+16*33"
+#define BGR2V_IDX "16*4+16*34"
+    int y;
+    const x86_reg chromWidth= width>>1;
+
+    if (height > 2) {
+        ff_rgb24toyv12_c(src, ydst, udst, vdst, width, 2, lumStride, chromStride, srcStride, rgb2yuv);
+        src  += 2*srcStride;
+        ydst += 2*lumStride;
+        udst += chromStride;
+        vdst += chromStride;
+        height -= 2;
+    }
+
+    for (y = 0; y < height - 2; y += 2) {
+        for (int i = 0; i < 2; i++) {
+            __asm__ volatile(
+                "mov                        %2, %%"FF_REG_a"\n\t"
+                "movq          "BGR2Y_IDX"(%3), %%mm6       \n\t"
+                "movq          "MANGLE(w1111)", %%mm5       \n\t"
+                "pxor                    %%mm7, %%mm7       \n\t"
+                "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_d" \n\t"
+                ".p2align                    4              \n\t"
+                "1:                                         \n\t"
+                PREFETCH" 64(%0, %%"FF_REG_d")              \n\t"
+                "movd       (%0, %%"FF_REG_d"), %%mm0       \n\t"
+                "movd      3(%0, %%"FF_REG_d"), %%mm1       \n\t"
+                "punpcklbw               %%mm7, %%mm0       \n\t"
+                "punpcklbw               %%mm7, %%mm1       \n\t"
+                "movd      6(%0, %%"FF_REG_d"), %%mm2       \n\t"
+                "movd      9(%0, %%"FF_REG_d"), %%mm3       \n\t"
+                "punpcklbw               %%mm7, %%mm2       \n\t"
+                "punpcklbw               %%mm7, %%mm3       \n\t"
+                "pmaddwd                 %%mm6, %%mm0       \n\t"
+                "pmaddwd                 %%mm6, %%mm1       \n\t"
+                "pmaddwd                 %%mm6, %%mm2       \n\t"
+                "pmaddwd                 %%mm6, %%mm3       \n\t"
+                "psrad                      $8, %%mm0       \n\t"
+                "psrad                      $8, %%mm1       \n\t"
+                "psrad                      $8, %%mm2       \n\t"
+                "psrad                      $8, %%mm3       \n\t"
+                "packssdw                %%mm1, %%mm0       \n\t"
+                "packssdw                %%mm3, %%mm2       \n\t"
+                "pmaddwd                 %%mm5, %%mm0       \n\t"
+                "pmaddwd                 %%mm5, %%mm2       \n\t"
+                "packssdw                %%mm2, %%mm0       \n\t"
+                "psraw                      $7, %%mm0       \n\t"
+
+                "movd     12(%0, %%"FF_REG_d"), %%mm4       \n\t"
+                "movd     15(%0, %%"FF_REG_d"), %%mm1       \n\t"
+                "punpcklbw               %%mm7, %%mm4       \n\t"
+                "punpcklbw               %%mm7, %%mm1       \n\t"
+                "movd     18(%0, %%"FF_REG_d"), %%mm2       \n\t"
+                "movd     21(%0, %%"FF_REG_d"), %%mm3       \n\t"
+                "punpcklbw               %%mm7, %%mm2       \n\t"
+                "punpcklbw               %%mm7, %%mm3       \n\t"
+                "pmaddwd                 %%mm6, %%mm4       \n\t"
+                "pmaddwd                 %%mm6, %%mm1       \n\t"
+                "pmaddwd                 %%mm6, %%mm2       \n\t"
+                "pmaddwd                 %%mm6, %%mm3       \n\t"
+                "psrad                      $8, %%mm4       \n\t"
+                "psrad                      $8, %%mm1       \n\t"
+                "psrad                      $8, %%mm2       \n\t"
+                "psrad                      $8, %%mm3       \n\t"
+                "packssdw                %%mm1, %%mm4       \n\t"
+                "packssdw                %%mm3, %%mm2       \n\t"
+                "pmaddwd                 %%mm5, %%mm4       \n\t"
+                "pmaddwd                 %%mm5, %%mm2       \n\t"
+                "add                       $24, %%"FF_REG_d"\n\t"
+                "packssdw                %%mm2, %%mm4       \n\t"
+                "psraw                      $7, %%mm4       \n\t"
+
+                "packuswb                %%mm4, %%mm0       \n\t"
+                "paddusb "MANGLE(bgr2YOffset)", %%mm0       \n\t"
+
+                MOVNTQ"                  %%mm0, (%1, %%"FF_REG_a") \n\t"
+                "add                        $8,      %%"FF_REG_a"  \n\t"
+                " js                        1b                     \n\t"
+                : : "r" (src+width*3), "r" (ydst+width), "g" ((x86_reg)-width), "r"(rgb2yuv)
+                  NAMED_CONSTRAINTS_ADD(w1111,bgr2YOffset)
+                : "%"FF_REG_a, "%"FF_REG_d
+            );
+            ydst += lumStride;
+            src  += srcStride;
+        }
+        src -= srcStride*2;
+        __asm__ volatile(
+            "mov                        %4, %%"FF_REG_a"\n\t"
+            "movq          "MANGLE(w1111)", %%mm5       \n\t"
+            "movq          "BGR2U_IDX"(%5), %%mm6       \n\t"
+            "pxor                    %%mm7, %%mm7       \n\t"
+            "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_d" \n\t"
+            "add              %%"FF_REG_d", %%"FF_REG_d"\n\t"
+            ".p2align                    4              \n\t"
+            "1:                                         \n\t"
+            PREFETCH" 64(%0, %%"FF_REG_d")              \n\t"
+            PREFETCH" 64(%1, %%"FF_REG_d")              \n\t"
+            "movq       (%0, %%"FF_REG_d"), %%mm0       \n\t"
+            "movq       (%1, %%"FF_REG_d"), %%mm1       \n\t"
+            "movq      6(%0, %%"FF_REG_d"), %%mm2       \n\t"
+            "movq      6(%1, %%"FF_REG_d"), %%mm3       \n\t"
+            PAVGB"                   %%mm1, %%mm0       \n\t"
+            PAVGB"                   %%mm3, %%mm2       \n\t"
+            "movq                    %%mm0, %%mm1       \n\t"
+            "movq                    %%mm2, %%mm3       \n\t"
+            "psrlq                     $24, %%mm0       \n\t"
+            "psrlq                     $24, %%mm2       \n\t"
+            PAVGB"                   %%mm1, %%mm0       \n\t"
+            PAVGB"                   %%mm3, %%mm2       \n\t"
+            "punpcklbw               %%mm7, %%mm0       \n\t"
+            "punpcklbw               %%mm7, %%mm2       \n\t"
+            "movq          "BGR2V_IDX"(%5), %%mm1       \n\t"
+            "movq          "BGR2V_IDX"(%5), %%mm3       \n\t"
+
+            "pmaddwd                 %%mm0, %%mm1       \n\t"
+            "pmaddwd                 %%mm2, %%mm3       \n\t"
+            "pmaddwd                 %%mm6, %%mm0       \n\t"
+            "pmaddwd                 %%mm6, %%mm2       \n\t"
+            "psrad                      $8, %%mm0       \n\t"
+            "psrad                      $8, %%mm1       \n\t"
+            "psrad                      $8, %%mm2       \n\t"
+            "psrad                      $8, %%mm3       \n\t"
+            "packssdw                %%mm2, %%mm0       \n\t"
+            "packssdw                %%mm3, %%mm1       \n\t"
+            "pmaddwd                 %%mm5, %%mm0       \n\t"
+            "pmaddwd                 %%mm5, %%mm1       \n\t"
+            "packssdw                %%mm1, %%mm0       \n\t" // V1 V0 U1 U0
+            "psraw                      $7, %%mm0       \n\t"
+
+            "movq     12(%0, %%"FF_REG_d"), %%mm4       \n\t"
+            "movq     12(%1, %%"FF_REG_d"), %%mm1       \n\t"
+            "movq     18(%0, %%"FF_REG_d"), %%mm2       \n\t"
+            "movq     18(%1, %%"FF_REG_d"), %%mm3       \n\t"
+            PAVGB"                   %%mm1, %%mm4       \n\t"
+            PAVGB"                   %%mm3, %%mm2       \n\t"
+            "movq                    %%mm4, %%mm1       \n\t"
+            "movq                    %%mm2, %%mm3       \n\t"
+            "psrlq                     $24, %%mm4       \n\t"
+            "psrlq                     $24, %%mm2       \n\t"
+            PAVGB"                   %%mm1, %%mm4       \n\t"
+            PAVGB"                   %%mm3, %%mm2       \n\t"
+            "punpcklbw               %%mm7, %%mm4       \n\t"
+            "punpcklbw               %%mm7, %%mm2       \n\t"
+            "movq          "BGR2V_IDX"(%5), %%mm1       \n\t"
+            "movq          "BGR2V_IDX"(%5), %%mm3       \n\t"
+
+            "pmaddwd                 %%mm4, %%mm1       \n\t"
+            "pmaddwd                 %%mm2, %%mm3       \n\t"
+            "pmaddwd                 %%mm6, %%mm4       \n\t"
+            "pmaddwd                 %%mm6, %%mm2       \n\t"
+            "psrad                      $8, %%mm4       \n\t"
+            "psrad                      $8, %%mm1       \n\t"
+            "psrad                      $8, %%mm2       \n\t"
+            "psrad                      $8, %%mm3       \n\t"
+            "packssdw                %%mm2, %%mm4       \n\t"
+            "packssdw                %%mm3, %%mm1       \n\t"
+            "pmaddwd                 %%mm5, %%mm4       \n\t"
+            "pmaddwd                 %%mm5, %%mm1       \n\t"
+            "add                       $24, %%"FF_REG_d"\n\t"
+            "packssdw                %%mm1, %%mm4       \n\t" // V3 V2 U3 U2
+            "psraw                      $7, %%mm4       \n\t"
+
+            "movq                    %%mm0, %%mm1           \n\t"
+            "punpckldq               %%mm4, %%mm0           \n\t"
+            "punpckhdq               %%mm4, %%mm1           \n\t"
+            "packsswb                %%mm1, %%mm0           \n\t"
+            "paddb  "MANGLE(bgr2UVOffset)", %%mm0           \n\t"
+            "movd                    %%mm0, (%2, %%"FF_REG_a") \n\t"
+            "punpckhdq               %%mm0, %%mm0              \n\t"
+            "movd                    %%mm0, (%3, %%"FF_REG_a") \n\t"
+            "add                        $4, %%"FF_REG_a"       \n\t"
+            " js                        1b              \n\t"
+            : : "r" (src+chromWidth*6), "r" (src+srcStride+chromWidth*6), "r" (udst+chromWidth), "r" (vdst+chromWidth), "g" (-chromWidth), "r"(rgb2yuv)
+              NAMED_CONSTRAINTS_ADD(w1111,bgr2UVOffset)
+            : "%"FF_REG_a, "%"FF_REG_d
+        );
+
+        udst += chromStride;
+        vdst += chromStride;
+        src  += srcStride*2;
+    }
+
+    __asm__ volatile(EMMS"       \n\t"
+                     SFENCE"     \n\t"
+                     :::"memory");
+
+     ff_rgb24toyv12_c(src, ydst, udst, vdst, width, height-y, lumStride, chromStride, srcStride, rgb2yuv);
+}
+#endif /* HAVE_7REGS */
+
+static void extract_even_mmxext(const uint8_t *src, uint8_t *dst, x86_reg count)
+{
+    dst +=   count;
+    src += 2*count;
+    count= - count;
+
+    if(count <= -16) {
+        count += 15;
+        __asm__ volatile(
+            "pcmpeqw       %%mm7, %%mm7        \n\t"
+            "psrlw            $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq -30(%1, %0, 2), %%mm0        \n\t"
+            "movq -22(%1, %0, 2), %%mm1        \n\t"
+            "movq -14(%1, %0, 2), %%mm2        \n\t"
+            "movq  -6(%1, %0, 2), %%mm3        \n\t"
+            "pand          %%mm7, %%mm0        \n\t"
+            "pand          %%mm7, %%mm1        \n\t"
+            "pand          %%mm7, %%mm2        \n\t"
+            "pand          %%mm7, %%mm3        \n\t"
+            "packuswb      %%mm1, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm2        \n\t"
+            MOVNTQ"        %%mm0,-15(%2, %0)   \n\t"
+            MOVNTQ"        %%mm2,- 7(%2, %0)   \n\t"
+            "add             $16, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src), "r"(dst)
+        );
+        count -= 15;
+    }
+    while(count<0) {
+        dst[count]= src[2*count];
+        count++;
+    }
+}
+
+static void extract_odd_mmxext(const uint8_t *src, uint8_t *dst, x86_reg count)
+{
+    src ++;
+    dst +=   count;
+    src += 2*count;
+    count= - count;
+
+    if(count < -16) {
+        count += 16;
+        __asm__ volatile(
+            "pcmpeqw       %%mm7, %%mm7        \n\t"
+            "psrlw            $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq -32(%1, %0, 2), %%mm0        \n\t"
+            "movq -24(%1, %0, 2), %%mm1        \n\t"
+            "movq -16(%1, %0, 2), %%mm2        \n\t"
+            "movq  -8(%1, %0, 2), %%mm3        \n\t"
+            "pand          %%mm7, %%mm0        \n\t"
+            "pand          %%mm7, %%mm1        \n\t"
+            "pand          %%mm7, %%mm2        \n\t"
+            "pand          %%mm7, %%mm3        \n\t"
+            "packuswb      %%mm1, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm2        \n\t"
+            MOVNTQ"        %%mm0,-16(%2, %0)   \n\t"
+            MOVNTQ"        %%mm2,- 8(%2, %0)   \n\t"
+            "add             $16, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src), "r"(dst)
+        );
+        count -= 16;
+    }
+    while(count<0) {
+        dst[count]= src[2*count];
+        count++;
+    }
+}
+
+#if ARCH_X86_32
+static void extract_even2_mmxext(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, x86_reg count)
+{
+    dst0+=   count;
+    dst1+=   count;
+    src += 4*count;
+    count= - count;
+    if(count <= -8) {
+        count += 7;
+        __asm__ volatile(
+            "pcmpeqw       %%mm7, %%mm7        \n\t"
+            "psrlw            $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq -28(%1, %0, 4), %%mm0        \n\t"
+            "movq -20(%1, %0, 4), %%mm1        \n\t"
+            "movq -12(%1, %0, 4), %%mm2        \n\t"
+            "movq  -4(%1, %0, 4), %%mm3        \n\t"
+            "pand          %%mm7, %%mm0        \n\t"
+            "pand          %%mm7, %%mm1        \n\t"
+            "pand          %%mm7, %%mm2        \n\t"
+            "pand          %%mm7, %%mm3        \n\t"
+            "packuswb      %%mm1, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm2        \n\t"
+            "movq          %%mm0, %%mm1        \n\t"
+            "movq          %%mm2, %%mm3        \n\t"
+            "psrlw            $8, %%mm0        \n\t"
+            "psrlw            $8, %%mm2        \n\t"
+            "pand          %%mm7, %%mm1        \n\t"
+            "pand          %%mm7, %%mm3        \n\t"
+            "packuswb      %%mm2, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm1        \n\t"
+            MOVNTQ"        %%mm0,- 7(%3, %0)   \n\t"
+            MOVNTQ"        %%mm1,- 7(%2, %0)   \n\t"
+            "add              $8, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src), "r"(dst0), "r"(dst1)
+        );
+        count -= 7;
+    }
+    while(count<0) {
+        dst0[count]= src[4*count+0];
+        dst1[count]= src[4*count+2];
+        count++;
+    }
+}
+#endif /* ARCH_X86_32 */
+
+static void extract_even2avg_mmxext(const uint8_t *src0, const uint8_t *src1, uint8_t *dst0, uint8_t *dst1, x86_reg count)
+{
+    dst0 +=   count;
+    dst1 +=   count;
+    src0 += 4*count;
+    src1 += 4*count;
+    count= - count;
+#ifdef PAVGB
+    if(count <= -8) {
+        count += 7;
+        __asm__ volatile(
+            "pcmpeqw        %%mm7, %%mm7        \n\t"
+            "psrlw             $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq  -28(%1, %0, 4), %%mm0        \n\t"
+            "movq  -20(%1, %0, 4), %%mm1        \n\t"
+            "movq  -12(%1, %0, 4), %%mm2        \n\t"
+            "movq   -4(%1, %0, 4), %%mm3        \n\t"
+            PAVGB" -28(%2, %0, 4), %%mm0        \n\t"
+            PAVGB" -20(%2, %0, 4), %%mm1        \n\t"
+            PAVGB" -12(%2, %0, 4), %%mm2        \n\t"
+            PAVGB" - 4(%2, %0, 4), %%mm3        \n\t"
+            "pand           %%mm7, %%mm0        \n\t"
+            "pand           %%mm7, %%mm1        \n\t"
+            "pand           %%mm7, %%mm2        \n\t"
+            "pand           %%mm7, %%mm3        \n\t"
+            "packuswb       %%mm1, %%mm0        \n\t"
+            "packuswb       %%mm3, %%mm2        \n\t"
+            "movq           %%mm0, %%mm1        \n\t"
+            "movq           %%mm2, %%mm3        \n\t"
+            "psrlw             $8, %%mm0        \n\t"
+            "psrlw             $8, %%mm2        \n\t"
+            "pand           %%mm7, %%mm1        \n\t"
+            "pand           %%mm7, %%mm3        \n\t"
+            "packuswb       %%mm2, %%mm0        \n\t"
+            "packuswb       %%mm3, %%mm1        \n\t"
+            MOVNTQ"         %%mm0,- 7(%4, %0)   \n\t"
+            MOVNTQ"         %%mm1,- 7(%3, %0)   \n\t"
+            "add               $8, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src0), "r"(src1), "r"(dst0), "r"(dst1)
+        );
+        count -= 7;
+    }
+#endif
+    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_mmxext(const uint8_t *src, uint8_t *dst0, uint8_t *dst1, x86_reg count)
+{
+    dst0+=   count;
+    dst1+=   count;
+    src += 4*count;
+    count= - count;
+    if(count <= -8) {
+        count += 7;
+        __asm__ volatile(
+            "pcmpeqw       %%mm7, %%mm7        \n\t"
+            "psrlw            $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq -28(%1, %0, 4), %%mm0        \n\t"
+            "movq -20(%1, %0, 4), %%mm1        \n\t"
+            "movq -12(%1, %0, 4), %%mm2        \n\t"
+            "movq  -4(%1, %0, 4), %%mm3        \n\t"
+            "psrlw            $8, %%mm0        \n\t"
+            "psrlw            $8, %%mm1        \n\t"
+            "psrlw            $8, %%mm2        \n\t"
+            "psrlw            $8, %%mm3        \n\t"
+            "packuswb      %%mm1, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm2        \n\t"
+            "movq          %%mm0, %%mm1        \n\t"
+            "movq          %%mm2, %%mm3        \n\t"
+            "psrlw            $8, %%mm0        \n\t"
+            "psrlw            $8, %%mm2        \n\t"
+            "pand          %%mm7, %%mm1        \n\t"
+            "pand          %%mm7, %%mm3        \n\t"
+            "packuswb      %%mm2, %%mm0        \n\t"
+            "packuswb      %%mm3, %%mm1        \n\t"
+            MOVNTQ"        %%mm0,- 7(%3, %0)   \n\t"
+            MOVNTQ"        %%mm1,- 7(%2, %0)   \n\t"
+            "add              $8, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src), "r"(dst0), "r"(dst1)
+        );
+        count -= 7;
+    }
+    src++;
+    while(count<0) {
+        dst0[count]= src[4*count+0];
+        dst1[count]= src[4*count+2];
+        count++;
+    }
+}
+
+static void extract_odd2avg_mmxext(const uint8_t *src0, const uint8_t *src1, uint8_t *dst0, uint8_t *dst1, x86_reg count)
+{
+    dst0 +=   count;
+    dst1 +=   count;
+    src0 += 4*count;
+    src1 += 4*count;
+    count= - count;
+#ifdef PAVGB
+    if(count <= -8) {
+        count += 7;
+        __asm__ volatile(
+            "pcmpeqw        %%mm7, %%mm7        \n\t"
+            "psrlw             $8, %%mm7        \n\t"
+            "1:                                \n\t"
+            "movq  -28(%1, %0, 4), %%mm0        \n\t"
+            "movq  -20(%1, %0, 4), %%mm1        \n\t"
+            "movq  -12(%1, %0, 4), %%mm2        \n\t"
+            "movq   -4(%1, %0, 4), %%mm3        \n\t"
+            PAVGB" -28(%2, %0, 4), %%mm0        \n\t"
+            PAVGB" -20(%2, %0, 4), %%mm1        \n\t"
+            PAVGB" -12(%2, %0, 4), %%mm2        \n\t"
+            PAVGB" - 4(%2, %0, 4), %%mm3        \n\t"
+            "psrlw             $8, %%mm0        \n\t"
+            "psrlw             $8, %%mm1        \n\t"
+            "psrlw             $8, %%mm2        \n\t"
+            "psrlw             $8, %%mm3        \n\t"
+            "packuswb       %%mm1, %%mm0        \n\t"
+            "packuswb       %%mm3, %%mm2        \n\t"
+            "movq           %%mm0, %%mm1        \n\t"
+            "movq           %%mm2, %%mm3        \n\t"
+            "psrlw             $8, %%mm0        \n\t"
+            "psrlw             $8, %%mm2        \n\t"
+            "pand           %%mm7, %%mm1        \n\t"
+            "pand           %%mm7, %%mm3        \n\t"
+            "packuswb       %%mm2, %%mm0        \n\t"
+            "packuswb       %%mm3, %%mm1        \n\t"
+            MOVNTQ"         %%mm0,- 7(%4, %0)   \n\t"
+            MOVNTQ"         %%mm1,- 7(%3, %0)   \n\t"
+            "add               $8, %0           \n\t"
+            " js 1b                            \n\t"
+            : "+r"(count)
+            : "r"(src0), "r"(src1), "r"(dst0), "r"(dst1)
+        );
+        count -= 7;
+    }
+#endif
+    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_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src,
+                                 int width, int height,
+                                 int lumStride, int chromStride, int srcStride)
+{
+    const int chromWidth = AV_CEIL_RSHIFT(width, 1);
+
+    for (int y = 0; y < height; y++) {
+        extract_even_mmxext(src, ydst, width);
+        if(y&1) {
+            extract_odd2avg_mmxext(src-srcStride, src, udst, vdst, chromWidth);
+            udst+= chromStride;
+            vdst+= chromStride;
+        }
+
+        src += srcStride;
+        ydst+= lumStride;
+    }
+    __asm__(
+            EMMS"       \n\t"
+            SFENCE"     \n\t"
+            ::: "memory"
+        );
+}
+
+static void yuyvtoyuv422_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src,
+                                 int width, int height,
+                                 int lumStride, int chromStride, int srcStride)
+{
+    const int chromWidth = AV_CEIL_RSHIFT(width, 1);
+
+    for (int y = 0; y < height; y++) {
+        extract_even_mmxext(src, ydst, width);
+        extract_odd2_mmxext(src, udst, vdst, chromWidth);
+
+        src += srcStride;
+        ydst+= lumStride;
+        udst+= chromStride;
+        vdst+= chromStride;
+    }
+    __asm__(
+            EMMS"       \n\t"
+            SFENCE"     \n\t"
+            ::: "memory"
+        );
+}
+
+static void uyvytoyuv420_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src,
+                                 int width, int height,
+                                 int lumStride, int chromStride, int srcStride)
+{
+    const int chromWidth = AV_CEIL_RSHIFT(width, 1);
+
+    for (int y = 0; y < height; y++) {
+        extract_odd_mmxext(src, ydst, width);
+        if(y&1) {
+            extract_even2avg_mmxext(src-srcStride, src, udst, vdst, chromWidth);
+            udst+= chromStride;
+            vdst+= chromStride;
+        }
+
+        src += srcStride;
+        ydst+= lumStride;
+    }
+    __asm__(
+            EMMS"       \n\t"
+            SFENCE"     \n\t"
+            ::: "memory"
+        );
+}
+
+#if ARCH_X86_32
+static void uyvytoyuv422_mmxext(uint8_t *ydst, uint8_t *udst, uint8_t *vdst, const uint8_t *src,
+                                 int width, int height,
+                                 int lumStride, int chromStride, int srcStride)
+{
+    const int chromWidth = AV_CEIL_RSHIFT(width, 1);
+
+    for (int y = 0; y < height; y++) {
+        extract_odd_mmxext(src, ydst, width);
+        extract_even2_mmxext(src, udst, vdst, chromWidth);
+
+        src += srcStride;
+        ydst+= lumStride;
+        udst+= chromStride;
+        vdst+= chromStride;
+    }
+    __asm__(
+            EMMS"       \n\t"
+            SFENCE"     \n\t"
+            ::: "memory"
+        );
+}
+#endif /* ARCH_X86_32 */
+
+static av_cold void rgb2rgb_init_mmxext(void)
+{
+    rgb15to16          = rgb15to16_mmxext;
+    rgb15tobgr24       = rgb15tobgr24_mmxext;
+    rgb15to32          = rgb15to32_mmxext;
+    rgb16tobgr24       = rgb16tobgr24_mmxext;
+    rgb16to32          = rgb16to32_mmxext;
+    rgb16to15          = rgb16to15_mmxext;
+    rgb24tobgr16       = rgb24tobgr16_mmxext;
+    rgb24tobgr15       = rgb24tobgr15_mmxext;
+    rgb24tobgr32       = rgb24tobgr32_mmxext;
+    rgb32to16          = rgb32to16_mmxext;
+    rgb32to15          = rgb32to15_mmxext;
+    rgb32tobgr24       = rgb32tobgr24_mmxext;
+    rgb24to15          = rgb24to15_mmxext;
+    rgb24to16          = rgb24to16_mmxext;
+    rgb24tobgr24       = rgb24tobgr24_mmxext;
+    rgb32tobgr16       = rgb32tobgr16_mmxext;
+    rgb32tobgr15       = rgb32tobgr15_mmxext;
+    yv12toyuy2         = yv12toyuy2_mmxext;
+    yv12touyvy         = yv12touyvy_mmxext;
+    yuv422ptoyuy2      = yuv422ptoyuy2_mmxext;
+    yuv422ptouyvy      = yuv422ptouyvy_mmxext;
+#if ARCH_X86_32
+    uyvytoyuv422       = uyvytoyuv422_mmxext;
+#endif
+    yuyvtoyuv422       = yuyvtoyuv422_mmxext;
+
+    planar2x           = planar2x_mmxext;
+#if ARCH_X86_32 && HAVE_7REGS
+    ff_rgb24toyv12     = rgb24toyv12_mmxext;
+#endif /* ARCH_X86_32 && HAVE_7REGS */
+
+    yuyvtoyuv420       = yuyvtoyuv420_mmxext;
+    uyvytoyuv420       = uyvytoyuv420_mmxext;
+}
+
+//SSE2 versions
+static void interleave_bytes_sse2(const uint8_t *src1, const uint8_t *src2, uint8_t *dest,
+                                  int width, int height, int src1Stride,
+                                  int src2Stride, int dstStride)
+{
+    for (int h = 0; h < height; h++) {
+        if (width >= 16) {
+            if (!((((intptr_t)src1) | ((intptr_t)src2) | ((intptr_t)dest))&15)) {
+        __asm__(
+            "xor              %%"FF_REG_a", %%"FF_REG_a"  \n\t"
+            "1:                                     \n\t"
+            PREFETCH" 64(%1, %%"FF_REG_a")          \n\t"
+            PREFETCH" 64(%2, %%"FF_REG_a")          \n\t"
+            "movdqa  (%1, %%"FF_REG_a"), %%xmm0     \n\t"
+            "movdqa  (%1, %%"FF_REG_a"), %%xmm1     \n\t"
+            "movdqa  (%2, %%"FF_REG_a"), %%xmm2     \n\t"
+            "punpcklbw           %%xmm2, %%xmm0     \n\t"
+            "punpckhbw           %%xmm2, %%xmm1     \n\t"
+            "movntdq             %%xmm0,   (%0, %%"FF_REG_a", 2) \n\t"
+            "movntdq             %%xmm1, 16(%0, %%"FF_REG_a", 2) \n\t"
+            "add                    $16, %%"FF_REG_a"            \n\t"
+            "cmp                     %3, %%"FF_REG_a"            \n\t"
+            " jb                     1b             \n\t"
+            ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15)
+            : "memory", XMM_CLOBBERS("xmm0", "xmm1", "xmm2",) "%"FF_REG_a
+        );
+            } else
+        __asm__(
+            "xor %%"FF_REG_a", %%"FF_REG_a"         \n\t"
+            "1:                                     \n\t"
+            PREFETCH" 64(%1, %%"FF_REG_a")          \n\t"
+            PREFETCH" 64(%2, %%"FF_REG_a")          \n\t"
+            "movq    (%1, %%"FF_REG_a"), %%mm0      \n\t"
+            "movq   8(%1, %%"FF_REG_a"), %%mm2      \n\t"
+            "movq                 %%mm0, %%mm1      \n\t"
+            "movq                 %%mm2, %%mm3      \n\t"
+            "movq    (%2, %%"FF_REG_a"), %%mm4      \n\t"
+            "movq   8(%2, %%"FF_REG_a"), %%mm5      \n\t"
+            "punpcklbw            %%mm4, %%mm0      \n\t"
+            "punpckhbw            %%mm4, %%mm1      \n\t"
+            "punpcklbw            %%mm5, %%mm2      \n\t"
+            "punpckhbw            %%mm5, %%mm3      \n\t"
+            MOVNTQ"               %%mm0,   (%0, %%"FF_REG_a", 2) \n\t"
+            MOVNTQ"               %%mm1,  8(%0, %%"FF_REG_a", 2) \n\t"
+            MOVNTQ"               %%mm2, 16(%0, %%"FF_REG_a", 2) \n\t"
+            MOVNTQ"               %%mm3, 24(%0, %%"FF_REG_a", 2) \n\t"
+            "add                    $16, %%"FF_REG_a"            \n\t"
+            "cmp                     %3, %%"FF_REG_a"            \n\t"
+            " jb                     1b                          \n\t"
+            ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15)
+            : "memory", "%"FF_REG_a
+        );
+
+        }
+        for (int w = (width & (~15)); w < width; w++) {
+            dest[2*w+0] = src1[w];
+            dest[2*w+1] = src2[w];
+        }
+        dest += dstStride;
+        src1 += src1Stride;
+        src2 += src2Stride;
+    }
+    __asm__(
+            EMMS"       \n\t"
+            SFENCE"     \n\t"
+            ::: "memory"
+            );
+}
+
+/*
+ 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
+*/
+
+#endif /* HAVE_INLINE_ASM */
+
+void ff_shuffle_bytes_2103_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_0321_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1230_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3012_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3210_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3102_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2013_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2130_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1203_ssse3(const uint8_t *src, uint8_t *dst, int src_size);
+
+#if ARCH_X86_64
+void ff_shuffle_bytes_2103_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_0321_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1230_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3012_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3210_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3102_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2013_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2130_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1203_avx2(const uint8_t *src, uint8_t *dst, int src_size);
+
+void ff_shuffle_bytes_2103_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_0321_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1230_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3012_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3210_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_3102_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2013_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_2130_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+void ff_shuffle_bytes_1203_avx512icl(const uint8_t *src, uint8_t *dst, int src_size);
+
+void ff_uyvytoyuv422_sse2(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_uyvytoyuv422_avx(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_uyvytoyuv422_avx2(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_uyvytoyuv422_avx512icl(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
+                               const uint8_t *src, int width, int height,
+                               int lumStride, int chromStride, int srcStride);
+#endif
+
+#define DEINTERLEAVE_BYTES(cpuext)                                            \
+void ff_nv12ToUV_ ## cpuext(uint8_t *dstU, uint8_t *dstV,                     \
+                            const uint8_t *unused,                            \
+                            const uint8_t *src1,                              \
+                            const uint8_t *src2,                              \
+                            int w,                                            \
+                            uint32_t *unused2,                                \
+                            void *opq);                                       \
+static void deinterleave_bytes_ ## cpuext(const uint8_t *src, uint8_t *dst1, uint8_t *dst2, \
+                                          int width, int height, int srcStride, \
+                                          int dst1Stride, int dst2Stride)     \
+{                                                                             \
+    for (int h = 0; h < height; h++) {                                        \
+        if (width >= 16)                                                      \
+            ff_nv12ToUV_ ## cpuext(dst1, dst2, NULL, src, NULL, width - 15, NULL, NULL); \
+        for (int w = (width & (~15)); w < width; w++) {                       \
+            dst1[w] = src[2*w+0];                                             \
+            dst2[w] = src[2*w+1];                                             \
+        }                                                                     \
+        src  += srcStride;                                                    \
+        dst1 += dst1Stride;                                                   \
+        dst2 += dst2Stride;                                                   \
+    }                                                                         \
+}
+
+#if HAVE_SSE2_EXTERNAL
+DEINTERLEAVE_BYTES(sse2)
+#endif
+#if HAVE_AVX_EXTERNAL
+DEINTERLEAVE_BYTES(avx)
+#endif
+
+av_cold void rgb2rgb_init_x86(void)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+#if HAVE_INLINE_ASM
+    if (INLINE_MMXEXT(cpu_flags))
+        rgb2rgb_init_mmxext();
+    if (INLINE_SSE2(cpu_flags))
+        interleaveBytes = interleave_bytes_sse2;
+#endif /* HAVE_INLINE_ASM */
+
+#if HAVE_SSE2_EXTERNAL
+    if (EXTERNAL_SSE2(cpu_flags)) {
+#if ARCH_X86_64
+        uyvytoyuv422 = ff_uyvytoyuv422_sse2;
+#endif
+        deinterleaveBytes = deinterleave_bytes_sse2;
+    }
+#endif
+    if (EXTERNAL_SSSE3(cpu_flags)) {
+        shuffle_bytes_0321 = ff_shuffle_bytes_0321_ssse3;
+        shuffle_bytes_2103 = ff_shuffle_bytes_2103_ssse3;
+        shuffle_bytes_1230 = ff_shuffle_bytes_1230_ssse3;
+        shuffle_bytes_3012 = ff_shuffle_bytes_3012_ssse3;
+        shuffle_bytes_3210 = ff_shuffle_bytes_3210_ssse3;
+        shuffle_bytes_3102 = ff_shuffle_bytes_3102_ssse3;
+        shuffle_bytes_2013 = ff_shuffle_bytes_2013_ssse3;
+        shuffle_bytes_2130 = ff_shuffle_bytes_2130_ssse3;
+        shuffle_bytes_1203 = ff_shuffle_bytes_1203_ssse3;
+    }
+#if HAVE_AVX_EXTERNAL
+    if (EXTERNAL_AVX(cpu_flags)) {
+        deinterleaveBytes = deinterleave_bytes_avx;
+#if ARCH_X86_64
+        uyvytoyuv422 = ff_uyvytoyuv422_avx;
+    }
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        shuffle_bytes_0321 = ff_shuffle_bytes_0321_avx2;
+        shuffle_bytes_2103 = ff_shuffle_bytes_2103_avx2;
+        shuffle_bytes_1230 = ff_shuffle_bytes_1230_avx2;
+        shuffle_bytes_3012 = ff_shuffle_bytes_3012_avx2;
+        shuffle_bytes_3210 = ff_shuffle_bytes_3210_avx2;
+        shuffle_bytes_3102 = ff_shuffle_bytes_3102_avx2;
+        shuffle_bytes_2013 = ff_shuffle_bytes_2013_avx2;
+        shuffle_bytes_2130 = ff_shuffle_bytes_2130_avx2;
+        shuffle_bytes_1203 = ff_shuffle_bytes_1203_avx2;
+    }
+    if (EXTERNAL_AVX512ICL(cpu_flags)) {
+        shuffle_bytes_0321 = ff_shuffle_bytes_0321_avx512icl;
+        shuffle_bytes_2103 = ff_shuffle_bytes_2103_avx512icl;
+        shuffle_bytes_1230 = ff_shuffle_bytes_1230_avx512icl;
+        shuffle_bytes_3012 = ff_shuffle_bytes_3012_avx512icl;
+        shuffle_bytes_3210 = ff_shuffle_bytes_3210_avx512icl;
+        shuffle_bytes_3102 = ff_shuffle_bytes_3102_avx512icl;
+        shuffle_bytes_2013 = ff_shuffle_bytes_2013_avx512icl;
+        shuffle_bytes_2130 = ff_shuffle_bytes_2130_avx512icl;
+        shuffle_bytes_1203 = ff_shuffle_bytes_1203_avx512icl;
+    }
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        uyvytoyuv422 = ff_uyvytoyuv422_avx2;
+    }
+    if (EXTERNAL_AVX512ICL(cpu_flags)) {
+        uyvytoyuv422 = ff_uyvytoyuv422_avx512icl;
+#endif
+    }
+#endif
+}
+
+#endif
diff --git a/libs/ffmpeg/libswscale/x86/rgb_2_rgb.asm b/libs/ffmpeg/libswscale/x86/rgb_2_rgb.asm
new file mode 100644
index 000000000000..871bb2112750
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/rgb_2_rgb.asm
@@ -0,0 +1,411 @@
+;******************************************************************************
+;* Copyright Nick Kurshev
+;* Copyright Michael (michaelni@gmx.at)
+;* Copyright 2018 Jokyo Images
+;* Copyright Ivo van Poorten
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General 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/x86/x86util.asm"
+
+SECTION_RODATA
+
+pb_shuffle2103: db 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15
+pb_shuffle0321: db 0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13
+pb_shuffle1230: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12
+pb_shuffle3012: db 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14
+pb_shuffle3210: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12
+pb_shuffle3102: db 3, 1, 0, 2, 7, 5, 4, 6, 11, 9, 8, 10, 15, 13, 12, 14
+pb_shuffle2013: db 2, 0, 1, 3, 6, 4, 5, 7, 10, 8, 9, 11, 14, 12, 13, 15
+pb_shuffle2130: db 2, 1, 3, 0, 6, 5, 7, 4, 10, 9, 11, 8, 14, 13, 15, 12
+pb_shuffle1203: db 1, 2, 0, 3, 5, 6, 4, 7, 9, 10, 8, 11, 13, 14, 12, 15
+
+%if HAVE_AVX512ICL_EXTERNAL
+; shuffle vector to rearrange packuswb result to be linear
+shuf_packus: db  0,  1,  2,  3, 16, 17, 18, 19, 32, 33, 34, 35, 48, 49, 50, 51,\
+                 4,  5,  6,  7, 20, 21, 22, 23, 36, 37, 38, 39, 52, 53, 54, 55,\
+                 8,  9, 10, 11, 24, 25, 26, 27, 40, 41, 42, 43, 56, 57, 58, 59,\
+                12, 13, 14, 15, 28, 29, 30, 31, 44, 45, 46, 47, 60, 61, 62, 63
+
+; shuffle vector to combine odd elements from two vectors to extract Y
+shuf_perm2b: db  1,  3,   5,   7,   9,  11,  13,  15,  17,  19,  21,  23,  25,  27,  29,  31,\
+                33, 35,  37,  39,  41,  43,  45,  47,  49,  51,  53,  55,  57,  59,  61,  63,\
+                65, 67,  69,  71,  73,  75,  77,  79,  81,  83,  85,  87,  89,  91,  93,  95,\
+                97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127
+%endif
+
+%if HAVE_AVX2_EXTERNAL
+; shuffle vector to rearrange packuswb result to be linear
+shuf_packus_avx2: db  0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0,\
+                      2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0,
+%endif
+
+SECTION .text
+
+%macro RSHIFT_COPY 3
+; %1 dst ; %2 src ; %3 shift
+%if cpuflag(avx) || cpuflag(avx2) || cpuflag(avx512icl)
+    psrldq  %1, %2, %3
+%else
+    mova           %1, %2
+    RSHIFT         %1, %3
+%endif
+%endmacro
+
+;------------------------------------------------------------------------------
+; shuffle_bytes_## (const uint8_t *src, uint8_t *dst, int src_size)
+;------------------------------------------------------------------------------
+; %1-4 index shuffle
+%macro SHUFFLE_BYTES 4
+cglobal shuffle_bytes_%1%2%3%4, 3, 5, 2, src, dst, w, tmp, x
+    VBROADCASTI128    m0, [pb_shuffle%1%2%3%4]
+    movsxdifnidn      wq, wd
+    mov               xq, wq
+
+    add             srcq, wq
+    add             dstq, wq
+    neg               wq
+
+%if mmsize == 64
+    and                    xq, mmsize - 4
+    shr                    xq, 2
+    mov                  tmpd, -1
+    shlx                 tmpd, tmpd, xd
+    not                  tmpd
+    kmovw                  k7, tmpd
+    vmovdqu32       m1{k7}{z}, [srcq + wq]
+    pshufb                 m1, m0
+    vmovdqu32 [dstq + wq]{k7}, m1
+    lea                    wq, [wq + 4 * xq]
+%else
+    ;calc scalar loop
+    and xq, mmsize-4
+    je .loop_simd
+
+    .loop_scalar:
+        mov          tmpb, [srcq + wq + %1]
+        mov [dstq+wq + 0], tmpb
+        mov          tmpb, [srcq + wq + %2]
+        mov [dstq+wq + 1], tmpb
+        mov          tmpb, [srcq + wq + %3]
+        mov [dstq+wq + 2], tmpb
+        mov          tmpb, [srcq + wq + %4]
+        mov [dstq+wq + 3], tmpb
+        add            wq, 4
+        sub            xq, 4
+        jg .loop_scalar
+%endif
+
+    ;check if src_size < mmsize
+    cmp wq, 0
+    jge .end
+
+    .loop_simd:
+        movu            m1, [srcq + wq]
+        pshufb          m1, m0
+        movu   [dstq + wq], m1
+        add             wq, mmsize
+        jl .loop_simd
+
+.end:
+    RET
+%endmacro
+
+INIT_XMM ssse3
+SHUFFLE_BYTES 2, 1, 0, 3
+SHUFFLE_BYTES 0, 3, 2, 1
+SHUFFLE_BYTES 1, 2, 3, 0
+SHUFFLE_BYTES 3, 0, 1, 2
+SHUFFLE_BYTES 3, 2, 1, 0
+SHUFFLE_BYTES 3, 1, 0, 2
+SHUFFLE_BYTES 2, 0, 1, 3
+SHUFFLE_BYTES 2, 1, 3, 0
+SHUFFLE_BYTES 1, 2, 0, 3
+
+%if ARCH_X86_64
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+SHUFFLE_BYTES 2, 1, 0, 3
+SHUFFLE_BYTES 0, 3, 2, 1
+SHUFFLE_BYTES 1, 2, 3, 0
+SHUFFLE_BYTES 3, 0, 1, 2
+SHUFFLE_BYTES 3, 2, 1, 0
+SHUFFLE_BYTES 3, 1, 0, 2
+SHUFFLE_BYTES 2, 0, 1, 3
+SHUFFLE_BYTES 2, 1, 3, 0
+SHUFFLE_BYTES 1, 2, 0, 3
+%endif
+%endif
+
+%if ARCH_X86_64
+%if HAVE_AVX512ICL_EXTERNAL
+INIT_ZMM avx512icl
+SHUFFLE_BYTES 2, 1, 0, 3
+SHUFFLE_BYTES 0, 3, 2, 1
+SHUFFLE_BYTES 1, 2, 3, 0
+SHUFFLE_BYTES 3, 0, 1, 2
+SHUFFLE_BYTES 3, 2, 1, 0
+SHUFFLE_BYTES 3, 1, 0, 2
+SHUFFLE_BYTES 2, 0, 1, 3
+SHUFFLE_BYTES 2, 1, 3, 0
+SHUFFLE_BYTES 1, 2, 0, 3
+%endif
+%endif
+
+;-----------------------------------------------------------------------------------------------
+; uyvytoyuv422(uint8_t *ydst, uint8_t *udst, uint8_t *vdst,
+;              const uint8_t *src, int width, int height,
+;              int lumStride, int chromStride, int srcStride)
+;-----------------------------------------------------------------------------------------------
+%macro UYVY_TO_YUV422 0
+cglobal uyvytoyuv422, 9, 14, 8 + cpuflag(avx2) + cpuflag(avx512icl), ydst, udst, vdst, src, w, h, lum_stride, chrom_stride, src_stride, wtwo, whalf, tmp, x, back_w
+    pxor         m0, m0
+%if mmsize == 64
+    vpternlogd   m1, m1, m1, 0xff  ; m1 = _mm512_set1_epi8(0xff)
+    movu         m8, [shuf_packus]
+    movu         m9, [shuf_perm2b]
+%else
+    %if cpuflag(avx2)
+        movu     m8, [shuf_packus_avx2]
+    %endif
+    pcmpeqw      m1, m1
+%endif
+    psrlw        m1, 8
+
+    movsxdifnidn            wq, wd
+    movsxdifnidn   lum_strideq, lum_strided
+    movsxdifnidn chrom_strideq, chrom_strided
+    movsxdifnidn   src_strideq, src_strided
+
+    mov     back_wq, wq
+    mov      whalfq, wq
+    shr      whalfq, 1     ; whalf = width / 2
+
+    lea srcq, [srcq + wq * 2]
+    add    ydstq, wq
+    add    udstq, whalfq
+    add    vdstq, whalfq
+
+.loop_line:
+    mov          xq, wq
+    mov       wtwoq, wq
+    add       wtwoq, wtwoq ; wtwo = width * 2
+
+    neg       wq
+    neg    wtwoq
+    neg   whalfq
+
+    ;calc scalar loop count
+    and       xq, mmsize * 2 - 1
+    je .loop_simd
+
+%if mmsize == 64
+    shr     xq, 1
+    mov   tmpq, -1
+    shlx  tmpq, tmpq, xq
+    not   tmpq
+    kmovq   k7, tmpq ; write mask for U/V
+    kmovd   k1, tmpd ; write mask for 1st half of Y
+    kmovw   k3, tmpd ; read mask for 1st vector
+    shr   tmpq, 16
+    kmovw   k4, tmpd ; read mask for 2nd vector
+    shr   tmpq, 16
+    kmovd   k2, tmpd ; write mask for 2nd half of Y
+    kmovw   k5, tmpd ; read mask for 3rd vector
+    shr   tmpd, 16
+    kmovw   k6, tmpd ; read mask for 4th vector
+
+    vmovdqu32  m2{k3}{z}, [srcq + wtwoq             ]
+    vmovdqu32  m3{k4}{z}, [srcq + wtwoq + mmsize    ]
+    vmovdqu32  m4{k5}{z}, [srcq + wtwoq + mmsize * 2]
+    vmovdqu32  m5{k6}{z}, [srcq + wtwoq + mmsize * 3]
+
+    ; extract y part 1
+    mova                             m6, m9
+    vpermi2b                         m6, m2, m3 ; UYVY UYVY -> YYYY using permute
+    vmovdqu16          [ydstq + wq]{k1}, m6
+
+    ; extract y part 2
+    mova                             m7, m9
+    vpermi2b                         m7, m4, m5 ; UYVY UYVY -> YYYY using permute
+    vmovdqu16 [ydstq + wq + mmsize]{k2}, m7
+
+    ; extract uv
+    pand                         m2, m1     ; UxVx...
+    pand                         m3, m1     ; UxVx...
+    pand                         m4, m1     ; UxVx...
+    pand                         m5, m1     ; UxVx...
+    packuswb                     m2, m3     ; UVUV...
+    packuswb                     m4, m5     ; UVUV...
+
+    ; U
+    pand                         m6, m2, m1 ; UxUx...
+    pand                         m7, m4, m1 ; UxUx...
+    packuswb                     m6, m7     ; UUUU
+    vpermb                       m6, m8, m6
+    vmovdqu8   [udstq + whalfq]{k7}, m6
+
+    ; V
+    psrlw                        m2, 8      ; VxVx...
+    psrlw                        m4, 8      ; VxVx...
+    packuswb                     m2, m4     ; VVVV
+    vpermb                       m2, m8, m2
+    vmovdqu8   [vdstq + whalfq]{k7}, m2
+
+    lea      wq, [   wq + 2 * xq]
+    lea   wtwoq, [wtwoq + 4 * xq]
+    add  whalfq, xq
+%else
+    .loop_scalar:
+        mov             tmpb, [srcq + wtwoq + 0]
+        mov [udstq + whalfq], tmpb
+
+        mov             tmpb, [srcq + wtwoq + 1]
+        mov     [ydstq + wq], tmpb
+
+        mov             tmpb, [srcq + wtwoq + 2]
+        mov [vdstq + whalfq], tmpb
+
+        mov             tmpb, [srcq + wtwoq + 3]
+        mov [ydstq + wq + 1], tmpb
+
+        add      wq, 2
+        add   wtwoq, 4
+        add  whalfq, 1
+        sub      xq, 2
+        jg .loop_scalar
+%endif
+
+    ; check if simd loop is need
+    cmp      wq, 0
+    jge .end_line
+
+    .loop_simd:
+        movu    m2, [srcq + wtwoq             ]
+        movu    m3, [srcq + wtwoq + mmsize    ]
+        movu    m4, [srcq + wtwoq + mmsize * 2]
+        movu    m5, [srcq + wtwoq + mmsize * 3]
+
+%if mmsize == 64
+        ; extract y part 1
+        mova                    m6, m9
+        vpermi2b                m6, m2, m3 ; UYVY UYVY -> YYYY using permute
+        movu          [ydstq + wq], m6
+
+        ; extract y part 2
+        mova                    m7, m9
+        vpermi2b                m7, m4, m5 ; UYVY UYVY -> YYYY using permute
+        movu [ydstq + wq + mmsize], m7
+%else
+        ; extract y part 1
+        RSHIFT_COPY    m6, m2, 1 ; UYVY UYVY -> YVYU YVY...
+        pand           m6, m1    ; YxYx YxYx...
+
+        RSHIFT_COPY    m7, m3, 1 ; UYVY UYVY -> YVYU YVY...
+        pand           m7, m1    ; YxYx YxYx...
+
+        packuswb       m6, m7    ; YYYY YYYY...
+%if mmsize == 32
+        vpermq         m6, m6, 0xd8
+%endif
+        movu [ydstq + wq], m6
+
+        ; extract y part 2
+        RSHIFT_COPY    m6, m4, 1 ; UYVY UYVY -> YVYU YVY...
+        pand           m6, m1    ; YxYx YxYx...
+
+        RSHIFT_COPY    m7, m5, 1 ; UYVY UYVY -> YVYU YVY...
+        pand           m7, m1    ; YxYx YxYx...
+
+        packuswb       m6, m7    ; YYYY YYYY...
+%if mmsize == 32
+        vpermq         m6, m6, 0xd8
+%endif
+        movu [ydstq + wq + mmsize], m6
+%endif
+
+        ; extract uv
+        pand       m2, m1   ; UxVx...
+        pand       m3, m1   ; UxVx...
+        pand       m4, m1   ; UxVx...
+        pand       m5, m1   ; UxVx...
+
+        packuswb   m2, m3   ; UVUV...
+        packuswb   m4, m5   ; UVUV...
+
+        ; U
+        pand       m6, m2, m1 ; UxUx...
+        pand       m7, m4, m1 ; UxUx...
+
+        packuswb m6, m7 ; UUUU
+%if mmsize == 64
+        vpermb   m6, m8, m6
+%elif mmsize == 32
+        vpermd   m6, m8, m6
+%endif
+        movu   [udstq + whalfq], m6
+
+
+        ; V
+        psrlw      m2, 8  ; VxVx...
+        psrlw      m4, 8  ; VxVx...
+        packuswb   m2, m4 ; VVVV
+%if mmsize == 64
+        vpermb     m2, m8, m2
+%elif mmsize == 32
+        vpermd     m2, m8, m2
+%endif
+        movu   [vdstq + whalfq], m2
+
+        add   whalfq, mmsize
+        add    wtwoq, mmsize * 4
+        add       wq, mmsize * 2
+        jl .loop_simd
+
+    .end_line:
+        add        srcq, src_strideq
+        add        ydstq, lum_strideq
+        add        udstq, chrom_strideq
+        add        vdstq, chrom_strideq
+
+        ;restore initial state of line variable
+        mov           wq, back_wq
+        mov          xq, wq
+        mov      whalfq, wq
+        shr      whalfq, 1     ; whalf = width / 2
+        sub          hd, 1
+        jg .loop_line
+
+    RET
+%endmacro
+
+%if ARCH_X86_64
+INIT_XMM sse2
+UYVY_TO_YUV422
+
+INIT_XMM avx
+UYVY_TO_YUV422
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+UYVY_TO_YUV422
+%endif
+%if HAVE_AVX512ICL_EXTERNAL
+INIT_ZMM avx512icl
+UYVY_TO_YUV422
+%endif
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/scale.asm b/libs/ffmpeg/libswscale/x86/scale.asm
new file mode 100644
index 000000000000..85a96dc57e4b
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/scale.asm
@@ -0,0 +1,389 @@
+;******************************************************************************
+;* x86-optimized horizontal line scaling functions
+;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@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/x86/x86util.asm"
+
+SECTION_RODATA
+
+max_19bit_int: times 4 dd 0x7ffff
+minshort:      times 8 dw 0x8000
+unicoeff:      times 4 dd 0x20000000
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; horizontal line scaling
+;
+; void hscale<source_width>to<intermediate_nbits>_<filterSize>_<opt>
+;                               (SwsInternal *c, int{16,32}_t *dst,
+;                                int dstW, const uint{8,16}_t *src,
+;                                const int16_t *filter,
+;                                const int32_t *filterPos, int filterSize);
+;
+; Scale one horizontal line. Input is either 8-bit width or 16-bit width
+; ($source_width can be either 8, 9, 10 or 16, difference is whether we have to
+; downscale before multiplying). Filter is 14 bits. Output is either 15 bits
+; (in int16_t) or 19 bits (in int32_t), as given in $intermediate_nbits. Each
+; output pixel is generated from $filterSize input pixels, the position of
+; the first pixel is given in filterPos[nOutputPixel].
+;-----------------------------------------------------------------------------
+
+; SCALE_FUNC source_width, intermediate_nbits, filtersize, filtersuffix, n_args, n_xmm
+%macro SCALE_FUNC 6
+%ifnidn %3, X
+cglobal hscale%1to%2_%4, %5, 7, %6, pos0, dst, w, src, filter, fltpos, pos1
+%else
+cglobal hscale%1to%2_%4, %5, 10, %6, pos0, dst, w, srcmem, filter, fltpos, fltsize
+%endif
+%if ARCH_X86_64
+    movsxd        wq, wd
+%define mov32 movsxd
+%else ; x86-32
+%define mov32 mov
+%endif ; x86-64
+%if %2 == 19
+    mova          m2, [max_19bit_int]
+%endif ; %2 == 19
+%if %1 == 16
+    mova          m6, [minshort]
+    mova          m7, [unicoeff]
+%elif %1 == 8
+    pxor          m3, m3
+%endif ; %1 == 8/16
+
+%if %1 == 8
+%define movlh movd
+%define movbh movh
+%define srcmul 1
+%else ; %1 == 9-16
+%define movlh movq
+%define movbh movu
+%define srcmul 2
+%endif ; %1 == 8/9-16
+
+%ifnidn %3, X
+
+    ; setup loop
+%if %3 == 8
+    shl           wq, 1                         ; this allows *16 (i.e. now *8) in lea instructions for the 8-tap filter
+%define wshr 1
+%else ; %3 == 4
+%define wshr 0
+%endif ; %3 == 8
+    lea      filterq, [filterq+wq*8]
+%if %2 == 15
+    lea         dstq, [dstq+wq*(2>>wshr)]
+%else ; %2 == 19
+    lea         dstq, [dstq+wq*(4>>wshr)]
+%endif ; %2 == 15/19
+    lea      fltposq, [fltposq+wq*(4>>wshr)]
+    neg           wq
+
+.loop:
+%if %3 == 4 ; filterSize == 4 scaling
+    ; load 2x4 or 4x4 source pixels into m0/m1
+    mov32      pos0q, dword [fltposq+wq*4+ 0]   ; filterPos[0]
+    mov32      pos1q, dword [fltposq+wq*4+ 4]   ; filterPos[1]
+    movlh         m0, [srcq+pos0q*srcmul]       ; src[filterPos[0] + {0,1,2,3}]
+%if mmsize == 8
+    movlh         m1, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
+%else ; mmsize == 16
+%if %1 > 8
+    movhps        m0, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
+%else ; %1 == 8
+    movd          m4, [srcq+pos1q*srcmul]       ; src[filterPos[1] + {0,1,2,3}]
+%endif
+    mov32      pos0q, dword [fltposq+wq*4+ 8]   ; filterPos[2]
+    mov32      pos1q, dword [fltposq+wq*4+12]   ; filterPos[3]
+    movlh         m1, [srcq+pos0q*srcmul]       ; src[filterPos[2] + {0,1,2,3}]
+%if %1 > 8
+    movhps        m1, [srcq+pos1q*srcmul]       ; src[filterPos[3] + {0,1,2,3}]
+%else ; %1 == 8
+    movd          m5, [srcq+pos1q*srcmul]       ; src[filterPos[3] + {0,1,2,3}]
+    punpckldq     m0, m4
+    punpckldq     m1, m5
+%endif ; %1 == 8
+%endif ; mmsize == 8/16
+%if %1 == 8
+    punpcklbw     m0, m3                        ; byte -> word
+    punpcklbw     m1, m3                        ; byte -> word
+%endif ; %1 == 8
+
+    ; multiply with filter coefficients
+%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
+             ; add back 0x8000 * sum(coeffs) after the horizontal add
+    psubw         m0, m6
+    psubw         m1, m6
+%endif ; %1 == 16
+    pmaddwd       m0, [filterq+wq*8+mmsize*0]   ; *= filter[{0,1,..,6,7}]
+    pmaddwd       m1, [filterq+wq*8+mmsize*1]   ; *= filter[{8,9,..,14,15}]
+
+    ; add up horizontally (4 srcpix * 4 coefficients -> 1 dstpix)
+%if notcpuflag(ssse3) ; sse2
+    mova          m4, m0
+    shufps        m0, m1, 10001000b
+    shufps        m4, m1, 11011101b
+    paddd         m0, m4
+%else ; ssse3/sse4
+    phaddd        m0, m1                        ; filter[{ 0, 1, 2, 3}]*src[filterPos[0]+{0,1,2,3}],
+                                                ; filter[{ 4, 5, 6, 7}]*src[filterPos[1]+{0,1,2,3}],
+                                                ; filter[{ 8, 9,10,11}]*src[filterPos[2]+{0,1,2,3}],
+                                                ; filter[{12,13,14,15}]*src[filterPos[3]+{0,1,2,3}]
+%endif ; sse2/ssse3/sse4
+%else ; %3 == 8, i.e. filterSize == 8 scaling
+    ; load 2x8 or 4x8 source pixels into m0, m1, m4 and m5
+    mov32      pos0q, dword [fltposq+wq*2+0]    ; filterPos[0]
+    mov32      pos1q, dword [fltposq+wq*2+4]    ; filterPos[1]
+    movbh         m0, [srcq+ pos0q   *srcmul]   ; src[filterPos[0] + {0,1,2,3,4,5,6,7}]
+%if mmsize == 8
+    movbh         m1, [srcq+(pos0q+4)*srcmul]   ; src[filterPos[0] + {4,5,6,7}]
+    movbh         m4, [srcq+ pos1q   *srcmul]   ; src[filterPos[1] + {0,1,2,3}]
+    movbh         m5, [srcq+(pos1q+4)*srcmul]   ; src[filterPos[1] + {4,5,6,7}]
+%else ; mmsize == 16
+    movbh         m1, [srcq+ pos1q   *srcmul]   ; src[filterPos[1] + {0,1,2,3,4,5,6,7}]
+    mov32      pos0q, dword [fltposq+wq*2+8]    ; filterPos[2]
+    mov32      pos1q, dword [fltposq+wq*2+12]   ; filterPos[3]
+    movbh         m4, [srcq+ pos0q   *srcmul]   ; src[filterPos[2] + {0,1,2,3,4,5,6,7}]
+    movbh         m5, [srcq+ pos1q   *srcmul]   ; src[filterPos[3] + {0,1,2,3,4,5,6,7}]
+%endif ; mmsize == 8/16
+%if %1 == 8
+    punpcklbw     m0, m3                        ; byte -> word
+    punpcklbw     m1, m3                        ; byte -> word
+    punpcklbw     m4, m3                        ; byte -> word
+    punpcklbw     m5, m3                        ; byte -> word
+%endif ; %1 == 8
+
+    ; multiply
+%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
+             ; add back 0x8000 * sum(coeffs) after the horizontal add
+    psubw         m0, m6
+    psubw         m1, m6
+    psubw         m4, m6
+    psubw         m5, m6
+%endif ; %1 == 16
+    pmaddwd       m0, [filterq+wq*8+mmsize*0]   ; *= filter[{0,1,..,6,7}]
+    pmaddwd       m1, [filterq+wq*8+mmsize*1]   ; *= filter[{8,9,..,14,15}]
+    pmaddwd       m4, [filterq+wq*8+mmsize*2]   ; *= filter[{16,17,..,22,23}]
+    pmaddwd       m5, [filterq+wq*8+mmsize*3]   ; *= filter[{24,25,..,30,31}]
+
+    ; add up horizontally (8 srcpix * 8 coefficients -> 1 dstpix)
+%if notcpuflag(ssse3) ; sse2
+%if %1 == 8
+%define mex m6
+%else
+%define mex m3
+%endif
+    ; emulate horizontal add as transpose + vertical add
+    mova         mex, m0
+    punpckldq     m0, m1
+    punpckhdq    mex, m1
+    paddd         m0, mex
+    mova          m1, m4
+    punpckldq     m4, m5
+    punpckhdq     m1, m5
+    paddd         m4, m1
+    mova          m1, m0
+    punpcklqdq    m0, m4
+    punpckhqdq    m1, m4
+    paddd         m0, m1
+%else ; ssse3/sse4
+    ; FIXME if we rearrange the filter in pairs of 4, we can
+    ; load pixels likewise and use 2 x paddd + phaddd instead
+    ; of 3 x phaddd here, faster on older cpus
+    phaddd        m0, m1
+    phaddd        m4, m5
+    phaddd        m0, m4                        ; filter[{ 0, 1,..., 6, 7}]*src[filterPos[0]+{0,1,...,6,7}],
+                                                ; filter[{ 8, 9,...,14,15}]*src[filterPos[1]+{0,1,...,6,7}],
+                                                ; filter[{16,17,...,22,23}]*src[filterPos[2]+{0,1,...,6,7}],
+                                                ; filter[{24,25,...,30,31}]*src[filterPos[3]+{0,1,...,6,7}]
+%endif ; sse2/ssse3/sse4
+%endif ; %3 == 4/8
+
+%else ; %3 == X, i.e. any filterSize scaling
+
+%ifidn %4, X4
+%define dlt 4
+%else ; %4 == X || %4 == X8
+%define dlt 0
+%endif ; %4 ==/!= X4
+%if ARCH_X86_64
+%define srcq    r8
+%define pos1q   r7
+%define srcendq r9
+    movsxd  fltsizeq, fltsized                  ; filterSize
+    lea      srcendq, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
+%else ; x86-32
+%define srcq    srcmemq
+%define pos1q   dstq
+%define srcendq r6m
+    lea        pos0q, [srcmemq+(fltsizeq-dlt)*srcmul] ; &src[filterSize&~4]
+    mov      srcendq, pos0q
+%endif ; x86-32/64
+    lea      fltposq, [fltposq+wq*4]
+%if %2 == 15
+    lea         dstq, [dstq+wq*2]
+%else ; %2 == 19
+    lea         dstq, [dstq+wq*4]
+%endif ; %2 == 15/19
+    movifnidn  dstmp, dstq
+    neg           wq
+
+.loop:
+    mov32      pos0q, dword [fltposq+wq*4+0]    ; filterPos[0]
+    mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
+    ; FIXME maybe do 4px/iteration on x86-64 (x86-32 wouldn't have enough regs)?
+    pxor          m4, m4
+    pxor          m5, m5
+    mov         srcq, srcmemmp
+
+.innerloop:
+    ; load 2x8 (sse) source pixels into m0/m1 -> m4/m5
+    movbh         m0, [srcq+ pos0q     *srcmul] ; src[filterPos[0] + {0,1,2,3(,4,5,6,7)}]
+    movbh         m1, [srcq+(pos1q+dlt)*srcmul] ; src[filterPos[1] + {0,1,2,3(,4,5,6,7)}]
+%if %1 == 8
+    punpcklbw     m0, m3
+    punpcklbw     m1, m3
+%endif ; %1 == 8
+
+    ; multiply
+%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
+             ; add back 0x8000 * sum(coeffs) after the horizontal add
+    psubw         m0, m6
+    psubw         m1, m6
+%endif ; %1 == 16
+    pmaddwd       m0, [filterq]                 ; filter[{0,1,2,3(,4,5,6,7)}]
+    pmaddwd       m1, [filterq+(fltsizeq+dlt)*2]; filter[filtersize+{0,1,2,3(,4,5,6,7)}]
+    paddd         m4, m0
+    paddd         m5, m1
+    add      filterq, mmsize
+    add         srcq, srcmul*mmsize/2
+    cmp         srcq, srcendq                   ; while (src += 4) < &src[filterSize]
+    jl .innerloop
+
+%ifidn %4, X4
+    mov32      pos1q, dword [fltposq+wq*4+4]    ; filterPos[1]
+    movlh         m0, [srcq+ pos0q     *srcmul] ; split last 4 srcpx of dstpx[0]
+    sub        pos1q, fltsizeq                  ; and first 4 srcpx of dstpx[1]
+%if %1 > 8
+    movhps        m0, [srcq+(pos1q+dlt)*srcmul]
+%else ; %1 == 8
+    movd          m1, [srcq+(pos1q+dlt)*srcmul]
+    punpckldq     m0, m1
+%endif ; %1 == 8
+%if %1 == 8
+    punpcklbw     m0, m3
+%endif ; %1 == 8
+%if %1 == 16 ; pmaddwd needs signed adds, so this moves unsigned -> signed, we'll
+             ; add back 0x8000 * sum(coeffs) after the horizontal add
+    psubw         m0, m6
+%endif ; %1 == 16
+    pmaddwd       m0, [filterq]
+%endif ; %4 == X4
+
+    lea      filterq, [filterq+(fltsizeq+dlt)*2]
+
+%if notcpuflag(ssse3) ; sse2
+    mova          m1, m4
+    punpcklqdq    m4, m5
+    punpckhqdq    m1, m5
+    paddd         m4, m1
+%else ; ssse3/sse4
+    phaddd        m4, m5
+%endif ; sse2/ssse3/sse4
+%ifidn %4, X4
+    paddd         m4, m0
+%endif ; %3 == X4
+%if notcpuflag(ssse3) ; sse2
+    pshufd        m4, m4, 11011000b
+    movhlps       m0, m4
+    paddd         m0, m4
+%else ; ssse3/sse4
+    phaddd        m4, m4
+    SWAP           0, 4
+%endif ; sse2/ssse3/sse4
+%endif ; %3 ==/!= X
+
+%if %1 == 16 ; add 0x8000 * sum(coeffs), i.e. back from signed -> unsigned
+    paddd         m0, m7
+%endif ; %1 == 16
+
+    ; clip, store
+    psrad         m0, 14 + %1 - %2
+%ifidn %3, X
+    movifnidn   dstq, dstmp
+%endif ; %3 == X
+%if %2 == 15
+    packssdw      m0, m0
+%ifnidn %3, X
+    movh [dstq+wq*(2>>wshr)], m0
+%else ; %3 == X
+    movd [dstq+wq*2], m0
+%endif ; %3 ==/!= X
+%else ; %2 == 19
+    PMINSD        m0, m2, m4
+%ifnidn %3, X
+    mova [dstq+wq*(4>>wshr)], m0
+%else ; %3 == X
+    movq [dstq+wq*4], m0
+%endif ; %3 ==/!= X
+%endif ; %2 == 15/19
+%ifnidn %3, X
+    add           wq, (mmsize<<wshr)/4          ; both 8tap and 4tap really only do 4 pixels
+                                                ; per iteration. see "shl wq,1" above as for why we do this
+%else ; %3 == X
+    add           wq, 2
+%endif ; %3 ==/!= X
+    jl .loop
+    RET
+%endmacro
+
+; SCALE_FUNCS source_width, intermediate_nbits, n_xmm
+%macro SCALE_FUNCS 3
+SCALE_FUNC %1, %2, 4, 4,  6, %3
+SCALE_FUNC %1, %2, 8, 8,  6, %3
+SCALE_FUNC %1, %2, X, X4, 7, %3
+SCALE_FUNC %1, %2, X, X8, 7, %3
+%endmacro
+
+; SCALE_FUNCS2 8_xmm_args, 9to10_xmm_args, 16_xmm_args
+%macro SCALE_FUNCS2 3
+%if notcpuflag(sse4)
+SCALE_FUNCS  8, 15, %1
+SCALE_FUNCS  9, 15, %2
+SCALE_FUNCS 10, 15, %2
+SCALE_FUNCS 12, 15, %2
+SCALE_FUNCS 14, 15, %2
+SCALE_FUNCS 16, 15, %3
+%endif ; !sse4
+SCALE_FUNCS  8, 19, %1
+SCALE_FUNCS  9, 19, %2
+SCALE_FUNCS 10, 19, %2
+SCALE_FUNCS 12, 19, %2
+SCALE_FUNCS 14, 19, %2
+SCALE_FUNCS 16, 19, %3
+%endmacro
+
+INIT_XMM sse2
+SCALE_FUNCS2 7, 6, 8
+INIT_XMM ssse3
+SCALE_FUNCS2 6, 6, 8
+INIT_XMM sse4
+SCALE_FUNCS2 6, 6, 8
diff --git a/libs/ffmpeg/libswscale/x86/scale_avx2.asm b/libs/ffmpeg/libswscale/x86/scale_avx2.asm
new file mode 100644
index 000000000000..b4b852d60bb1
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/scale_avx2.asm
@@ -0,0 +1,156 @@
+;******************************************************************************
+;* x86-optimized horizontal line scaling functions
+;* Copyright 2020 Google LLC
+;* Copyright (c) 2011 Ronald S. Bultje <rsbultje@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/x86/x86util.asm"
+
+SECTION_RODATA 32
+
+swizzle: dd 0, 4, 1, 5, 2, 6, 3, 7
+four: times 8 dd 4
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; horizontal line scaling
+;
+; void hscale8to15_<filterSize>_<opt>
+;                   (SwsInternal *c, int16_t *dst,
+;                    int dstW, const uint8_t *src,
+;                    const int16_t *filter,
+;                    const int32_t *filterPos, int filterSize);
+;
+; Scale one horizontal line. Input is 8-bit width Filter is 14 bits. Output is
+; 15 bits (in int16_t). Each output pixel is generated from $filterSize input
+; pixels, the position of the first pixel is given in filterPos[nOutputPixel].
+;-----------------------------------------------------------------------------
+
+%macro SCALE_FUNC 1
+cglobal hscale8to15_%1, 7, 9, 16, pos0, dst, w, srcmem, filter, fltpos, fltsize, count, inner
+    pxor m0, m0
+    mova m15, [swizzle]
+    xor countq, countq
+    movsxd wq, wd
+%ifidn %1, X4
+    mova m14, [four]
+    shr fltsized, 2
+%endif
+    cmp wq, 0x10
+    jl .tail_loop
+    sub wq, 0x10
+.loop:
+    movu m1, [fltposq]
+    movu m2, [fltposq+32]
+%ifidn %1, X4
+    pxor m9, m9
+    pxor m10, m10
+    pxor m11, m11
+    pxor m12, m12
+    xor innerq, innerq
+.innerloop:
+%endif
+    vpcmpeqd  m13, m13
+    vpgatherdd m3,[srcmemq + m1], m13
+    vpcmpeqd  m13, m13
+    vpgatherdd m4,[srcmemq + m2], m13
+    vpunpcklbw m5, m3, m0
+    vpunpckhbw m6, m3, m0
+    vpunpcklbw m7, m4, m0
+    vpunpckhbw m8, m4, m0
+    vpmaddwd m5, m5, [filterq]
+    vpmaddwd m6, m6, [filterq + 32]
+    vpmaddwd m7, m7, [filterq + 64]
+    vpmaddwd m8, m8, [filterq + 96]
+    add filterq, 0x80
+%ifidn %1, X4
+    paddd m9, m5
+    paddd m10, m6
+    paddd m11, m7
+    paddd m12, m8
+    paddd m1, m14
+    paddd m2, m14
+    add innerq, 1
+    cmp innerq, fltsizeq
+    jl .innerloop
+    vphaddd m5, m9, m10
+    vphaddd m6, m11, m12
+%else
+    vphaddd m5, m5, m6
+    vphaddd m6, m7, m8
+%endif
+    vpsrad  m5, 7
+    vpsrad  m6, 7
+    vpackssdw m5, m5, m6
+    vpermd m5, m15, m5
+    vmovdqu [dstq + countq * 2], m5
+    add fltposq, 0x40
+    add countq, 0x10
+    cmp countq, wq
+    jle .loop
+
+    add wq, 0x10
+    cmp countq, wq
+    jge .end
+
+.tail_loop:
+    movu xm1, [fltposq]
+%ifidn %1, X4
+    pxor xm9, xm9
+    pxor xm10, xm10
+    xor innerq, innerq
+.tail_innerloop:
+%endif
+    vpcmpeqd  xm13, xm13
+    vpgatherdd xm3,[srcmemq + xm1], xm13
+    vpunpcklbw xm5, xm3, xm0
+    vpunpckhbw xm6, xm3, xm0
+    vpmaddwd xm5, xm5, [filterq]
+    vpmaddwd xm6, xm6, [filterq + 0x10]
+    add filterq, 0x20
+%ifidn %1, X4
+    paddd xm9, xm5
+    paddd xm10, xm6
+    paddd xm1, xm14
+    add innerq, 1
+    cmp innerq, fltsizeq
+    jl .tail_innerloop
+    vphaddd xm5, xm9, xm10
+%else
+    vphaddd xm5, xm5, xm6
+%endif
+    vpsrad  xm5, 7
+    vpackssdw xm5, xm5, xm5
+    vmovq [dstq + countq * 2], xm5
+    add fltposq, 0x10
+    add countq, 0x4
+    cmp countq, wq
+    jl .tail_loop
+.end:
+RET
+%endmacro
+
+%if ARCH_X86_64
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+SCALE_FUNC 4
+SCALE_FUNC X4
+%endif
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/swscale.c b/libs/ffmpeg/libswscale/x86/swscale.c
new file mode 100644
index 000000000000..00fdd44f7056
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/swscale.c
@@ -0,0 +1,858 @@
+/*
+ * 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <inttypes.h>
+#include "config.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/attributes.h"
+#include "libavutil/avassert.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/cpu.h"
+#include "libavutil/mem_internal.h"
+#include "libavutil/pixdesc.h"
+
+const DECLARE_ALIGNED(8, uint64_t, ff_dither4)[2] = {
+    0x0103010301030103LL,
+    0x0200020002000200LL,};
+
+const DECLARE_ALIGNED(8, uint64_t, ff_dither8)[2] = {
+    0x0602060206020602LL,
+    0x0004000400040004LL,};
+
+#if HAVE_INLINE_ASM
+
+DECLARE_ASM_CONST(8, uint64_t, bF8)=       0xF8F8F8F8F8F8F8F8LL;
+DECLARE_ASM_CONST(8, uint64_t, bFC)=       0xFCFCFCFCFCFCFCFCLL;
+
+DECLARE_ASM_CONST(8, uint64_t, M24A) = 0x00FF0000FF0000FFLL;
+DECLARE_ASM_CONST(8, uint64_t, M24B) = 0xFF0000FF0000FF00LL;
+DECLARE_ASM_CONST(8, uint64_t, M24C) = 0x0000FF0000FF0000LL;
+
+// MMXEXT versions
+#if HAVE_MMXEXT_INLINE
+#undef RENAME
+#undef COMPILE_TEMPLATE_MMXEXT
+#define COMPILE_TEMPLATE_MMXEXT 1
+#define RENAME(a) a ## _mmxext
+#include "swscale_template.c"
+#endif
+
+void ff_updateMMXDitherTables(SwsInternal *c, int dstY)
+{
+    const int dstH= c->opts.dst_h;
+    const int flags= c->opts.flags;
+
+    SwsPlane *lumPlane = &c->slice[c->numSlice-2].plane[0];
+    SwsPlane *chrUPlane = &c->slice[c->numSlice-2].plane[1];
+    SwsPlane *alpPlane = &c->slice[c->numSlice-2].plane[3];
+
+    int hasAlpha = c->needAlpha;
+    int32_t *vLumFilterPos= c->vLumFilterPos;
+    int32_t *vChrFilterPos= c->vChrFilterPos;
+    int16_t *vLumFilter= c->vLumFilter;
+    int16_t *vChrFilter= c->vChrFilter;
+    int32_t *lumMmxFilter= c->lumMmxFilter;
+    int32_t *chrMmxFilter= c->chrMmxFilter;
+    av_unused int32_t *alpMmxFilter= c->alpMmxFilter;
+    const int vLumFilterSize= c->vLumFilterSize;
+    const int vChrFilterSize= c->vChrFilterSize;
+    const int chrDstY= dstY>>c->chrDstVSubSample;
+    const int firstLumSrcY= vLumFilterPos[dstY]; //First line needed as input
+    const int firstChrSrcY= vChrFilterPos[chrDstY]; //First line needed as input
+
+    c->blueDither= ff_dither8[dstY&1];
+    if (c->opts.dst_format == AV_PIX_FMT_RGB555 || c->opts.dst_format == AV_PIX_FMT_BGR555)
+        c->greenDither= ff_dither8[dstY&1];
+    else
+        c->greenDither= ff_dither4[dstY&1];
+    c->redDither= ff_dither8[(dstY+1)&1];
+    if (dstY < dstH - 2) {
+        const int16_t **lumSrcPtr  = (const int16_t **)(void*) lumPlane->line + firstLumSrcY - lumPlane->sliceY;
+        const int16_t **chrUSrcPtr = (const int16_t **)(void*) chrUPlane->line + firstChrSrcY - chrUPlane->sliceY;
+        const int16_t **alpSrcPtr  = (CONFIG_SWSCALE_ALPHA && hasAlpha) ? (const int16_t **)(void*) alpPlane->line + firstLumSrcY - alpPlane->sliceY : NULL;
+
+        int i;
+        if (firstLumSrcY < 0 || firstLumSrcY + vLumFilterSize > c->opts.src_h) {
+            const int16_t **tmpY = (const int16_t **) lumPlane->tmp;
+
+            int neg = -firstLumSrcY, i, end = FFMIN(c->opts.src_h - firstLumSrcY, vLumFilterSize);
+            for (i = 0; i < neg;            i++)
+                tmpY[i] = lumSrcPtr[neg];
+            for (     ; i < end;            i++)
+                tmpY[i] = lumSrcPtr[i];
+            for (     ; i < vLumFilterSize; i++)
+                tmpY[i] = tmpY[i-1];
+            lumSrcPtr = tmpY;
+
+            if (alpSrcPtr) {
+                const int16_t **tmpA = (const int16_t **) alpPlane->tmp;
+                for (i = 0; i < neg;            i++)
+                    tmpA[i] = alpSrcPtr[neg];
+                for (     ; i < end;            i++)
+                    tmpA[i] = alpSrcPtr[i];
+                for (     ; i < vLumFilterSize; i++)
+                    tmpA[i] = tmpA[i - 1];
+                alpSrcPtr = tmpA;
+            }
+        }
+        if (firstChrSrcY < 0 || firstChrSrcY + vChrFilterSize > c->chrSrcH) {
+            const int16_t **tmpU = (const int16_t **) chrUPlane->tmp;
+            int neg = -firstChrSrcY, i, end = FFMIN(c->chrSrcH - firstChrSrcY, vChrFilterSize);
+            for (i = 0; i < neg;            i++) {
+                tmpU[i] = chrUSrcPtr[neg];
+            }
+            for (     ; i < end;            i++) {
+                tmpU[i] = chrUSrcPtr[i];
+            }
+            for (     ; i < vChrFilterSize; i++) {
+                tmpU[i] = tmpU[i - 1];
+            }
+            chrUSrcPtr = tmpU;
+        }
+
+        if (flags & SWS_ACCURATE_RND) {
+            int s= APCK_SIZE / 8;
+            for (i=0; i<vLumFilterSize; i+=2) {
+                *(const void**)&lumMmxFilter[s*i              ]= lumSrcPtr[i  ];
+                *(const void**)&lumMmxFilter[s*i+APCK_PTR2/4  ]= lumSrcPtr[i+(vLumFilterSize>1)];
+                lumMmxFilter[s*i+APCK_COEF/4  ]=
+                lumMmxFilter[s*i+APCK_COEF/4+1]= vLumFilter[dstY*vLumFilterSize + i    ]
+                    + (vLumFilterSize>1 ? vLumFilter[dstY*vLumFilterSize + i + 1] * (1 << 16) : 0);
+                if (CONFIG_SWSCALE_ALPHA && hasAlpha) {
+                    *(const void**)&alpMmxFilter[s*i              ]= alpSrcPtr[i  ];
+                    *(const void**)&alpMmxFilter[s*i+APCK_PTR2/4  ]= alpSrcPtr[i+(vLumFilterSize>1)];
+                    alpMmxFilter[s*i+APCK_COEF/4  ]=
+                    alpMmxFilter[s*i+APCK_COEF/4+1]= lumMmxFilter[s*i+APCK_COEF/4  ];
+                }
+            }
+            for (i=0; i<vChrFilterSize; i+=2) {
+                *(const void**)&chrMmxFilter[s*i              ]= chrUSrcPtr[i  ];
+                *(const void**)&chrMmxFilter[s*i+APCK_PTR2/4  ]= chrUSrcPtr[i+(vChrFilterSize>1)];
+                chrMmxFilter[s*i+APCK_COEF/4  ]=
+                chrMmxFilter[s*i+APCK_COEF/4+1]= vChrFilter[chrDstY*vChrFilterSize + i    ]
+                    + (vChrFilterSize>1 ? vChrFilter[chrDstY*vChrFilterSize + i + 1] * (1 << 16) : 0);
+            }
+        } else {
+            for (i=0; i<vLumFilterSize; i++) {
+                *(const void**)&lumMmxFilter[4*i+0]= lumSrcPtr[i];
+                lumMmxFilter[4*i+2]=
+                lumMmxFilter[4*i+3]=
+                ((uint16_t)vLumFilter[dstY*vLumFilterSize + i])*0x10001U;
+                if (CONFIG_SWSCALE_ALPHA && hasAlpha) {
+                    *(const void**)&alpMmxFilter[4*i+0]= alpSrcPtr[i];
+                    alpMmxFilter[4*i+2]=
+                    alpMmxFilter[4*i+3]= lumMmxFilter[4*i+2];
+                }
+            }
+            for (i=0; i<vChrFilterSize; i++) {
+                *(const void**)&chrMmxFilter[4*i+0]= chrUSrcPtr[i];
+                chrMmxFilter[4*i+2]=
+                chrMmxFilter[4*i+3]=
+                ((uint16_t)vChrFilter[chrDstY*vChrFilterSize + i])*0x10001U;
+            }
+        }
+    }
+}
+#endif /* HAVE_INLINE_ASM */
+
+#define YUV2YUVX_FUNC_MMX(opt, step)  \
+void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
+                           uint8_t *dest, int dstW,  \
+                           const uint8_t *dither, int offset); \
+static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, \
+                           const int16_t **src, uint8_t *dest, int dstW, \
+                           const uint8_t *dither, int offset) \
+{ \
+    if(dstW > 0) \
+        ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, dstW + offset, dither, offset); \
+    return; \
+}
+
+#define YUV2YUVX_FUNC(opt, step)  \
+void ff_yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, int srcOffset, \
+                           uint8_t *dest, int dstW,  \
+                           const uint8_t *dither, int offset); \
+static void yuv2yuvX_ ##opt(const int16_t *filter, int filterSize, \
+                           const int16_t **src, uint8_t *dest, int dstW, \
+                           const uint8_t *dither, int offset) \
+{ \
+    int remainder = (dstW % step); \
+    int pixelsProcessed = dstW - remainder; \
+    if(((uintptr_t)dest) & 15){ \
+        yuv2yuvX_mmxext(filter, filterSize, src, dest, dstW, dither, offset); \
+        return; \
+    } \
+    if(pixelsProcessed > 0) \
+        ff_yuv2yuvX_ ##opt(filter, filterSize - 1, 0, dest - offset, pixelsProcessed + offset, dither, offset); \
+    if(remainder > 0){ \
+      ff_yuv2yuvX_mmxext(filter, filterSize - 1, pixelsProcessed, dest - offset, pixelsProcessed + remainder + offset, dither, offset); \
+    } \
+    return; \
+}
+
+#if HAVE_MMXEXT_EXTERNAL
+YUV2YUVX_FUNC_MMX(mmxext, 16)
+#endif
+#if HAVE_SSE3_EXTERNAL
+YUV2YUVX_FUNC(sse3, 32)
+#endif
+#if HAVE_AVX2_EXTERNAL
+YUV2YUVX_FUNC(avx2, 64)
+#endif
+
+#define SCALE_FUNC(filter_n, from_bpc, to_bpc, opt) \
+void ff_hscale ## from_bpc ## to ## to_bpc ## _ ## filter_n ## _ ## opt( \
+                                                SwsInternal *c, int16_t *data, \
+                                                int dstW, const uint8_t *src, \
+                                                const int16_t *filter, \
+                                                const int32_t *filterPos, int filterSize)
+
+#define SCALE_FUNCS(filter_n, opt) \
+    SCALE_FUNC(filter_n,  8, 15, opt); \
+    SCALE_FUNC(filter_n,  9, 15, opt); \
+    SCALE_FUNC(filter_n, 10, 15, opt); \
+    SCALE_FUNC(filter_n, 12, 15, opt); \
+    SCALE_FUNC(filter_n, 14, 15, opt); \
+    SCALE_FUNC(filter_n, 16, 15, opt); \
+    SCALE_FUNC(filter_n,  8, 19, opt); \
+    SCALE_FUNC(filter_n,  9, 19, opt); \
+    SCALE_FUNC(filter_n, 10, 19, opt); \
+    SCALE_FUNC(filter_n, 12, 19, opt); \
+    SCALE_FUNC(filter_n, 14, 19, opt); \
+    SCALE_FUNC(filter_n, 16, 19, opt)
+
+#define SCALE_FUNCS_MMX(opt) \
+    SCALE_FUNCS(4, opt); \
+    SCALE_FUNCS(8, opt); \
+    SCALE_FUNCS(X, opt)
+
+#define SCALE_FUNCS_SSE(opt) \
+    SCALE_FUNCS(4, opt); \
+    SCALE_FUNCS(8, opt); \
+    SCALE_FUNCS(X4, opt); \
+    SCALE_FUNCS(X8, opt)
+
+SCALE_FUNCS_SSE(sse2);
+SCALE_FUNCS_SSE(ssse3);
+SCALE_FUNCS_SSE(sse4);
+
+SCALE_FUNC(4, 8, 15, avx2);
+SCALE_FUNC(X4, 8, 15, avx2);
+
+#define VSCALEX_FUNC(size, opt) \
+void ff_yuv2planeX_ ## size ## _ ## opt(const int16_t *filter, int filterSize, \
+                                        const int16_t **src, uint8_t *dest, int dstW, \
+                                        const uint8_t *dither, int offset)
+#define VSCALEX_FUNCS(opt) \
+    VSCALEX_FUNC(8,  opt); \
+    VSCALEX_FUNC(9,  opt); \
+    VSCALEX_FUNC(10, opt)
+
+VSCALEX_FUNC(8, mmxext);
+VSCALEX_FUNCS(sse2);
+VSCALEX_FUNCS(sse4);
+VSCALEX_FUNC(16, sse4);
+VSCALEX_FUNCS(avx);
+
+#define VSCALE_FUNC(size, opt) \
+void ff_yuv2plane1_ ## size ## _ ## opt(const int16_t *src, uint8_t *dst, int dstW, \
+                                        const uint8_t *dither, int offset)
+#define VSCALE_FUNCS(opt1, opt2) \
+    VSCALE_FUNC(8,  opt1); \
+    VSCALE_FUNC(9,  opt2); \
+    VSCALE_FUNC(10, opt2); \
+    VSCALE_FUNC(16, opt1)
+
+VSCALE_FUNCS(sse2, sse2);
+VSCALE_FUNC(16, sse4);
+VSCALE_FUNCS(avx, avx);
+
+#define INPUT_Y_FUNC(fmt, opt) \
+void ff_ ## fmt ## ToY_  ## opt(uint8_t *dst, const uint8_t *src, \
+                                const uint8_t *unused1, const uint8_t *unused2, \
+                                int w, uint32_t *unused, void *opq)
+#define INPUT_UV_FUNC(fmt, opt) \
+void ff_ ## fmt ## ToUV_ ## opt(uint8_t *dstU, uint8_t *dstV, \
+                                const uint8_t *unused0, \
+                                const uint8_t *src1, \
+                                const uint8_t *src2, \
+                                int w, uint32_t *unused, void *opq)
+#define INPUT_FUNC(fmt, opt) \
+    INPUT_Y_FUNC(fmt, opt); \
+    INPUT_UV_FUNC(fmt, opt)
+#define INPUT_FUNCS(opt) \
+    INPUT_FUNC(uyvy, opt); \
+    INPUT_FUNC(yuyv, opt); \
+    INPUT_UV_FUNC(nv12, opt); \
+    INPUT_UV_FUNC(nv21, opt); \
+    INPUT_FUNC(rgba, opt); \
+    INPUT_FUNC(bgra, opt); \
+    INPUT_FUNC(argb, opt); \
+    INPUT_FUNC(abgr, opt); \
+    INPUT_FUNC(rgb24, opt); \
+    INPUT_FUNC(bgr24, opt)
+
+INPUT_FUNCS(sse2);
+INPUT_FUNCS(ssse3);
+INPUT_FUNCS(avx);
+INPUT_FUNC(rgba, avx2);
+INPUT_FUNC(bgra, avx2);
+INPUT_FUNC(argb, avx2);
+INPUT_FUNC(abgr, avx2);
+INPUT_FUNC(rgb24, avx2);
+INPUT_FUNC(bgr24, avx2);
+
+#if ARCH_X86_64
+#define YUV2NV_DECL(fmt, opt) \
+void ff_yuv2 ## fmt ## cX_ ## opt(enum AVPixelFormat format, const uint8_t *dither, \
+                                  const int16_t *filter, int filterSize, \
+                                  const int16_t **u, const int16_t **v, \
+                                  uint8_t *dst, int dstWidth)
+
+YUV2NV_DECL(nv12, avx2);
+YUV2NV_DECL(nv21, avx2);
+
+#define YUV2GBRP_FN_DECL(fmt, opt)                                                      \
+void ff_yuv2##fmt##_full_X_ ##opt(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)
+
+#define YUV2GBRP_DECL(opt)     \
+YUV2GBRP_FN_DECL(gbrp,       opt); \
+YUV2GBRP_FN_DECL(gbrap,      opt); \
+YUV2GBRP_FN_DECL(gbrp9le,    opt); \
+YUV2GBRP_FN_DECL(gbrp10le,   opt); \
+YUV2GBRP_FN_DECL(gbrap10le,  opt); \
+YUV2GBRP_FN_DECL(gbrp12le,   opt); \
+YUV2GBRP_FN_DECL(gbrap12le,  opt); \
+YUV2GBRP_FN_DECL(gbrp14le,   opt); \
+YUV2GBRP_FN_DECL(gbrp16le,   opt); \
+YUV2GBRP_FN_DECL(gbrap16le,  opt); \
+YUV2GBRP_FN_DECL(gbrpf32le,  opt); \
+YUV2GBRP_FN_DECL(gbrapf32le, opt); \
+YUV2GBRP_FN_DECL(gbrp9be,    opt); \
+YUV2GBRP_FN_DECL(gbrp10be,   opt); \
+YUV2GBRP_FN_DECL(gbrap10be,  opt); \
+YUV2GBRP_FN_DECL(gbrp12be,   opt); \
+YUV2GBRP_FN_DECL(gbrap12be,  opt); \
+YUV2GBRP_FN_DECL(gbrp14be,   opt); \
+YUV2GBRP_FN_DECL(gbrp16be,   opt); \
+YUV2GBRP_FN_DECL(gbrap16be,  opt); \
+YUV2GBRP_FN_DECL(gbrpf32be,  opt); \
+YUV2GBRP_FN_DECL(gbrapf32be, opt)
+
+YUV2GBRP_DECL(sse2);
+YUV2GBRP_DECL(sse4);
+YUV2GBRP_DECL(avx2);
+
+#define INPUT_PLANAR_RGB_Y_FN_DECL(fmt, opt)                               \
+void ff_planar_##fmt##_to_y_##opt(uint8_t *dst,                            \
+                           const uint8_t *src[4], int w, int32_t *rgb2yuv, \
+                           void *opq)
+
+#define INPUT_PLANAR_RGB_UV_FN_DECL(fmt, opt)                              \
+void ff_planar_##fmt##_to_uv_##opt(uint8_t *dstU, uint8_t *dstV,           \
+                           const uint8_t *src[4], int w, int32_t *rgb2yuv, \
+                           void *opq)
+
+#define INPUT_PLANAR_RGB_A_FN_DECL(fmt, opt)                               \
+void ff_planar_##fmt##_to_a_##opt(uint8_t *dst,                            \
+                           const uint8_t *src[4], int w, int32_t *rgb2yuv, \
+                           void *opq)
+
+
+#define INPUT_PLANAR_RGBXX_A_DECL(fmt, opt) \
+INPUT_PLANAR_RGB_A_FN_DECL(fmt##le,  opt);  \
+INPUT_PLANAR_RGB_A_FN_DECL(fmt##be,  opt)
+
+#define INPUT_PLANAR_RGBXX_Y_DECL(fmt, opt) \
+INPUT_PLANAR_RGB_Y_FN_DECL(fmt##le,  opt);  \
+INPUT_PLANAR_RGB_Y_FN_DECL(fmt##be,  opt)
+
+#define INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt) \
+INPUT_PLANAR_RGB_UV_FN_DECL(fmt##le,  opt);  \
+INPUT_PLANAR_RGB_UV_FN_DECL(fmt##be,  opt)
+
+#define INPUT_PLANAR_RGBXX_YUVA_DECL(fmt, opt) \
+INPUT_PLANAR_RGBXX_Y_DECL(fmt,  opt);          \
+INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt);          \
+INPUT_PLANAR_RGBXX_A_DECL(fmt,  opt)
+
+#define INPUT_PLANAR_RGBXX_YUV_DECL(fmt, opt) \
+INPUT_PLANAR_RGBXX_Y_DECL(fmt,  opt);         \
+INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt)
+
+#define INPUT_PLANAR_RGBXX_UVA_DECL(fmt, opt) \
+INPUT_PLANAR_RGBXX_UV_DECL(fmt, opt);         \
+INPUT_PLANAR_RGBXX_A_DECL(fmt,  opt)
+
+#define INPUT_PLANAR_RGB_A_ALL_DECL(opt) \
+INPUT_PLANAR_RGB_A_FN_DECL(rgb,   opt);  \
+INPUT_PLANAR_RGBXX_A_DECL(rgb10,  opt);  \
+INPUT_PLANAR_RGBXX_A_DECL(rgb12,  opt);  \
+INPUT_PLANAR_RGBXX_A_DECL(rgb16,  opt);  \
+INPUT_PLANAR_RGBXX_A_DECL(rgbf32, opt)
+
+#define INPUT_PLANAR_RGB_Y_ALL_DECL(opt) \
+INPUT_PLANAR_RGB_Y_FN_DECL(rgb,   opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgb9,   opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgb10,  opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgb12,  opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgb14,  opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgb16,  opt);  \
+INPUT_PLANAR_RGBXX_Y_DECL(rgbf32, opt)
+
+#define INPUT_PLANAR_RGB_UV_ALL_DECL(opt) \
+INPUT_PLANAR_RGB_UV_FN_DECL(rgb,    opt); \
+INPUT_PLANAR_RGBXX_UV_DECL(rgb9,   opt);  \
+INPUT_PLANAR_RGBXX_UV_DECL(rgb10,  opt);  \
+INPUT_PLANAR_RGBXX_UV_DECL(rgb12,  opt);  \
+INPUT_PLANAR_RGBXX_UV_DECL(rgb14,  opt);  \
+INPUT_PLANAR_RGBXX_UV_DECL(rgb16,  opt);  \
+INPUT_PLANAR_RGBXX_UV_DECL(rgbf32, opt)
+
+INPUT_PLANAR_RGBXX_Y_DECL(rgbf32, sse2);
+INPUT_PLANAR_RGB_UV_ALL_DECL(sse2);
+INPUT_PLANAR_RGB_A_ALL_DECL(sse2);
+
+INPUT_PLANAR_RGB_Y_ALL_DECL(sse4);
+INPUT_PLANAR_RGB_UV_ALL_DECL(sse4);
+INPUT_PLANAR_RGBXX_A_DECL(rgbf32, sse4);
+
+INPUT_PLANAR_RGB_Y_ALL_DECL(avx2);
+INPUT_PLANAR_RGB_UV_ALL_DECL(avx2);
+INPUT_PLANAR_RGB_A_ALL_DECL(avx2);
+#endif
+
+#define RANGE_CONVERT_FUNCS(opt, bpc) do {                                  \
+    if (c->opts.src_range) {                                                \
+        c->lumConvertRange = ff_lumRangeFromJpeg##bpc##_##opt;              \
+        c->chrConvertRange = ff_chrRangeFromJpeg##bpc##_##opt;              \
+    } else {                                                                \
+        c->lumConvertRange = ff_lumRangeToJpeg##bpc##_##opt;                \
+        c->chrConvertRange = ff_chrRangeToJpeg##bpc##_##opt;                \
+    }                                                                       \
+} while (0)
+
+#define RANGE_CONVERT_FUNCS_DECL(opt, bpc)                                  \
+void ff_lumRangeFromJpeg##bpc##_##opt(int16_t *dst, int width,              \
+                                      uint32_t coeff, int64_t offset);      \
+void ff_chrRangeFromJpeg##bpc##_##opt(int16_t *dstU, int16_t *dstV, int width, \
+                                      uint32_t coeff, int64_t offset);      \
+void ff_lumRangeToJpeg##bpc##_##opt(int16_t *dst, int width,                \
+                                    uint32_t coeff, int64_t offset);        \
+void ff_chrRangeToJpeg##bpc##_##opt(int16_t *dstU, int16_t *dstV, int width, \
+                                    uint32_t coeff, int64_t offset);        \
+
+RANGE_CONVERT_FUNCS_DECL(sse2, 8)
+RANGE_CONVERT_FUNCS_DECL(sse4, 16)
+RANGE_CONVERT_FUNCS_DECL(avx2, 8)
+RANGE_CONVERT_FUNCS_DECL(avx2, 16)
+
+av_cold void ff_sws_init_range_convert_x86(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        if (c->dstBpc <= 14) {
+            RANGE_CONVERT_FUNCS(avx2, 8);
+        } else {
+            RANGE_CONVERT_FUNCS(avx2, 16);
+        }
+    } else if (EXTERNAL_SSE2(cpu_flags) && c->dstBpc <= 14) {
+        RANGE_CONVERT_FUNCS(sse2, 8);
+    } else if (EXTERNAL_SSE4(cpu_flags) && c->dstBpc > 14) {
+        RANGE_CONVERT_FUNCS(sse4, 16);
+    }
+}
+
+av_cold void ff_sws_init_swscale_x86(SwsInternal *c)
+{
+    int cpu_flags = av_get_cpu_flags();
+
+#if HAVE_MMXEXT_INLINE
+    if (INLINE_MMXEXT(cpu_flags))
+        sws_init_swscale_mmxext(c);
+#endif
+    if(c->use_mmx_vfilter && !(c->opts.flags & SWS_ACCURATE_RND)) {
+#if HAVE_MMXEXT_EXTERNAL
+        if (EXTERNAL_MMXEXT(cpu_flags))
+            c->yuv2planeX = yuv2yuvX_mmxext;
+#endif
+#if HAVE_SSE3_EXTERNAL
+        if (EXTERNAL_SSE3(cpu_flags))
+            c->yuv2planeX = yuv2yuvX_sse3;
+#endif
+#if HAVE_AVX2_EXTERNAL
+        if (EXTERNAL_AVX2_FAST(cpu_flags))
+            c->yuv2planeX = yuv2yuvX_avx2;
+#endif
+    }
+#if ARCH_X86_32 && !HAVE_ALIGNED_STACK
+    // The better yuv2planeX_8 functions need aligned stack on x86-32,
+    // so we use MMXEXT in this case if they are not available.
+    if (EXTERNAL_MMXEXT(cpu_flags)) {
+        if (c->dstBpc == 8 && !c->use_mmx_vfilter)
+            c->yuv2planeX = ff_yuv2planeX_8_mmxext;
+    }
+#endif /* ARCH_X86_32 && !HAVE_ALIGNED_STACK */
+
+#define ASSIGN_SCALE_FUNC2(hscalefn, filtersize, opt1, opt2) do { \
+    if (c->srcBpc == 8) { \
+        hscalefn = c->dstBpc <= 14 ? ff_hscale8to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale8to19_ ## filtersize ## _ ## opt1; \
+    } else if (c->srcBpc == 9) { \
+        hscalefn = c->dstBpc <= 14 ? ff_hscale9to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale9to19_ ## filtersize ## _ ## opt1; \
+    } else if (c->srcBpc == 10) { \
+        hscalefn = c->dstBpc <= 14 ? ff_hscale10to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale10to19_ ## filtersize ## _ ## opt1; \
+    } else if (c->srcBpc == 12) { \
+        hscalefn = c->dstBpc <= 14 ? ff_hscale12to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale12to19_ ## filtersize ## _ ## opt1; \
+    } else if (c->srcBpc == 14 || ((c->opts.src_format==AV_PIX_FMT_PAL8||isAnyRGB(c->opts.src_format)) && av_pix_fmt_desc_get(c->opts.src_format)->comp[0].depth<16)) { \
+        hscalefn = c->dstBpc <= 14 ? ff_hscale14to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale14to19_ ## filtersize ## _ ## opt1; \
+    } else { /* c->srcBpc == 16 */ \
+        av_assert0(c->srcBpc == 16);\
+        hscalefn = c->dstBpc <= 14 ? ff_hscale16to15_ ## filtersize ## _ ## opt2 : \
+                                     ff_hscale16to19_ ## filtersize ## _ ## opt1; \
+    } \
+} while (0)
+#define ASSIGN_VSCALEX_FUNC(vscalefn, opt, do_16_case, condition_8bit) \
+switch(c->dstBpc){ \
+    case 16:                          do_16_case;                          break; \
+    case 10: if (!isBE(c->opts.dst_format) && !isSemiPlanarYUV(c->opts.dst_format) && !isDataInHighBits(c->opts.dst_format)) vscalefn = ff_yuv2planeX_10_ ## opt; break; \
+    case 9:  if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2planeX_9_  ## opt; break; \
+    case 8: if ((condition_8bit) && !c->use_mmx_vfilter) vscalefn = ff_yuv2planeX_8_  ## opt; break; \
+    }
+#define ASSIGN_VSCALE_FUNC(vscalefn, opt) \
+    switch(c->dstBpc){ \
+    case 16: if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2plane1_16_ ## opt; break; \
+    case 10: if (!isBE(c->opts.dst_format) && !isSemiPlanarYUV(c->opts.dst_format) && !isDataInHighBits(c->opts.dst_format)) vscalefn = ff_yuv2plane1_10_ ## opt; break; \
+    case 9:  if (!isBE(c->opts.dst_format)) vscalefn = ff_yuv2plane1_9_  ## opt;  break; \
+    case 8:                           vscalefn = ff_yuv2plane1_8_  ## opt;  break; \
+    default: av_assert0(c->dstBpc>8); \
+    }
+#define case_rgb(x, X, opt) \
+        case AV_PIX_FMT_ ## X: \
+            c->lumToYV12 = ff_ ## x ## ToY_ ## opt; \
+            if (!c->chrSrcHSubSample) \
+                c->chrToYV12 = ff_ ## x ## ToUV_ ## opt; \
+            break
+#define ASSIGN_SSE_SCALE_FUNC(hscalefn, filtersize, opt1, opt2) \
+    switch (filtersize) { \
+    case 4:  ASSIGN_SCALE_FUNC2(hscalefn, 4, opt1, opt2); break; \
+    case 8:  ASSIGN_SCALE_FUNC2(hscalefn, 8, opt1, opt2); break; \
+    default: if (filtersize & 4) ASSIGN_SCALE_FUNC2(hscalefn, X4, opt1, opt2); \
+             else                ASSIGN_SCALE_FUNC2(hscalefn, X8, opt1, opt2); \
+             break; \
+    }
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse2, sse2);
+        ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, sse2, sse2);
+        ASSIGN_VSCALEX_FUNC(c->yuv2planeX, sse2, ,
+                            HAVE_ALIGNED_STACK || ARCH_X86_64);
+        if (!(c->opts.flags & SWS_ACCURATE_RND))
+            ASSIGN_VSCALE_FUNC(c->yuv2plane1, sse2);
+
+        switch (c->opts.src_format) {
+        case AV_PIX_FMT_YA8:
+            c->lumToYV12 = ff_yuyvToY_sse2;
+            if (c->needAlpha)
+                c->alpToYV12 = ff_uyvyToY_sse2;
+            break;
+        case AV_PIX_FMT_YUYV422:
+            c->lumToYV12 = ff_yuyvToY_sse2;
+            c->chrToYV12 = ff_yuyvToUV_sse2;
+            break;
+        case AV_PIX_FMT_UYVY422:
+            c->lumToYV12 = ff_uyvyToY_sse2;
+            c->chrToYV12 = ff_uyvyToUV_sse2;
+            break;
+        case AV_PIX_FMT_NV12:
+            c->chrToYV12 = ff_nv12ToUV_sse2;
+            break;
+        case AV_PIX_FMT_NV21:
+            c->chrToYV12 = ff_nv21ToUV_sse2;
+            break;
+        case_rgb(rgb24, RGB24, sse2);
+        case_rgb(bgr24, BGR24, sse2);
+        case_rgb(bgra,  BGRA,  sse2);
+        case_rgb(rgba,  RGBA,  sse2);
+        case_rgb(abgr,  ABGR,  sse2);
+        case_rgb(argb,  ARGB,  sse2);
+        default:
+            break;
+        }
+    }
+    if (EXTERNAL_SSSE3(cpu_flags)) {
+        ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, ssse3, ssse3);
+        ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, ssse3, ssse3);
+        switch (c->opts.src_format) {
+        case_rgb(rgb24, RGB24, ssse3);
+        case_rgb(bgr24, BGR24, ssse3);
+        default:
+            break;
+        }
+    }
+    if (EXTERNAL_SSE4(cpu_flags)) {
+        /* Xto15 don't need special sse4 functions */
+        ASSIGN_SSE_SCALE_FUNC(c->hyScale, c->hLumFilterSize, sse4, ssse3);
+        ASSIGN_SSE_SCALE_FUNC(c->hcScale, c->hChrFilterSize, sse4, ssse3);
+        ASSIGN_VSCALEX_FUNC(c->yuv2planeX, sse4,
+                            if (!isBE(c->opts.dst_format)) c->yuv2planeX = ff_yuv2planeX_16_sse4,
+                            HAVE_ALIGNED_STACK || ARCH_X86_64);
+        if (c->dstBpc == 16 && !isBE(c->opts.dst_format) && !(c->opts.flags & SWS_ACCURATE_RND))
+            c->yuv2plane1 = ff_yuv2plane1_16_sse4;
+    }
+
+    if (EXTERNAL_AVX(cpu_flags)) {
+        ASSIGN_VSCALEX_FUNC(c->yuv2planeX, avx, ,
+                            HAVE_ALIGNED_STACK || ARCH_X86_64);
+        if (!(c->opts.flags & SWS_ACCURATE_RND))
+            ASSIGN_VSCALE_FUNC(c->yuv2plane1, avx);
+
+        switch (c->opts.src_format) {
+        case AV_PIX_FMT_YUYV422:
+            c->chrToYV12 = ff_yuyvToUV_avx;
+            break;
+        case AV_PIX_FMT_UYVY422:
+            c->chrToYV12 = ff_uyvyToUV_avx;
+            break;
+        case AV_PIX_FMT_NV12:
+            c->chrToYV12 = ff_nv12ToUV_avx;
+            break;
+        case AV_PIX_FMT_NV21:
+            c->chrToYV12 = ff_nv21ToUV_avx;
+            break;
+        case_rgb(rgb24, RGB24, avx);
+        case_rgb(bgr24, BGR24, avx);
+        case_rgb(bgra,  BGRA,  avx);
+        case_rgb(rgba,  RGBA,  avx);
+        case_rgb(abgr,  ABGR,  avx);
+        case_rgb(argb,  ARGB,  avx);
+        default:
+            break;
+        }
+    }
+
+#if ARCH_X86_64
+#define ASSIGN_AVX2_SCALE_FUNC(hscalefn, filtersize) \
+    switch (filtersize) { \
+    case 4:  hscalefn = ff_hscale8to15_4_avx2; break; \
+    default:  hscalefn = ff_hscale8to15_X4_avx2; break; \
+             break; \
+    }
+
+    if (EXTERNAL_AVX2_FAST(cpu_flags) && !(cpu_flags & AV_CPU_FLAG_SLOW_GATHER)) {
+        if ((c->srcBpc == 8) && (c->dstBpc <= 14)) {
+            ASSIGN_AVX2_SCALE_FUNC(c->hcScale, c->hChrFilterSize);
+            ASSIGN_AVX2_SCALE_FUNC(c->hyScale, c->hLumFilterSize);
+        }
+    }
+
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        if (ARCH_X86_64)
+            switch (c->opts.src_format) {
+            case_rgb(rgb24, RGB24, avx2);
+            case_rgb(bgr24, BGR24, avx2);
+            case_rgb(bgra,  BGRA,  avx2);
+            case_rgb(rgba,  RGBA,  avx2);
+            case_rgb(abgr,  ABGR,  avx2);
+            case_rgb(argb,  ARGB,  avx2);
+            }
+        if (!(c->opts.flags & SWS_ACCURATE_RND)) // FIXME
+        switch (c->opts.dst_format) {
+        case AV_PIX_FMT_NV12:
+        case AV_PIX_FMT_NV24:
+            c->yuv2nv12cX = ff_yuv2nv12cX_avx2;
+            break;
+        case AV_PIX_FMT_NV21:
+        case AV_PIX_FMT_NV42:
+            c->yuv2nv12cX = ff_yuv2nv21cX_avx2;
+            break;
+        default:
+            break;
+        }
+    }
+
+
+#define INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(fmt, name, opt)          \
+        case fmt:                                                     \
+            c->readAlpPlanar = ff_planar_##name##_to_a_##opt;
+
+#define INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
+        case rgba_fmt:                                                \
+        case rgb_fmt:                                                 \
+            c->readLumPlanar = ff_planar_##name##_to_y_##opt;         \
+            c->readChrPlanar = ff_planar_##name##_to_uv_##opt;        \
+            break;
+
+#define INPUT_PLANER_RGB_YUV_FUNC_CASE(fmt, name, opt)                \
+        case fmt:                                                     \
+            c->readLumPlanar = ff_planar_##name##_to_y_##opt;         \
+            c->readChrPlanar = ff_planar_##name##_to_uv_##opt;        \
+            break;
+
+#define INPUT_PLANER_RGB_UV_FUNC_CASE(fmt, name, opt)                 \
+        case fmt:                                                     \
+            c->readChrPlanar = ff_planar_##name##_to_uv_##opt;        \
+            break;
+
+#define INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##LE,  name##le, opt)       \
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##LE, name##le, opt)       \
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##BE,  name##be, opt)       \
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
+
+#define INPUT_PLANER_RGBAXX_UVA_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt) \
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##LE, name##le, opt)       \
+        INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##LE, name##le, opt)       \
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(rgba_fmt##BE, name##be, opt)       \
+        INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
+
+#define INPUT_PLANER_RGBAXX_YUV_FUNC_CASE(rgb_fmt, rgba_fmt, name, opt)           \
+        INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt##LE, rgba_fmt##LE, name##le, opt) \
+        INPUT_PLANER_RGBA_YUV_FUNC_CASE(rgb_fmt##BE, rgba_fmt##BE, name##be, opt)
+
+#define INPUT_PLANER_RGBXX_YUV_FUNC_CASE(rgb_fmt, name, opt)       \
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##LE, name##le, opt) \
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
+
+#define INPUT_PLANER_RGBXX_UV_FUNC_CASE(rgb_fmt, name, opt)        \
+        INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##LE, name##le, opt)  \
+        INPUT_PLANER_RGB_UV_FUNC_CASE(rgb_fmt##BE, name##be, opt)
+
+#define INPUT_PLANER_RGB_YUVA_ALL_CASES(opt)                                                     \
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(AV_PIX_FMT_GBRAP,                         rgb, opt) \
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(    AV_PIX_FMT_GBRP,                            rgb, opt) \
+        INPUT_PLANER_RGBXX_YUV_FUNC_CASE(  AV_PIX_FMT_GBRP9,                          rgb9, opt) \
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP10,  AV_PIX_FMT_GBRAP10,   rgb10, opt) \
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP12,  AV_PIX_FMT_GBRAP12,   rgb12, opt) \
+        INPUT_PLANER_RGBXX_YUV_FUNC_CASE(  AV_PIX_FMT_GBRP14,                        rgb14, opt) \
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRP16,  AV_PIX_FMT_GBRAP16,   rgb16, opt) \
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, opt)
+
+
+    if (EXTERNAL_SSE2(cpu_flags)) {
+        switch (c->opts.src_format) {
+        INPUT_PLANER_RGB_A_FUNC_CASE_NOBREAK(AV_PIX_FMT_GBRAP,                         rgb, sse2);
+        INPUT_PLANER_RGB_UV_FUNC_CASE(     AV_PIX_FMT_GBRP,                            rgb, sse2);
+        INPUT_PLANER_RGBXX_UV_FUNC_CASE(   AV_PIX_FMT_GBRP9,                          rgb9, sse2);
+        INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP10,  AV_PIX_FMT_GBRAP10,   rgb10, sse2);
+        INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP12,  AV_PIX_FMT_GBRAP12,   rgb12, sse2);
+        INPUT_PLANER_RGBXX_UV_FUNC_CASE(   AV_PIX_FMT_GBRP14,                        rgb14, sse2);
+        INPUT_PLANER_RGBAXX_UVA_FUNC_CASE( AV_PIX_FMT_GBRP16,  AV_PIX_FMT_GBRAP16,   rgb16, sse2);
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, sse2);
+        default:
+            break;
+        }
+    }
+
+    if (EXTERNAL_SSE4(cpu_flags)) {
+        switch (c->opts.src_format) {
+        case AV_PIX_FMT_GBRAP:
+        INPUT_PLANER_RGB_YUV_FUNC_CASE(    AV_PIX_FMT_GBRP,                            rgb, sse4);
+        INPUT_PLANER_RGBXX_YUV_FUNC_CASE(  AV_PIX_FMT_GBRP9,                          rgb9, sse4);
+        INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP10,  AV_PIX_FMT_GBRAP10,   rgb10, sse4);
+        INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP12,  AV_PIX_FMT_GBRAP12,   rgb12, sse4);
+        INPUT_PLANER_RGBXX_YUV_FUNC_CASE(  AV_PIX_FMT_GBRP14,                        rgb14, sse4);
+        INPUT_PLANER_RGBAXX_YUV_FUNC_CASE( AV_PIX_FMT_GBRP16,  AV_PIX_FMT_GBRAP16,   rgb16, sse4);
+        INPUT_PLANER_RGBAXX_YUVA_FUNC_CASE(AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32, rgbf32, sse4);
+        default:
+            break;
+        }
+    }
+
+    if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+        switch (c->opts.src_format) {
+        INPUT_PLANER_RGB_YUVA_ALL_CASES(avx2)
+        default:
+            break;
+        }
+    }
+
+    if(c->opts.flags & SWS_FULL_CHR_H_INT) {
+
+#define YUV2ANYX_FUNC_CASE(fmt, name, opt)              \
+        case fmt:                                       \
+            c->yuv2anyX = ff_yuv2##name##_full_X_##opt; \
+            break;
+
+#define YUV2ANYX_GBRAP_CASES(opt)                                  \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP,       gbrp,       opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP,      gbrap,      opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP9LE,    gbrp9le,    opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP10LE,   gbrp10le,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP10LE,  gbrap10le,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP12LE,   gbrp12le,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP12LE,  gbrap12le,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP14LE,   gbrp14le,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP16LE,   gbrp16le,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP16LE,  gbrap16le,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRPF32LE,  gbrpf32le,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAPF32LE, gbrapf32le, opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP9BE,    gbrp9be,    opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP10BE,   gbrp10be,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP10BE,  gbrap10be,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP12BE,   gbrp12be,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP12BE,  gbrap12be,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP14BE,   gbrp14be,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRP16BE,   gbrp16be,   opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAP16BE,  gbrap16be,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRPF32BE,  gbrpf32be,  opt) \
+        YUV2ANYX_FUNC_CASE(AV_PIX_FMT_GBRAPF32BE, gbrapf32be, opt)
+
+        if (EXTERNAL_SSE2(cpu_flags)) {
+            switch (c->opts.dst_format) {
+            YUV2ANYX_GBRAP_CASES(sse2)
+            default:
+                break;
+            }
+        }
+
+        if (EXTERNAL_SSE4(cpu_flags)) {
+            switch (c->opts.dst_format) {
+            YUV2ANYX_GBRAP_CASES(sse4)
+            default:
+                break;
+            }
+        }
+
+        if (EXTERNAL_AVX2_FAST(cpu_flags)) {
+            switch (c->opts.dst_format) {
+            YUV2ANYX_GBRAP_CASES(avx2)
+            default:
+                break;
+            }
+        }
+    }
+
+#endif
+}
+
+#endif
diff --git a/libs/ffmpeg/libswscale/x86/swscale_template.c b/libs/ffmpeg/libswscale/x86/swscale_template.c
new file mode 100644
index 000000000000..bfd0d68968ea
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/swscale_template.c
@@ -0,0 +1,1408 @@
+/*
+ * 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
+ */
+
+#if 0
+#pragma makedep header
+#endif
+
+#include <stdint.h>
+
+#include "libavutil/x86/asm.h"
+#include "libswscale/swscale_internal.h"
+
+#undef REAL_MOVNTQ
+#undef MOVNTQ
+
+
+#define REAL_MOVNTQ(a,b) "movntq " #a ", " #b " \n\t"
+#define MOVNTQ(a,b)  REAL_MOVNTQ(a,b)
+
+#define YSCALEYUV2PACKEDX_UV \
+    __asm__ volatile(\
+        "xor                %%"FF_REG_a", %%"FF_REG_a"  \n\t"\
+        ".p2align                      4                \n\t"\
+        "nop                                            \n\t"\
+        "1:                                             \n\t"\
+        "lea "CHR_MMX_FILTER_OFFSET"(%0), %%"FF_REG_d"  \n\t"\
+        "mov              (%%"FF_REG_d"), %%"FF_REG_S"  \n\t"\
+        "movq      "VROUNDER_OFFSET"(%0), %%mm3         \n\t"\
+        "movq                      %%mm3, %%mm4         \n\t"\
+        ".p2align                      4                \n\t"\
+        "2:                                             \n\t"\
+        "movq            8(%%"FF_REG_d"), %%mm0         \n\t" /* filterCoeff */\
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm2      \n\t" /* UsrcData */\
+        "add                          %6, %%"FF_REG_S"  \n\t" \
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm5      \n\t" /* VsrcData */\
+        "add                         $16, %%"FF_REG_d"  \n\t"\
+        "mov              (%%"FF_REG_d"), %%"FF_REG_S"  \n\t"\
+        "pmulhw                    %%mm0, %%mm2         \n\t"\
+        "pmulhw                    %%mm0, %%mm5         \n\t"\
+        "paddw                     %%mm2, %%mm3         \n\t"\
+        "paddw                     %%mm5, %%mm4         \n\t"\
+        "test               %%"FF_REG_S", %%"FF_REG_S"  \n\t"\
+        " jnz                         2b                \n\t"\
+
+#define YSCALEYUV2PACKEDX_YA(offset,coeff,src1,src2,dst1,dst2) \
+    "lea                "offset"(%0), %%"FF_REG_d"  \n\t"\
+    "mov              (%%"FF_REG_d"), %%"FF_REG_S"  \n\t"\
+    "movq      "VROUNDER_OFFSET"(%0), "#dst1"       \n\t"\
+    "movq                    "#dst1", "#dst2"       \n\t"\
+    ".p2align                      4                \n\t"\
+    "2:                                             \n\t"\
+    "movq            8(%%"FF_REG_d"), "#coeff"      \n\t" /* filterCoeff */\
+    "movq  (%%"FF_REG_S", %%"FF_REG_a", 2), "#src1" \n\t" /* Y1srcData */\
+    "movq 8(%%"FF_REG_S", %%"FF_REG_a", 2), "#src2" \n\t" /* Y2srcData */\
+    "add                         $16, %%"FF_REG_d"  \n\t"\
+    "mov              (%%"FF_REG_d"), %%"FF_REG_S"  \n\t"\
+    "pmulhw                 "#coeff", "#src1"       \n\t"\
+    "pmulhw                 "#coeff", "#src2"       \n\t"\
+    "paddw                   "#src1", "#dst1"       \n\t"\
+    "paddw                   "#src2", "#dst2"       \n\t"\
+    "test               %%"FF_REG_S", %%"FF_REG_S"  \n\t"\
+    " jnz                         2b                \n\t"\
+
+#define YSCALEYUV2PACKEDX \
+    YSCALEYUV2PACKEDX_UV \
+    YSCALEYUV2PACKEDX_YA(LUM_MMX_FILTER_OFFSET,%%mm0,%%mm2,%%mm5,%%mm1,%%mm7) \
+
+#define YSCALEYUV2PACKEDX_END                     \
+        :: "r" (&c->redDither),                   \
+            "m" (dummy), "m" (dummy), "m" (dummy),\
+            "r" (dest), "m" (dstW_reg), "m"(uv_off) \
+            NAMED_CONSTRAINTS_ADD(bF8,bFC) \
+        : "%"FF_REG_a, "%"FF_REG_d, "%"FF_REG_S            \
+    );
+
+#define YSCALEYUV2PACKEDX_ACCURATE_UV \
+    __asm__ volatile(\
+        "xor %%"FF_REG_a", %%"FF_REG_a"                 \n\t"\
+        ".p2align                      4                \n\t"\
+        "nop                                            \n\t"\
+        "1:                                             \n\t"\
+        "lea "CHR_MMX_FILTER_OFFSET"(%0), %%"FF_REG_d"  \n\t"\
+        "mov              (%%"FF_REG_d"), %%"FF_REG_S"  \n\t"\
+        "pxor                      %%mm4, %%mm4         \n\t"\
+        "pxor                      %%mm5, %%mm5         \n\t"\
+        "pxor                      %%mm6, %%mm6         \n\t"\
+        "pxor                      %%mm7, %%mm7         \n\t"\
+        ".p2align                      4                \n\t"\
+        "2:                                             \n\t"\
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm0      \n\t" /* UsrcData */\
+        "add                          %6, %%"FF_REG_S"  \n\t" \
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm2      \n\t" /* VsrcData */\
+        "mov "STR(APCK_PTR2)"(%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm1      \n\t" /* UsrcData */\
+        "movq                      %%mm0, %%mm3         \n\t"\
+        "punpcklwd                 %%mm1, %%mm0         \n\t"\
+        "punpckhwd                 %%mm1, %%mm3         \n\t"\
+        "movq "STR(APCK_COEF)"(%%"FF_REG_d"),%%mm1      \n\t" /* filterCoeff */\
+        "pmaddwd                   %%mm1, %%mm0         \n\t"\
+        "pmaddwd                   %%mm1, %%mm3         \n\t"\
+        "paddd                     %%mm0, %%mm4         \n\t"\
+        "paddd                     %%mm3, %%mm5         \n\t"\
+        "add                          %6, %%"FF_REG_S"  \n\t" \
+        "movq  (%%"FF_REG_S", %%"FF_REG_a"), %%mm3      \n\t" /* VsrcData */\
+        "mov "STR(APCK_SIZE)"(%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
+        "add           $"STR(APCK_SIZE)", %%"FF_REG_d"  \n\t"\
+        "test               %%"FF_REG_S", %%"FF_REG_S"  \n\t"\
+        "movq                      %%mm2, %%mm0         \n\t"\
+        "punpcklwd                 %%mm3, %%mm2         \n\t"\
+        "punpckhwd                 %%mm3, %%mm0         \n\t"\
+        "pmaddwd                   %%mm1, %%mm2         \n\t"\
+        "pmaddwd                   %%mm1, %%mm0         \n\t"\
+        "paddd                     %%mm2, %%mm6         \n\t"\
+        "paddd                     %%mm0, %%mm7         \n\t"\
+        " jnz                         2b                \n\t"\
+        "psrad                       $16, %%mm4         \n\t"\
+        "psrad                       $16, %%mm5         \n\t"\
+        "psrad                       $16, %%mm6         \n\t"\
+        "psrad                       $16, %%mm7         \n\t"\
+        "movq      "VROUNDER_OFFSET"(%0), %%mm0         \n\t"\
+        "packssdw                  %%mm5, %%mm4         \n\t"\
+        "packssdw                  %%mm7, %%mm6         \n\t"\
+        "paddw                     %%mm0, %%mm4         \n\t"\
+        "paddw                     %%mm0, %%mm6         \n\t"\
+        "movq                      %%mm4, "U_TEMP"(%0)  \n\t"\
+        "movq                      %%mm6, "V_TEMP"(%0)  \n\t"\
+
+#define YSCALEYUV2PACKEDX_ACCURATE_YA(offset) \
+    "lea                "offset"(%0), %%"FF_REG_d"      \n\t"\
+    "mov                 (%%"FF_REG_d"), %%"FF_REG_S"   \n\t"\
+    "pxor                      %%mm1, %%mm1         \n\t"\
+    "pxor                      %%mm5, %%mm5         \n\t"\
+    "pxor                      %%mm7, %%mm7         \n\t"\
+    "pxor                      %%mm6, %%mm6         \n\t"\
+    ".p2align                      4                \n\t"\
+    "2:                                             \n\t"\
+    "movq  (%%"FF_REG_S", %%"FF_REG_a", 2), %%mm0       \n\t" /* Y1srcData */\
+    "movq 8(%%"FF_REG_S", %%"FF_REG_a", 2), %%mm2       \n\t" /* Y2srcData */\
+    "mov "STR(APCK_PTR2)"(%%"FF_REG_d"), %%"FF_REG_S"   \n\t"\
+    "movq  (%%"FF_REG_S", %%"FF_REG_a", 2), %%mm4       \n\t" /* Y1srcData */\
+    "movq                      %%mm0, %%mm3         \n\t"\
+    "punpcklwd                 %%mm4, %%mm0         \n\t"\
+    "punpckhwd                 %%mm4, %%mm3         \n\t"\
+    "movq "STR(APCK_COEF)"(%%"FF_REG_d"), %%mm4     \n\t" /* filterCoeff */\
+    "pmaddwd                   %%mm4, %%mm0         \n\t"\
+    "pmaddwd                   %%mm4, %%mm3         \n\t"\
+    "paddd                     %%mm0, %%mm1         \n\t"\
+    "paddd                     %%mm3, %%mm5         \n\t"\
+    "movq 8(%%"FF_REG_S", %%"FF_REG_a", 2), %%mm3   \n\t" /* Y2srcData */\
+    "mov "STR(APCK_SIZE)"(%%"FF_REG_d"), %%"FF_REG_S" \n\t"\
+    "add           $"STR(APCK_SIZE)", %%"FF_REG_d"  \n\t"\
+    "test               %%"FF_REG_S", %%"FF_REG_S"  \n\t"\
+    "movq                      %%mm2, %%mm0         \n\t"\
+    "punpcklwd                 %%mm3, %%mm2         \n\t"\
+    "punpckhwd                 %%mm3, %%mm0         \n\t"\
+    "pmaddwd                   %%mm4, %%mm2         \n\t"\
+    "pmaddwd                   %%mm4, %%mm0         \n\t"\
+    "paddd                     %%mm2, %%mm7         \n\t"\
+    "paddd                     %%mm0, %%mm6         \n\t"\
+    " jnz                         2b                \n\t"\
+    "psrad                       $16, %%mm1         \n\t"\
+    "psrad                       $16, %%mm5         \n\t"\
+    "psrad                       $16, %%mm7         \n\t"\
+    "psrad                       $16, %%mm6         \n\t"\
+    "movq      "VROUNDER_OFFSET"(%0), %%mm0         \n\t"\
+    "packssdw                  %%mm5, %%mm1         \n\t"\
+    "packssdw                  %%mm6, %%mm7         \n\t"\
+    "paddw                     %%mm0, %%mm1         \n\t"\
+    "paddw                     %%mm0, %%mm7         \n\t"\
+    "movq               "U_TEMP"(%0), %%mm3         \n\t"\
+    "movq               "V_TEMP"(%0), %%mm4         \n\t"\
+
+#define YSCALEYUV2PACKEDX_ACCURATE \
+    YSCALEYUV2PACKEDX_ACCURATE_UV \
+    YSCALEYUV2PACKEDX_ACCURATE_YA(LUM_MMX_FILTER_OFFSET)
+
+#define YSCALEYUV2RGBX \
+    "psubw  "U_OFFSET"(%0), %%mm3       \n\t" /* (U-128)8*/\
+    "psubw  "V_OFFSET"(%0), %%mm4       \n\t" /* (V-128)8*/\
+    "movq            %%mm3, %%mm2       \n\t" /* (U-128)8*/\
+    "movq            %%mm4, %%mm5       \n\t" /* (V-128)8*/\
+    "pmulhw "UG_COEFF"(%0), %%mm3       \n\t"\
+    "pmulhw "VG_COEFF"(%0), %%mm4       \n\t"\
+    /* mm2=(U-128)8, mm3=ug, mm4=vg mm5=(V-128)8 */\
+    "pmulhw "UB_COEFF"(%0), %%mm2       \n\t"\
+    "pmulhw "VR_COEFF"(%0), %%mm5       \n\t"\
+    "psubw  "Y_OFFSET"(%0), %%mm1       \n\t" /* 8(Y-16)*/\
+    "psubw  "Y_OFFSET"(%0), %%mm7       \n\t" /* 8(Y-16)*/\
+    "pmulhw  "Y_COEFF"(%0), %%mm1       \n\t"\
+    "pmulhw  "Y_COEFF"(%0), %%mm7       \n\t"\
+    /* mm1= Y1, mm2=ub, mm3=ug, mm4=vg mm5=vr, mm7=Y2 */\
+    "paddw           %%mm3, %%mm4       \n\t"\
+    "movq            %%mm2, %%mm0       \n\t"\
+    "movq            %%mm5, %%mm6       \n\t"\
+    "movq            %%mm4, %%mm3       \n\t"\
+    "punpcklwd       %%mm2, %%mm2       \n\t"\
+    "punpcklwd       %%mm5, %%mm5       \n\t"\
+    "punpcklwd       %%mm4, %%mm4       \n\t"\
+    "paddw           %%mm1, %%mm2       \n\t"\
+    "paddw           %%mm1, %%mm5       \n\t"\
+    "paddw           %%mm1, %%mm4       \n\t"\
+    "punpckhwd       %%mm0, %%mm0       \n\t"\
+    "punpckhwd       %%mm6, %%mm6       \n\t"\
+    "punpckhwd       %%mm3, %%mm3       \n\t"\
+    "paddw           %%mm7, %%mm0       \n\t"\
+    "paddw           %%mm7, %%mm6       \n\t"\
+    "paddw           %%mm7, %%mm3       \n\t"\
+    /* mm0=B1, mm2=B2, mm3=G2, mm4=G1, mm5=R1, mm6=R2 */\
+    "packuswb        %%mm0, %%mm2       \n\t"\
+    "packuswb        %%mm6, %%mm5       \n\t"\
+    "packuswb        %%mm3, %%mm4       \n\t"\
+
+#define REAL_WRITEBGR32(dst, dstw, index, b, g, r, a, q0, q2, q3, t) \
+    "movq       "#b", "#q2"     \n\t" /* B */\
+    "movq       "#r", "#t"      \n\t" /* R */\
+    "punpcklbw  "#g", "#b"      \n\t" /* GBGBGBGB 0 */\
+    "punpcklbw  "#a", "#r"      \n\t" /* ARARARAR 0 */\
+    "punpckhbw  "#g", "#q2"     \n\t" /* GBGBGBGB 2 */\
+    "punpckhbw  "#a", "#t"      \n\t" /* ARARARAR 2 */\
+    "movq       "#b", "#q0"     \n\t" /* GBGBGBGB 0 */\
+    "movq      "#q2", "#q3"     \n\t" /* GBGBGBGB 2 */\
+    "punpcklwd  "#r", "#q0"     \n\t" /* ARGBARGB 0 */\
+    "punpckhwd  "#r", "#b"      \n\t" /* ARGBARGB 1 */\
+    "punpcklwd  "#t", "#q2"     \n\t" /* ARGBARGB 2 */\
+    "punpckhwd  "#t", "#q3"     \n\t" /* ARGBARGB 3 */\
+\
+    MOVNTQ(   q0,   (dst, index, 4))\
+    MOVNTQ(    b,  8(dst, index, 4))\
+    MOVNTQ(   q2, 16(dst, index, 4))\
+    MOVNTQ(   q3, 24(dst, index, 4))\
+\
+    "add      $8, "#index"      \n\t"\
+    "cmp  "dstw", "#index"      \n\t"\
+    " jb      1b                \n\t"
+#define WRITEBGR32(dst, dstw, index, b, g, r, a, q0, q2, q3, t)  REAL_WRITEBGR32(dst, dstw, index, b, g, r, a, q0, q2, q3, t)
+
+static void RENAME(yuv2rgb32_X_ar)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+        YSCALEYUV2PACKEDX_ACCURATE
+        YSCALEYUV2RGBX
+        "movq                      %%mm2, "U_TEMP"(%0)  \n\t"
+        "movq                      %%mm4, "V_TEMP"(%0)  \n\t"
+        "movq                      %%mm5, "Y_TEMP"(%0)  \n\t"
+        YSCALEYUV2PACKEDX_ACCURATE_YA(ALP_MMX_FILTER_OFFSET)
+        "movq               "Y_TEMP"(%0), %%mm5         \n\t"
+        "psraw                        $3, %%mm1         \n\t"
+        "psraw                        $3, %%mm7         \n\t"
+        "packuswb                  %%mm7, %%mm1         \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm3, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm2, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    } else {
+        YSCALEYUV2PACKEDX_ACCURATE
+        YSCALEYUV2RGBX
+        "pcmpeqd %%mm7, %%mm7 \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    }
+}
+
+static void RENAME(yuv2rgb32_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+        YSCALEYUV2PACKEDX
+        YSCALEYUV2RGBX
+        YSCALEYUV2PACKEDX_YA(ALP_MMX_FILTER_OFFSET, %%mm0, %%mm3, %%mm6, %%mm1, %%mm7)
+        "psraw                        $3, %%mm1         \n\t"
+        "psraw                        $3, %%mm7         \n\t"
+        "packuswb                  %%mm7, %%mm1         \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    } else {
+        YSCALEYUV2PACKEDX
+        YSCALEYUV2RGBX
+        "pcmpeqd %%mm7, %%mm7 \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    }
+}
+
+static void RENAME(yuv2bgr32_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+        YSCALEYUV2PACKEDX
+        YSCALEYUV2RGBX
+        YSCALEYUV2PACKEDX_YA(ALP_MMX_FILTER_OFFSET, %%mm0, %%mm3, %%mm6, %%mm1, %%mm7)
+        "psraw                        $3, %%mm1         \n\t"
+        "psraw                        $3, %%mm7         \n\t"
+        "packuswb                  %%mm7, %%mm1         \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm5, %%mm4, %%mm2, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    } else {
+        YSCALEYUV2PACKEDX
+        YSCALEYUV2RGBX
+        "pcmpeqd %%mm7, %%mm7 \n\t"
+        WRITEBGR32(%4, "%5", %%FF_REGa, %%mm5, %%mm4, %%mm2, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+        YSCALEYUV2PACKEDX_END
+    }
+}
+
+#define REAL_WRITERGB16(dst, dstw, index) \
+    "pand "MANGLE(bF8)", %%mm2  \n\t" /* B */\
+    "pand "MANGLE(bFC)", %%mm4  \n\t" /* G */\
+    "pand "MANGLE(bF8)", %%mm5  \n\t" /* R */\
+    "psrlq           $3, %%mm2  \n\t"\
+\
+    "movq         %%mm2, %%mm1  \n\t"\
+    "movq         %%mm4, %%mm3  \n\t"\
+\
+    "punpcklbw    %%mm7, %%mm3  \n\t"\
+    "punpcklbw    %%mm5, %%mm2  \n\t"\
+    "punpckhbw    %%mm7, %%mm4  \n\t"\
+    "punpckhbw    %%mm5, %%mm1  \n\t"\
+\
+    "psllq           $3, %%mm3  \n\t"\
+    "psllq           $3, %%mm4  \n\t"\
+\
+    "por          %%mm3, %%mm2  \n\t"\
+    "por          %%mm4, %%mm1  \n\t"\
+\
+    MOVNTQ(%%mm2,  (dst, index, 2))\
+    MOVNTQ(%%mm1, 8(dst, index, 2))\
+\
+    "add             $8, "#index"   \n\t"\
+    "cmp         "dstw", "#index"   \n\t"\
+    " jb             1b             \n\t"
+#define WRITERGB16(dst, dstw, index)  REAL_WRITERGB16(dst, dstw, index)
+
+static void RENAME(yuv2rgb565_X_ar)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX_ACCURATE
+    YSCALEYUV2RGBX
+    "pxor %%mm7, %%mm7 \n\t"
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "paddusb "BLUE_DITHER"(%0), %%mm2\n\t"
+    "paddusb "GREEN_DITHER"(%0), %%mm4\n\t"
+    "paddusb "RED_DITHER"(%0), %%mm5\n\t"
+    WRITERGB16(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+static void RENAME(yuv2rgb565_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX
+    YSCALEYUV2RGBX
+    "pxor %%mm7, %%mm7 \n\t"
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "paddusb "BLUE_DITHER"(%0), %%mm2  \n\t"
+    "paddusb "GREEN_DITHER"(%0), %%mm4  \n\t"
+    "paddusb "RED_DITHER"(%0), %%mm5  \n\t"
+    WRITERGB16(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+#define REAL_WRITERGB15(dst, dstw, index) \
+    "pand "MANGLE(bF8)", %%mm2  \n\t" /* B */\
+    "pand "MANGLE(bF8)", %%mm4  \n\t" /* G */\
+    "pand "MANGLE(bF8)", %%mm5  \n\t" /* R */\
+    "psrlq           $3, %%mm2  \n\t"\
+    "psrlq           $1, %%mm5  \n\t"\
+\
+    "movq         %%mm2, %%mm1  \n\t"\
+    "movq         %%mm4, %%mm3  \n\t"\
+\
+    "punpcklbw    %%mm7, %%mm3  \n\t"\
+    "punpcklbw    %%mm5, %%mm2  \n\t"\
+    "punpckhbw    %%mm7, %%mm4  \n\t"\
+    "punpckhbw    %%mm5, %%mm1  \n\t"\
+\
+    "psllq           $2, %%mm3  \n\t"\
+    "psllq           $2, %%mm4  \n\t"\
+\
+    "por          %%mm3, %%mm2  \n\t"\
+    "por          %%mm4, %%mm1  \n\t"\
+\
+    MOVNTQ(%%mm2,  (dst, index, 2))\
+    MOVNTQ(%%mm1, 8(dst, index, 2))\
+\
+    "add             $8, "#index"   \n\t"\
+    "cmp         "dstw", "#index"   \n\t"\
+    " jb             1b             \n\t"
+#define WRITERGB15(dst, dstw, index)  REAL_WRITERGB15(dst, dstw, index)
+
+static void RENAME(yuv2rgb555_X_ar)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX_ACCURATE
+    YSCALEYUV2RGBX
+    "pxor %%mm7, %%mm7 \n\t"
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "paddusb "BLUE_DITHER"(%0), %%mm2\n\t"
+    "paddusb "GREEN_DITHER"(%0), %%mm4\n\t"
+    "paddusb "RED_DITHER"(%0), %%mm5\n\t"
+    WRITERGB15(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+static void RENAME(yuv2rgb555_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX
+    YSCALEYUV2RGBX
+    "pxor %%mm7, %%mm7 \n\t"
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "paddusb "BLUE_DITHER"(%0), %%mm2  \n\t"
+    "paddusb "GREEN_DITHER"(%0), %%mm4  \n\t"
+    "paddusb "RED_DITHER"(%0), %%mm5  \n\t"
+    WRITERGB15(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+#define WRITEBGR24MMXEXT(dst, dstw, index) \
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */\
+    "movq "MANGLE(M24A)", %%mm0 \n\t"\
+    "movq "MANGLE(M24C)", %%mm7 \n\t"\
+    "pshufw $0x50, %%mm2, %%mm1 \n\t" /* B3 B2 B3 B2  B1 B0 B1 B0 */\
+    "pshufw $0x50, %%mm4, %%mm3 \n\t" /* G3 G2 G3 G2  G1 G0 G1 G0 */\
+    "pshufw $0x00, %%mm5, %%mm6 \n\t" /* R1 R0 R1 R0  R1 R0 R1 R0 */\
+\
+    "pand   %%mm0, %%mm1        \n\t" /*    B2        B1       B0 */\
+    "pand   %%mm0, %%mm3        \n\t" /*    G2        G1       G0 */\
+    "pand   %%mm7, %%mm6        \n\t" /*       R1        R0       */\
+\
+    "psllq     $8, %%mm3        \n\t" /* G2        G1       G0    */\
+    "por    %%mm1, %%mm6        \n\t"\
+    "por    %%mm3, %%mm6        \n\t"\
+    MOVNTQ(%%mm6, (dst))\
+\
+    "psrlq     $8, %%mm4        \n\t" /* 00 G7 G6 G5  G4 G3 G2 G1 */\
+    "pshufw $0xA5, %%mm2, %%mm1 \n\t" /* B5 B4 B5 B4  B3 B2 B3 B2 */\
+    "pshufw $0x55, %%mm4, %%mm3 \n\t" /* G4 G3 G4 G3  G4 G3 G4 G3 */\
+    "pshufw $0xA5, %%mm5, %%mm6 \n\t" /* R5 R4 R5 R4  R3 R2 R3 R2 */\
+\
+    "pand "MANGLE(M24B)", %%mm1 \n\t" /* B5       B4        B3    */\
+    "pand   %%mm7, %%mm3        \n\t" /*       G4        G3       */\
+    "pand   %%mm0, %%mm6        \n\t" /*    R4        R3       R2 */\
+\
+    "por    %%mm1, %%mm3        \n\t" /* B5    G4 B4     G3 B3    */\
+    "por    %%mm3, %%mm6        \n\t"\
+    MOVNTQ(%%mm6, 8(dst))\
+\
+    "pshufw $0xFF, %%mm2, %%mm1 \n\t" /* B7 B6 B7 B6  B7 B6 B6 B7 */\
+    "pshufw $0xFA, %%mm4, %%mm3 \n\t" /* 00 G7 00 G7  G6 G5 G6 G5 */\
+    "pshufw $0xFA, %%mm5, %%mm6 \n\t" /* R7 R6 R7 R6  R5 R4 R5 R4 */\
+\
+    "pand   %%mm7, %%mm1        \n\t" /*       B7        B6       */\
+    "pand   %%mm0, %%mm3        \n\t" /*    G7        G6       G5 */\
+    "pand "MANGLE(M24B)", %%mm6 \n\t" /* R7       R6        R5    */\
+\
+    "por    %%mm1, %%mm3        \n\t"\
+    "por    %%mm3, %%mm6        \n\t"\
+    MOVNTQ(%%mm6, 16(dst))\
+\
+    "add      $24, "#dst"       \n\t"\
+\
+    "add       $8, "#index"     \n\t"\
+    "cmp   "dstw", "#index"     \n\t"\
+    " jb       1b               \n\t"
+
+#undef WRITEBGR24
+#define WRITEBGR24(dst, dstw, index)  WRITEBGR24MMXEXT(dst, dstw, index)
+
+#if HAVE_6REGS
+static void RENAME(yuv2bgr24_X_ar)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX_ACCURATE
+    YSCALEYUV2RGBX
+    "pxor %%mm7, %%mm7 \n\t"
+    "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_c"\n\t" //FIXME optimize
+    "add %4, %%"FF_REG_c"                        \n\t"
+    WRITEBGR24(%%FF_REGc, "%5", %%FF_REGa)
+    :: "r" (&c->redDither),
+       "m" (dummy), "m" (dummy), "m" (dummy),
+       "r" (dest), "m" (dstW_reg), "m"(uv_off)
+       NAMED_CONSTRAINTS_ADD(M24A,M24C,M24B)
+    : "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S
+    );
+}
+
+static void RENAME(yuv2bgr24_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX
+    YSCALEYUV2RGBX
+    "pxor                    %%mm7, %%mm7              \n\t"
+    "lea (%%"FF_REG_a", %%"FF_REG_a", 2), %%"FF_REG_c" \n\t" //FIXME optimize
+    "add                        %4, %%"FF_REG_c"       \n\t"
+    WRITEBGR24(%%FF_REGc, "%5", %%FF_REGa)
+    :: "r" (&c->redDither),
+       "m" (dummy), "m" (dummy), "m" (dummy),
+       "r" (dest),  "m" (dstW_reg), "m"(uv_off)
+       NAMED_CONSTRAINTS_ADD(M24A,M24C,M24B)
+    : "%"FF_REG_a, "%"FF_REG_c, "%"FF_REG_d, "%"FF_REG_S
+    );
+}
+#endif /* HAVE_6REGS */
+
+#define REAL_WRITEYUY2(dst, dstw, index) \
+    "packuswb  %%mm3, %%mm3     \n\t"\
+    "packuswb  %%mm4, %%mm4     \n\t"\
+    "packuswb  %%mm7, %%mm1     \n\t"\
+    "punpcklbw %%mm4, %%mm3     \n\t"\
+    "movq      %%mm1, %%mm7     \n\t"\
+    "punpcklbw %%mm3, %%mm1     \n\t"\
+    "punpckhbw %%mm3, %%mm7     \n\t"\
+\
+    MOVNTQ(%%mm1, (dst, index, 2))\
+    MOVNTQ(%%mm7, 8(dst, index, 2))\
+\
+    "add          $8, "#index"  \n\t"\
+    "cmp      "dstw", "#index"  \n\t"\
+    " jb          1b            \n\t"
+#define WRITEYUY2(dst, dstw, index)  REAL_WRITEYUY2(dst, dstw, index)
+
+static void RENAME(yuv2yuyv422_X_ar)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX_ACCURATE
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "psraw $3, %%mm3    \n\t"
+    "psraw $3, %%mm4    \n\t"
+    "psraw $3, %%mm1    \n\t"
+    "psraw $3, %%mm7    \n\t"
+    WRITEYUY2(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+static void RENAME(yuv2yuyv422_X)(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 dstY)
+{
+    x86_reg dummy=0;
+    x86_reg dstW_reg = dstW;
+    x86_reg uv_off = c->uv_offx2;
+
+    YSCALEYUV2PACKEDX
+    /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+    "psraw $3, %%mm3    \n\t"
+    "psraw $3, %%mm4    \n\t"
+    "psraw $3, %%mm1    \n\t"
+    "psraw $3, %%mm7    \n\t"
+    WRITEYUY2(%4, "%5", %%FF_REGa)
+    YSCALEYUV2PACKEDX_END
+}
+
+#define REAL_YSCALEYUV2RGB_UV(index, c) \
+    "xor            "#index", "#index"  \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm2     \n\t" /* uvbuf0[eax]*/\
+    "movq     (%3, "#index"), %%mm3     \n\t" /* uvbuf1[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm5     \n\t" /* uvbuf0[eax+2048]*/\
+    "movq     (%3, "#index"), %%mm4     \n\t" /* uvbuf1[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "psubw             %%mm3, %%mm2     \n\t" /* uvbuf0[eax] - uvbuf1[eax]*/\
+    "psubw             %%mm4, %%mm5     \n\t" /* uvbuf0[eax+2048] - uvbuf1[eax+2048]*/\
+    "movq "CHR_MMX_FILTER_OFFSET"+8("#c"), %%mm0    \n\t"\
+    "pmulhw            %%mm0, %%mm2     \n\t" /* (uvbuf0[eax] - uvbuf1[eax])uvalpha1>>16*/\
+    "pmulhw            %%mm0, %%mm5     \n\t" /* (uvbuf0[eax+2048] - uvbuf1[eax+2048])uvalpha1>>16*/\
+    "psraw                $4, %%mm3     \n\t" /* uvbuf0[eax] - uvbuf1[eax] >>4*/\
+    "psraw                $4, %%mm4     \n\t" /* uvbuf0[eax+2048] - uvbuf1[eax+2048] >>4*/\
+    "paddw             %%mm2, %%mm3     \n\t" /* uvbuf0[eax]uvalpha1 - uvbuf1[eax](1-uvalpha1)*/\
+    "paddw             %%mm5, %%mm4     \n\t" /* uvbuf0[eax+2048]uvalpha1 - uvbuf1[eax+2048](1-uvalpha1)*/\
+    "psubw  "U_OFFSET"("#c"), %%mm3     \n\t" /* (U-128)8*/\
+    "psubw  "V_OFFSET"("#c"), %%mm4     \n\t" /* (V-128)8*/\
+    "movq              %%mm3, %%mm2     \n\t" /* (U-128)8*/\
+    "movq              %%mm4, %%mm5     \n\t" /* (V-128)8*/\
+    "pmulhw "UG_COEFF"("#c"), %%mm3     \n\t"\
+    "pmulhw "VG_COEFF"("#c"), %%mm4     \n\t"\
+    /* mm2=(U-128)8, mm3=ug, mm4=vg mm5=(V-128)8 */\
+
+#define REAL_YSCALEYUV2RGB_YA(index, c, b1, b2) \
+    "movq  ("#b1", "#index", 2), %%mm0     \n\t" /*buf0[eax]*/\
+    "movq  ("#b2", "#index", 2), %%mm1     \n\t" /*buf1[eax]*/\
+    "movq 8("#b1", "#index", 2), %%mm6     \n\t" /*buf0[eax]*/\
+    "movq 8("#b2", "#index", 2), %%mm7     \n\t" /*buf1[eax]*/\
+    "psubw             %%mm1, %%mm0     \n\t" /* buf0[eax] - buf1[eax]*/\
+    "psubw             %%mm7, %%mm6     \n\t" /* buf0[eax] - buf1[eax]*/\
+    "pmulhw "LUM_MMX_FILTER_OFFSET"+8("#c"), %%mm0  \n\t" /* (buf0[eax] - buf1[eax])yalpha1>>16*/\
+    "pmulhw "LUM_MMX_FILTER_OFFSET"+8("#c"), %%mm6  \n\t" /* (buf0[eax] - buf1[eax])yalpha1>>16*/\
+    "psraw                $4, %%mm1     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "psraw                $4, %%mm7     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "paddw             %%mm0, %%mm1     \n\t" /* buf0[eax]yalpha1 + buf1[eax](1-yalpha1) >>16*/\
+    "paddw             %%mm6, %%mm7     \n\t" /* buf0[eax]yalpha1 + buf1[eax](1-yalpha1) >>16*/\
+
+#define REAL_YSCALEYUV2RGB_COEFF(c) \
+    "pmulhw "UB_COEFF"("#c"), %%mm2     \n\t"\
+    "pmulhw "VR_COEFF"("#c"), %%mm5     \n\t"\
+    "psubw  "Y_OFFSET"("#c"), %%mm1     \n\t" /* 8(Y-16)*/\
+    "psubw  "Y_OFFSET"("#c"), %%mm7     \n\t" /* 8(Y-16)*/\
+    "pmulhw  "Y_COEFF"("#c"), %%mm1     \n\t"\
+    "pmulhw  "Y_COEFF"("#c"), %%mm7     \n\t"\
+    /* mm1= Y1, mm2=ub, mm3=ug, mm4=vg mm5=vr, mm7=Y2 */\
+    "paddw             %%mm3, %%mm4     \n\t"\
+    "movq              %%mm2, %%mm0     \n\t"\
+    "movq              %%mm5, %%mm6     \n\t"\
+    "movq              %%mm4, %%mm3     \n\t"\
+    "punpcklwd         %%mm2, %%mm2     \n\t"\
+    "punpcklwd         %%mm5, %%mm5     \n\t"\
+    "punpcklwd         %%mm4, %%mm4     \n\t"\
+    "paddw             %%mm1, %%mm2     \n\t"\
+    "paddw             %%mm1, %%mm5     \n\t"\
+    "paddw             %%mm1, %%mm4     \n\t"\
+    "punpckhwd         %%mm0, %%mm0     \n\t"\
+    "punpckhwd         %%mm6, %%mm6     \n\t"\
+    "punpckhwd         %%mm3, %%mm3     \n\t"\
+    "paddw             %%mm7, %%mm0     \n\t"\
+    "paddw             %%mm7, %%mm6     \n\t"\
+    "paddw             %%mm7, %%mm3     \n\t"\
+    /* mm0=B1, mm2=B2, mm3=G2, mm4=G1, mm5=R1, mm6=R2 */\
+    "packuswb          %%mm0, %%mm2     \n\t"\
+    "packuswb          %%mm6, %%mm5     \n\t"\
+    "packuswb          %%mm3, %%mm4     \n\t"\
+
+#define YSCALEYUV2RGB_YA(index, c, b1, b2) REAL_YSCALEYUV2RGB_YA(index, c, b1, b2)
+
+#define YSCALEYUV2RGB(index, c) \
+    REAL_YSCALEYUV2RGB_UV(index, c) \
+    REAL_YSCALEYUV2RGB_YA(index, c, %0, %1) \
+    REAL_YSCALEYUV2RGB_COEFF(c)
+
+/**
+ * vertical bilinear scale YV12 to RGB
+ */
+static void RENAME(yuv2rgb32_2)(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];
+
+    if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+        const int16_t *abuf0 = abuf[0], *abuf1 = abuf[1];
+#if ARCH_X86_64
+        __asm__ volatile(
+            YSCALEYUV2RGB(%%r8, %5)
+            YSCALEYUV2RGB_YA(%%r8, %5, %6, %7)
+            "psraw                  $3, %%mm1       \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
+            "psraw                  $3, %%mm7       \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
+            "packuswb            %%mm7, %%mm1       \n\t"
+            WRITEBGR32(%4, DSTW_OFFSET"(%5)", %%r8, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "r" (dest),
+               "a" (&c->redDither),
+               "r" (abuf0), "r" (abuf1)
+            : "%r8"
+        );
+#else
+        c->u_temp=(intptr_t)abuf0;
+        c->v_temp=(intptr_t)abuf1;
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov        %4, %%"FF_REG_b"            \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB(%%FF_REGBP, %5)
+            "push                   %0              \n\t"
+            "push                   %1              \n\t"
+            "mov          "U_TEMP"(%5), %0          \n\t"
+            "mov          "V_TEMP"(%5), %1          \n\t"
+            YSCALEYUV2RGB_YA(%%FF_REGBP, %5, %0, %1)
+            "psraw                  $3, %%mm1       \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
+            "psraw                  $3, %%mm7       \n\t" /* abuf0[eax] - abuf1[eax] >>7*/
+            "packuswb            %%mm7, %%mm1       \n\t"
+            "pop                    %1              \n\t"
+            "pop                    %0              \n\t"
+            WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm1, %%mm0, %%mm7, %%mm3, %%mm6)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+        );
+#endif
+    } else {
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov        %4, %%"FF_REG_b"            \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB(%%FF_REGBP, %5)
+            "pcmpeqd %%mm7, %%mm7                   \n\t"
+            WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+        );
+    }
+}
+
+static void RENAME(yuv2bgr24_2)(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];
+
+    __asm__ volatile(
+        "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+        "mov           %4, %%"FF_REG_b"         \n\t"
+        "push %%"FF_REG_BP"                     \n\t"
+        YSCALEYUV2RGB(%%FF_REGBP, %5)
+        "pxor    %%mm7, %%mm7                   \n\t"
+        WRITEBGR24(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+        "pop %%"FF_REG_BP"                      \n\t"
+        "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+        :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+           "a" (&c->redDither)
+           NAMED_CONSTRAINTS_ADD(M24A,M24C,M24B)
+    );
+}
+
+static void RENAME(yuv2rgb555_2)(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];
+
+    __asm__ volatile(
+        "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+        "mov        %4, %%"FF_REG_b"            \n\t"
+        "push %%"FF_REG_BP"                     \n\t"
+        YSCALEYUV2RGB(%%FF_REGBP, %5)
+        "pxor    %%mm7, %%mm7                   \n\t"
+        /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+        "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+        "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+        "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+        WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+        "pop %%"FF_REG_BP"                      \n\t"
+        "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+        :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+           "a" (&c->redDither)
+           NAMED_CONSTRAINTS_ADD(bF8)
+    );
+}
+
+static void RENAME(yuv2rgb565_2)(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];
+
+    __asm__ volatile(
+        "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+        "mov           %4, %%"FF_REG_b"         \n\t"
+        "push %%"FF_REG_BP"                     \n\t"
+        YSCALEYUV2RGB(%%FF_REGBP, %5)
+        "pxor    %%mm7, %%mm7                   \n\t"
+        /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+        "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+        "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+        "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+        WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+        "pop %%"FF_REG_BP"                      \n\t"
+        "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+        :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+           "a" (&c->redDither)
+           NAMED_CONSTRAINTS_ADD(bF8,bFC)
+    );
+}
+
+#define REAL_YSCALEYUV2PACKED(index, c) \
+    "movq "CHR_MMX_FILTER_OFFSET"+8("#c"), %%mm0              \n\t"\
+    "movq "LUM_MMX_FILTER_OFFSET"+8("#c"), %%mm1              \n\t"\
+    "psraw                $3, %%mm0                           \n\t"\
+    "psraw                $3, %%mm1                           \n\t"\
+    "movq              %%mm0, "CHR_MMX_FILTER_OFFSET"+8("#c") \n\t"\
+    "movq              %%mm1, "LUM_MMX_FILTER_OFFSET"+8("#c") \n\t"\
+    "xor            "#index", "#index"                        \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm2     \n\t" /* uvbuf0[eax]*/\
+    "movq     (%3, "#index"), %%mm3     \n\t" /* uvbuf1[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm5     \n\t" /* uvbuf0[eax+2048]*/\
+    "movq     (%3, "#index"), %%mm4     \n\t" /* uvbuf1[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "psubw             %%mm3, %%mm2     \n\t" /* uvbuf0[eax] - uvbuf1[eax]*/\
+    "psubw             %%mm4, %%mm5     \n\t" /* uvbuf0[eax+2048] - uvbuf1[eax+2048]*/\
+    "movq "CHR_MMX_FILTER_OFFSET"+8("#c"), %%mm0    \n\t"\
+    "pmulhw            %%mm0, %%mm2     \n\t" /* (uvbuf0[eax] - uvbuf1[eax])uvalpha1>>16*/\
+    "pmulhw            %%mm0, %%mm5     \n\t" /* (uvbuf0[eax+2048] - uvbuf1[eax+2048])uvalpha1>>16*/\
+    "psraw                $7, %%mm3     \n\t" /* uvbuf0[eax] - uvbuf1[eax] >>4*/\
+    "psraw                $7, %%mm4     \n\t" /* uvbuf0[eax+2048] - uvbuf1[eax+2048] >>4*/\
+    "paddw             %%mm2, %%mm3     \n\t" /* uvbuf0[eax]uvalpha1 - uvbuf1[eax](1-uvalpha1)*/\
+    "paddw             %%mm5, %%mm4     \n\t" /* uvbuf0[eax+2048]uvalpha1 - uvbuf1[eax+2048](1-uvalpha1)*/\
+    "movq  (%0, "#index", 2), %%mm0     \n\t" /*buf0[eax]*/\
+    "movq  (%1, "#index", 2), %%mm1     \n\t" /*buf1[eax]*/\
+    "movq 8(%0, "#index", 2), %%mm6     \n\t" /*buf0[eax]*/\
+    "movq 8(%1, "#index", 2), %%mm7     \n\t" /*buf1[eax]*/\
+    "psubw             %%mm1, %%mm0     \n\t" /* buf0[eax] - buf1[eax]*/\
+    "psubw             %%mm7, %%mm6     \n\t" /* buf0[eax] - buf1[eax]*/\
+    "pmulhw "LUM_MMX_FILTER_OFFSET"+8("#c"), %%mm0  \n\t" /* (buf0[eax] - buf1[eax])yalpha1>>16*/\
+    "pmulhw "LUM_MMX_FILTER_OFFSET"+8("#c"), %%mm6  \n\t" /* (buf0[eax] - buf1[eax])yalpha1>>16*/\
+    "psraw                $7, %%mm1     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "psraw                $7, %%mm7     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "paddw             %%mm0, %%mm1     \n\t" /* buf0[eax]yalpha1 + buf1[eax](1-yalpha1) >>16*/\
+    "paddw             %%mm6, %%mm7     \n\t" /* buf0[eax]yalpha1 + buf1[eax](1-yalpha1) >>16*/\
+
+#define YSCALEYUV2PACKED(index, c)  REAL_YSCALEYUV2PACKED(index, c)
+
+static void RENAME(yuv2yuyv422_2)(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];
+
+    __asm__ volatile(
+        "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+        "mov           %4, %%"FF_REG_b"         \n\t"
+        "push %%"FF_REG_BP"                     \n\t"
+        YSCALEYUV2PACKED(%%FF_REGBP, %5)
+        WRITEYUY2(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+        "pop %%"FF_REG_BP"                      \n\t"
+        "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+        :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+           "a" (&c->redDither)
+    );
+}
+
+#define REAL_YSCALEYUV2RGB1(index, c) \
+    "xor            "#index", "#index"  \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm3     \n\t" /* uvbuf0[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm4     \n\t" /* uvbuf0[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "psraw                $4, %%mm3     \n\t" /* uvbuf0[eax] - uvbuf1[eax] >>4*/\
+    "psraw                $4, %%mm4     \n\t" /* uvbuf0[eax+2048] - uvbuf1[eax+2048] >>4*/\
+    "psubw  "U_OFFSET"("#c"), %%mm3     \n\t" /* (U-128)8*/\
+    "psubw  "V_OFFSET"("#c"), %%mm4     \n\t" /* (V-128)8*/\
+    "movq              %%mm3, %%mm2     \n\t" /* (U-128)8*/\
+    "movq              %%mm4, %%mm5     \n\t" /* (V-128)8*/\
+    "pmulhw "UG_COEFF"("#c"), %%mm3     \n\t"\
+    "pmulhw "VG_COEFF"("#c"), %%mm4     \n\t"\
+    /* mm2=(U-128)8, mm3=ug, mm4=vg mm5=(V-128)8 */\
+    "movq  (%0, "#index", 2), %%mm1     \n\t" /*buf0[eax]*/\
+    "movq 8(%0, "#index", 2), %%mm7     \n\t" /*buf0[eax]*/\
+    "psraw                $4, %%mm1     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "psraw                $4, %%mm7     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "pmulhw "UB_COEFF"("#c"), %%mm2     \n\t"\
+    "pmulhw "VR_COEFF"("#c"), %%mm5     \n\t"\
+    "psubw  "Y_OFFSET"("#c"), %%mm1     \n\t" /* 8(Y-16)*/\
+    "psubw  "Y_OFFSET"("#c"), %%mm7     \n\t" /* 8(Y-16)*/\
+    "pmulhw  "Y_COEFF"("#c"), %%mm1     \n\t"\
+    "pmulhw  "Y_COEFF"("#c"), %%mm7     \n\t"\
+    /* mm1= Y1, mm2=ub, mm3=ug, mm4=vg mm5=vr, mm7=Y2 */\
+    "paddw             %%mm3, %%mm4     \n\t"\
+    "movq              %%mm2, %%mm0     \n\t"\
+    "movq              %%mm5, %%mm6     \n\t"\
+    "movq              %%mm4, %%mm3     \n\t"\
+    "punpcklwd         %%mm2, %%mm2     \n\t"\
+    "punpcklwd         %%mm5, %%mm5     \n\t"\
+    "punpcklwd         %%mm4, %%mm4     \n\t"\
+    "paddw             %%mm1, %%mm2     \n\t"\
+    "paddw             %%mm1, %%mm5     \n\t"\
+    "paddw             %%mm1, %%mm4     \n\t"\
+    "punpckhwd         %%mm0, %%mm0     \n\t"\
+    "punpckhwd         %%mm6, %%mm6     \n\t"\
+    "punpckhwd         %%mm3, %%mm3     \n\t"\
+    "paddw             %%mm7, %%mm0     \n\t"\
+    "paddw             %%mm7, %%mm6     \n\t"\
+    "paddw             %%mm7, %%mm3     \n\t"\
+    /* mm0=B1, mm2=B2, mm3=G2, mm4=G1, mm5=R1, mm6=R2 */\
+    "packuswb          %%mm0, %%mm2     \n\t"\
+    "packuswb          %%mm6, %%mm5     \n\t"\
+    "packuswb          %%mm3, %%mm4     \n\t"\
+
+#define YSCALEYUV2RGB1(index, c)  REAL_YSCALEYUV2RGB1(index, c)
+
+// do vertical chrominance interpolation
+#define REAL_YSCALEYUV2RGB1b(index, c) \
+    "xor            "#index", "#index"  \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm2     \n\t" /* uvbuf0[eax]*/\
+    "movq     (%3, "#index"), %%mm3     \n\t" /* uvbuf1[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm5     \n\t" /* uvbuf0[eax+2048]*/\
+    "movq     (%3, "#index"), %%mm4     \n\t" /* uvbuf1[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "paddw             %%mm2, %%mm3     \n\t" /* uvbuf0[eax] + uvbuf1[eax]*/\
+    "paddw             %%mm5, %%mm4     \n\t" /* uvbuf0[eax+2048] + uvbuf1[eax+2048]*/\
+    "psrlw                $5, %%mm3     \n\t" /*FIXME might overflow*/\
+    "psrlw                $5, %%mm4     \n\t" /*FIXME might overflow*/\
+    "psubw  "U_OFFSET"("#c"), %%mm3     \n\t" /* (U-128)8*/\
+    "psubw  "V_OFFSET"("#c"), %%mm4     \n\t" /* (V-128)8*/\
+    "movq              %%mm3, %%mm2     \n\t" /* (U-128)8*/\
+    "movq              %%mm4, %%mm5     \n\t" /* (V-128)8*/\
+    "pmulhw "UG_COEFF"("#c"), %%mm3     \n\t"\
+    "pmulhw "VG_COEFF"("#c"), %%mm4     \n\t"\
+    /* mm2=(U-128)8, mm3=ug, mm4=vg mm5=(V-128)8 */\
+    "movq  (%0, "#index", 2), %%mm1     \n\t" /*buf0[eax]*/\
+    "movq 8(%0, "#index", 2), %%mm7     \n\t" /*buf0[eax]*/\
+    "psraw                $4, %%mm1     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "psraw                $4, %%mm7     \n\t" /* buf0[eax] - buf1[eax] >>4*/\
+    "pmulhw "UB_COEFF"("#c"), %%mm2     \n\t"\
+    "pmulhw "VR_COEFF"("#c"), %%mm5     \n\t"\
+    "psubw  "Y_OFFSET"("#c"), %%mm1     \n\t" /* 8(Y-16)*/\
+    "psubw  "Y_OFFSET"("#c"), %%mm7     \n\t" /* 8(Y-16)*/\
+    "pmulhw  "Y_COEFF"("#c"), %%mm1     \n\t"\
+    "pmulhw  "Y_COEFF"("#c"), %%mm7     \n\t"\
+    /* mm1= Y1, mm2=ub, mm3=ug, mm4=vg mm5=vr, mm7=Y2 */\
+    "paddw             %%mm3, %%mm4     \n\t"\
+    "movq              %%mm2, %%mm0     \n\t"\
+    "movq              %%mm5, %%mm6     \n\t"\
+    "movq              %%mm4, %%mm3     \n\t"\
+    "punpcklwd         %%mm2, %%mm2     \n\t"\
+    "punpcklwd         %%mm5, %%mm5     \n\t"\
+    "punpcklwd         %%mm4, %%mm4     \n\t"\
+    "paddw             %%mm1, %%mm2     \n\t"\
+    "paddw             %%mm1, %%mm5     \n\t"\
+    "paddw             %%mm1, %%mm4     \n\t"\
+    "punpckhwd         %%mm0, %%mm0     \n\t"\
+    "punpckhwd         %%mm6, %%mm6     \n\t"\
+    "punpckhwd         %%mm3, %%mm3     \n\t"\
+    "paddw             %%mm7, %%mm0     \n\t"\
+    "paddw             %%mm7, %%mm6     \n\t"\
+    "paddw             %%mm7, %%mm3     \n\t"\
+    /* mm0=B1, mm2=B2, mm3=G2, mm4=G1, mm5=R1, mm6=R2 */\
+    "packuswb          %%mm0, %%mm2     \n\t"\
+    "packuswb          %%mm6, %%mm5     \n\t"\
+    "packuswb          %%mm3, %%mm4     \n\t"\
+
+#define YSCALEYUV2RGB1b(index, c)  REAL_YSCALEYUV2RGB1b(index, c)
+
+#define REAL_YSCALEYUV2RGB1_ALPHA(index) \
+    "movq  (%1, "#index", 2), %%mm7     \n\t" /* abuf0[index  ]     */\
+    "movq 8(%1, "#index", 2), %%mm1     \n\t" /* abuf0[index+4]     */\
+    "psraw                $7, %%mm7     \n\t" /* abuf0[index  ] >>7 */\
+    "psraw                $7, %%mm1     \n\t" /* abuf0[index+4] >>7 */\
+    "packuswb          %%mm1, %%mm7     \n\t"
+#define YSCALEYUV2RGB1_ALPHA(index) REAL_YSCALEYUV2RGB1_ALPHA(index)
+
+/**
+ * YV12 to RGB without scaling or interpolating
+ */
+static void RENAME(yuv2rgb32_1)(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 int16_t *ubuf0 = ubuf[0];
+    const int16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
+
+    if (uvalpha < 2048) { // note this is not correct (shifts chrominance by 0.5 pixels) but it is a bit faster
+        const int16_t *ubuf1 = ubuf[0];
+        if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+            __asm__ volatile(
+                "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+                "mov           %4, %%"FF_REG_b"         \n\t"
+                "push %%"FF_REG_BP"                     \n\t"
+                YSCALEYUV2RGB1(%%FF_REGBP, %5)
+                YSCALEYUV2RGB1_ALPHA(%%FF_REGBP)
+                WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+                "pop %%"FF_REG_BP"                      \n\t"
+                "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+                :: "c" (buf0), "d" (abuf0), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+                   "a" (&c->redDither)
+            );
+        } else {
+            __asm__ volatile(
+                "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+                "mov           %4, %%"FF_REG_b"         \n\t"
+                "push %%"FF_REG_BP"                     \n\t"
+                YSCALEYUV2RGB1(%%FF_REGBP, %5)
+                "pcmpeqd %%mm7, %%mm7                   \n\t"
+                WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+                "pop %%"FF_REG_BP"                      \n\t"
+                "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+                :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+                   "a" (&c->redDither)
+            );
+        }
+    } else {
+        const int16_t *ubuf1 = ubuf[1];
+        if (CONFIG_SWSCALE_ALPHA && c->needAlpha) {
+            __asm__ volatile(
+                "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+                "mov           %4, %%"FF_REG_b"         \n\t"
+                "push %%"FF_REG_BP"                     \n\t"
+                YSCALEYUV2RGB1b(%%FF_REGBP, %5)
+                YSCALEYUV2RGB1_ALPHA(%%FF_REGBP)
+                WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+                "pop %%"FF_REG_BP"                      \n\t"
+                "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+                :: "c" (buf0), "d" (abuf0), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+                   "a" (&c->redDither)
+            );
+        } else {
+            __asm__ volatile(
+                "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+                "mov           %4, %%"FF_REG_b"         \n\t"
+                "push %%"FF_REG_BP"                     \n\t"
+                YSCALEYUV2RGB1b(%%FF_REGBP, %5)
+                "pcmpeqd %%mm7, %%mm7                   \n\t"
+                WRITEBGR32(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP, %%mm2, %%mm4, %%mm5, %%mm7, %%mm0, %%mm1, %%mm3, %%mm6)
+                "pop %%"FF_REG_BP"                      \n\t"
+                "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+                :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+                   "a" (&c->redDither)
+            );
+        }
+    }
+}
+
+static void RENAME(yuv2bgr24_1)(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 int16_t *ubuf0 = ubuf[0];
+    const int16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
+
+    if (uvalpha < 2048) { // note this is not correct (shifts chrominance by 0.5 pixels) but it is a bit faster
+        const int16_t *ubuf1 = ubuf[0];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            WRITEBGR24(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(M24A,M24C,M24B)
+        );
+    } else {
+        const int16_t *ubuf1 = ubuf[1];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1b(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            WRITEBGR24(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(M24A,M24C,M24B)
+        );
+    }
+}
+
+static void RENAME(yuv2rgb555_1)(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 int16_t *ubuf0 = ubuf[0];
+    const int16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
+
+    if (uvalpha < 2048) { // note this is not correct (shifts chrominance by 0.5 pixels) but it is a bit faster
+        const int16_t *ubuf1 = ubuf[0];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+            "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+            "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+            "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+            WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(bF8)
+        );
+    } else {
+        const int16_t *ubuf1 = ubuf[1];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1b(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+            "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+            "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+            "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+            WRITERGB15(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(bF8)
+        );
+    }
+}
+
+static void RENAME(yuv2rgb565_1)(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 int16_t *ubuf0 = ubuf[0];
+    const int16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
+
+    if (uvalpha < 2048) { // note this is not correct (shifts chrominance by 0.5 pixels) but it is a bit faster
+        const int16_t *ubuf1 = ubuf[0];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+            "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+            "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+            "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+            WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(bF8,bFC)
+        );
+    } else {
+        const int16_t *ubuf1 = ubuf[1];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2RGB1b(%%FF_REGBP, %5)
+            "pxor    %%mm7, %%mm7                   \n\t"
+            /* mm2=B, %%mm4=G, %%mm5=R, %%mm7=0 */
+            "paddusb "BLUE_DITHER"(%5), %%mm2       \n\t"
+            "paddusb "GREEN_DITHER"(%5), %%mm4      \n\t"
+            "paddusb "RED_DITHER"(%5), %%mm5        \n\t"
+            WRITERGB16(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+               NAMED_CONSTRAINTS_ADD(bF8,bFC)
+        );
+    }
+}
+
+#define REAL_YSCALEYUV2PACKED1(index, c) \
+    "xor            "#index", "#index"  \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm3     \n\t" /* uvbuf0[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm4     \n\t" /* uvbuf0[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "psraw                $7, %%mm3     \n\t" \
+    "psraw                $7, %%mm4     \n\t" \
+    "movq  (%0, "#index", 2), %%mm1     \n\t" /*buf0[eax]*/\
+    "movq 8(%0, "#index", 2), %%mm7     \n\t" /*buf0[eax]*/\
+    "psraw                $7, %%mm1     \n\t" \
+    "psraw                $7, %%mm7     \n\t" \
+
+#define YSCALEYUV2PACKED1(index, c)  REAL_YSCALEYUV2PACKED1(index, c)
+
+#define REAL_YSCALEYUV2PACKED1b(index, c) \
+    "xor "#index", "#index"             \n\t"\
+    ".p2align              4            \n\t"\
+    "1:                                 \n\t"\
+    "movq     (%2, "#index"), %%mm2     \n\t" /* uvbuf0[eax]*/\
+    "movq     (%3, "#index"), %%mm3     \n\t" /* uvbuf1[eax]*/\
+    "add "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "movq     (%2, "#index"), %%mm5     \n\t" /* uvbuf0[eax+2048]*/\
+    "movq     (%3, "#index"), %%mm4     \n\t" /* uvbuf1[eax+2048]*/\
+    "sub "UV_OFF_BYTE"("#c"), "#index"  \n\t" \
+    "paddw             %%mm2, %%mm3     \n\t" /* uvbuf0[eax] + uvbuf1[eax]*/\
+    "paddw             %%mm5, %%mm4     \n\t" /* uvbuf0[eax+2048] + uvbuf1[eax+2048]*/\
+    "psrlw                $8, %%mm3     \n\t" \
+    "psrlw                $8, %%mm4     \n\t" \
+    "movq  (%0, "#index", 2), %%mm1     \n\t" /*buf0[eax]*/\
+    "movq 8(%0, "#index", 2), %%mm7     \n\t" /*buf0[eax]*/\
+    "psraw                $7, %%mm1     \n\t" \
+    "psraw                $7, %%mm7     \n\t"
+#define YSCALEYUV2PACKED1b(index, c)  REAL_YSCALEYUV2PACKED1b(index, c)
+
+static void RENAME(yuv2yuyv422_1)(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 int16_t *ubuf0 = ubuf[0];
+    const int16_t *buf1= buf0; //FIXME needed for RGB1/BGR1
+
+    if (uvalpha < 2048) { // note this is not correct (shifts chrominance by 0.5 pixels) but it is a bit faster
+        const int16_t *ubuf1 = ubuf[0];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2PACKED1(%%FF_REGBP, %5)
+            WRITEYUY2(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+        );
+    } else {
+        const int16_t *ubuf1 = ubuf[1];
+        __asm__ volatile(
+            "mov %%"FF_REG_b", "ESP_OFFSET"(%5)     \n\t"
+            "mov           %4, %%"FF_REG_b"         \n\t"
+            "push %%"FF_REG_BP"                     \n\t"
+            YSCALEYUV2PACKED1b(%%FF_REGBP, %5)
+            WRITEYUY2(%%FF_REGb, DSTW_OFFSET"(%5)", %%FF_REGBP)
+            "pop %%"FF_REG_BP"                      \n\t"
+            "mov "ESP_OFFSET"(%5), %%"FF_REG_b"     \n\t"
+            :: "c" (buf0), "d" (buf1), "S" (ubuf0), "D" (ubuf1), "m" (dest),
+               "a" (&c->redDither)
+        );
+    }
+}
+static av_cold void RENAME(sws_init_swscale)(SwsInternal *c)
+{
+    enum AVPixelFormat dstFormat = c->opts.dst_format;
+
+    c->use_mmx_vfilter= 0;
+    if (!is16BPS(dstFormat) && !isNBPS(dstFormat) && !isSemiPlanarYUV(dstFormat)
+        && dstFormat != AV_PIX_FMT_GRAYF32BE && dstFormat != AV_PIX_FMT_GRAYF32LE
+        && !(c->opts.flags & SWS_BITEXACT)) {
+            if (c->opts.flags & SWS_ACCURATE_RND) {
+                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+                    switch (c->opts.dst_format) {
+                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = RENAME(yuv2rgb32_X_ar);   break;
+#if HAVE_6REGS
+                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = RENAME(yuv2bgr24_X_ar);   break;
+#endif
+                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = RENAME(yuv2rgb555_X_ar);  break;
+                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = RENAME(yuv2rgb565_X_ar);  break;
+                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = RENAME(yuv2yuyv422_X_ar); break;
+                    default: break;
+                    }
+                }
+            } else {
+                c->use_mmx_vfilter= 1;
+                if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+                    switch (c->opts.dst_format) {
+                    case AV_PIX_FMT_RGB32:   c->yuv2packedX = RENAME(yuv2rgb32_X);   break;
+                    case AV_PIX_FMT_BGR32:   c->yuv2packedX = RENAME(yuv2bgr32_X);   break;
+#if HAVE_6REGS
+                    case AV_PIX_FMT_BGR24:   c->yuv2packedX = RENAME(yuv2bgr24_X);   break;
+#endif
+                    case AV_PIX_FMT_RGB555:  c->yuv2packedX = RENAME(yuv2rgb555_X);  break;
+                    case AV_PIX_FMT_RGB565:  c->yuv2packedX = RENAME(yuv2rgb565_X);  break;
+                    case AV_PIX_FMT_YUYV422: c->yuv2packedX = RENAME(yuv2yuyv422_X); break;
+                    default: break;
+                    }
+                }
+            }
+        if (!(c->opts.flags & SWS_FULL_CHR_H_INT)) {
+            switch (c->opts.dst_format) {
+            case AV_PIX_FMT_RGB32:
+                c->yuv2packed1 = RENAME(yuv2rgb32_1);
+                c->yuv2packed2 = RENAME(yuv2rgb32_2);
+                break;
+            case AV_PIX_FMT_BGR24:
+                c->yuv2packed1 = RENAME(yuv2bgr24_1);
+                c->yuv2packed2 = RENAME(yuv2bgr24_2);
+                break;
+            case AV_PIX_FMT_RGB555:
+                c->yuv2packed1 = RENAME(yuv2rgb555_1);
+                c->yuv2packed2 = RENAME(yuv2rgb555_2);
+                break;
+            case AV_PIX_FMT_RGB565:
+                c->yuv2packed1 = RENAME(yuv2rgb565_1);
+                c->yuv2packed2 = RENAME(yuv2rgb565_2);
+                break;
+            case AV_PIX_FMT_YUYV422:
+                c->yuv2packed1 = RENAME(yuv2yuyv422_1);
+                c->yuv2packed2 = RENAME(yuv2yuyv422_2);
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+    if (c->srcBpc == 8 && c->dstBpc <= 14) {
+        // Use the new MMX scaler if the MMXEXT one can't be used (it is faster than the x86 ASM one).
+        if (c->opts.flags & SWS_FAST_BILINEAR && c->canMMXEXTBeUsed) {
+            c->hyscale_fast = ff_hyscale_fast_mmxext;
+            c->hcscale_fast = ff_hcscale_fast_mmxext;
+        } else {
+            c->hyscale_fast = NULL;
+            c->hcscale_fast = NULL;
+        }
+    }
+}
diff --git a/libs/ffmpeg/libswscale/x86/yuv2rgb.c b/libs/ffmpeg/libswscale/x86/yuv2rgb.c
new file mode 100644
index 000000000000..14ff41117b62
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/yuv2rgb.c
@@ -0,0 +1,285 @@
+/*
+ * software YUV to RGB converter
+ *
+ * Copyright (C) 2001-2007 Michael Niedermayer
+ * Copyright (C) 2009-2010 Konstantin Shishkov
+ *
+ * MMX/MMXEXT template stuff (needed for fast movntq support),
+ * 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
+ */
+
+#if defined HAVE_NASM && defined __WINE_PE_BUILD && (defined __i386__ || (defined __x86_64__ && !defined __arm64ec__))
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include "config.h"
+#include "libswscale/rgb2rgb.h"
+#include "libswscale/swscale.h"
+#include "libswscale/swscale_internal.h"
+#include "libavutil/attributes.h"
+#include "libavutil/x86/asm.h"
+#include "libavutil/x86/cpu.h"
+#include "libavutil/cpu.h"
+
+#if HAVE_X86ASM
+
+#define YUV2RGB_LOOP(depth)                                          \
+    h_size = (c->opts.dst_w + 7) & ~7;                               \
+    if (h_size * depth > FFABS(dstStride[0]))                        \
+        h_size -= 8;                                                 \
+                                                                     \
+    vshift = c->opts.src_format != AV_PIX_FMT_YUV422P;               \
+                                                                     \
+    for (y = 0; y < srcSliceH; y++) {                                \
+        uint8_t *image    = dst[0] + (y + srcSliceY) * dstStride[0]; \
+        const uint8_t *py = src[0] +               y * srcStride[0]; \
+        const uint8_t *pu = src[1] +   (y >> vshift) * srcStride[1]; \
+        const uint8_t *pv = src[2] +   (y >> vshift) * srcStride[2]; \
+        x86_reg index = -h_size / 2;                                 \
+
+extern void ff_yuv_420_rgb24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+extern void ff_yuv_420_bgr24_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+
+extern void ff_yuv_420_rgb15_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+extern void ff_yuv_420_rgb16_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+extern void ff_yuv_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+extern void ff_yuv_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                   const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                   const uint8_t *py_2index);
+extern void ff_yuva_420_rgb32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                    const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                    const uint8_t *py_2index, const uint8_t *pa_2index);
+extern void ff_yuva_420_bgr32_ssse3(x86_reg index, uint8_t *image, const uint8_t *pu_index,
+                                    const uint8_t *pv_index, const uint64_t *pointer_c_dither,
+                                    const uint8_t *py_2index, const uint8_t *pa_2index);
+#if ARCH_X86_64
+extern void ff_yuv_420_gbrp24_ssse3(x86_reg index, uint8_t *image, uint8_t *dst_b, uint8_t *dst_r,
+                                    const uint8_t *pu_index, const uint8_t *pv_index,
+                                    const uint64_t *pointer_c_dither,
+                                    const uint8_t *py_2index);
+#endif
+
+static inline int yuv420_rgb15_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(2)
+
+        c->blueDither  = ff_dither8[y       & 1];
+        c->greenDither = ff_dither8[y       & 1];
+        c->redDither   = ff_dither8[(y + 1) & 1];
+
+        ff_yuv_420_rgb15_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuv420_rgb16_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(2)
+
+        c->blueDither  = ff_dither8[y       & 1];
+        c->greenDither = ff_dither4[y       & 1];
+        c->redDither   = ff_dither8[(y + 1) & 1];
+
+        ff_yuv_420_rgb16_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuv420_rgb32_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(4)
+
+        ff_yuv_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuv420_bgr32_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(4)
+
+        ff_yuv_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuva420_rgb32_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                      const int srcStride[],
+                                      int srcSliceY, int srcSliceH,
+                                      uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+    YUV2RGB_LOOP(4)
+
+        const uint8_t *pa = src[3] + y * srcStride[3];
+        ff_yuva_420_rgb32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuva420_bgr32_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                      const int srcStride[],
+                                      int srcSliceY, int srcSliceH,
+                                      uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(4)
+
+        const uint8_t *pa = src[3] + y * srcStride[3];
+        ff_yuva_420_bgr32_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index, pa - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuv420_rgb24_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(3)
+
+        ff_yuv_420_rgb24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+static inline int yuv420_bgr24_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                     const int srcStride[],
+                                     int srcSliceY, int srcSliceH,
+                                     uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    YUV2RGB_LOOP(3)
+
+        ff_yuv_420_bgr24_ssse3(index, image, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+
+#if ARCH_X86_64
+static inline int yuv420_gbrp_ssse3(SwsInternal *c, const uint8_t *const src[],
+                                    const int srcStride[],
+                                    int srcSliceY, int srcSliceH,
+                                    uint8_t *const dst[], const int dstStride[])
+{
+    int y, h_size, vshift;
+
+    h_size = (c->opts.dst_w + 7) & ~7;
+    if (h_size * 3 > FFABS(dstStride[0]))
+        h_size -= 8;
+
+    vshift = c->opts.src_format != AV_PIX_FMT_YUV422P;
+
+    for (y = 0; y < srcSliceH; y++) {
+        uint8_t *dst_g    = dst[0] + (y + srcSliceY) * dstStride[0];
+        uint8_t *dst_b    = dst[1] + (y + srcSliceY) * dstStride[1];
+        uint8_t *dst_r    = dst[2] + (y + srcSliceY) * dstStride[2];
+        const uint8_t *py = src[0] +               y * srcStride[0];
+        const uint8_t *pu = src[1] +   (y >> vshift) * srcStride[1];
+        const uint8_t *pv = src[2] +   (y >> vshift) * srcStride[2];
+        x86_reg index = -h_size / 2;
+
+        ff_yuv_420_gbrp24_ssse3(index, dst_g, dst_b, dst_r, pu - index, pv - index, &(c->redDither), py - 2 * index);
+    }
+    return srcSliceH;
+}
+#endif
+
+#endif /* HAVE_X86ASM */
+
+av_cold SwsFunc ff_yuv2rgb_init_x86(SwsInternal *c)
+{
+#if HAVE_X86ASM
+    int cpu_flags = av_get_cpu_flags();
+
+    if (EXTERNAL_SSSE3(cpu_flags)) {
+        switch (c->opts.dst_format) {
+        case AV_PIX_FMT_RGB32:
+            if (c->opts.src_format == AV_PIX_FMT_YUVA420P) {
+#if CONFIG_SWSCALE_ALPHA
+                return yuva420_rgb32_ssse3;
+#endif
+                break;
+            } else
+                return yuv420_rgb32_ssse3;
+        case AV_PIX_FMT_BGR32:
+            if (c->opts.src_format == AV_PIX_FMT_YUVA420P) {
+#if CONFIG_SWSCALE_ALPHA
+                return yuva420_bgr32_ssse3;
+#endif
+                break;
+            } else
+                return yuv420_bgr32_ssse3;
+        case AV_PIX_FMT_RGB24:
+            return yuv420_rgb24_ssse3;
+        case AV_PIX_FMT_BGR24:
+            return yuv420_bgr24_ssse3;
+        case AV_PIX_FMT_RGB565:
+            return yuv420_rgb16_ssse3;
+        case AV_PIX_FMT_RGB555:
+            return yuv420_rgb15_ssse3;
+#if ARCH_X86_64
+        case AV_PIX_FMT_GBRP:
+            return yuv420_gbrp_ssse3;
+#endif
+        }
+    }
+
+#endif /* HAVE_X86ASM */
+    return NULL;
+}
+
+#endif
diff --git a/libs/ffmpeg/libswscale/x86/yuv2yuvX.asm b/libs/ffmpeg/libswscale/x86/yuv2yuvX.asm
new file mode 100644
index 000000000000..7137be2e1784
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/yuv2yuvX.asm
@@ -0,0 +1,134 @@
+;******************************************************************************
+;* x86-optimized yuv2yuvX
+;* Copyright 2020 Google LLC
+;* 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 "libavutil/x86/x86util.asm"
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; yuv2yuvX
+;
+; void ff_yuv2yuvX_<opt>(const int16_t *filter, int filterSize,
+;                        int srcOffset, uint8_t *dest, int dstW,
+;                        const uint8_t *dither, int offset);
+;
+;-----------------------------------------------------------------------------
+
+%macro YUV2YUVX_FUNC 0
+cglobal yuv2yuvX, 7, 7, 8, filter, filterSize, src, dest, dstW, dither, offset
+%if notcpuflag(sse3)
+%define movr mova
+%define unroll 1
+%else
+%define movr movdqu
+%define unroll 2
+%endif
+    movsxdifnidn         dstWq, dstWd
+    movsxdifnidn         offsetq, offsetd
+    movsxdifnidn         srcq, srcd
+%if cpuflag(avx2)
+    vpbroadcastq         m3, [ditherq]
+%else
+    movq                 xm3, [ditherq]
+%endif ; avx2
+    cmp                  offsetd, 0
+    jz                   .offset
+
+    ; offset != 0 path.
+    psrlq                m5, m3, 0x18
+    psllq                m3, m3, 0x28
+    por                  m3, m3, m5
+
+.offset:
+    add offsetq, srcq
+    movd                 xm1, filterSized
+    SPLATW               m1, xm1, 0
+    pxor                 m0, m0, m0
+    mov                  filterSizeq, filterq
+    mov                  srcq, [filterSizeq]
+    punpcklbw            m3, m0
+    psllw                m1, m1, 3
+    paddw                m3, m3, m1
+    psraw                m7, m3, 4
+.outerloop:
+    mova                 m4, m7
+    mova                 m3, m7
+%if cpuflag(sse3)
+    mova                 m6, m7
+    mova                 m1, m7
+%endif
+.loop:
+%if cpuflag(avx2)
+    vpbroadcastq         m0, [filterSizeq + 8]
+%elif cpuflag(sse3)
+    movddup              m0, [filterSizeq + 8]
+%else
+    mova                 m0, [filterSizeq + 8]
+%endif
+    pmulhw               m2, m0, [srcq + offsetq * 2]
+    pmulhw               m5, m0, [srcq + offsetq * 2 + mmsize]
+    paddw                m3, m3, m2
+    paddw                m4, m4, m5
+%if cpuflag(sse3)
+    pmulhw               m2, m0, [srcq + offsetq * 2 + 2 * mmsize]
+    pmulhw               m5, m0, [srcq + offsetq * 2 + 3 * mmsize]
+    paddw                m6, m6, m2
+    paddw                m1, m1, m5
+%endif
+    add                  filterSizeq, 0x10
+    mov                  srcq, [filterSizeq]
+    test                 srcq, srcq
+    jnz                  .loop
+    psraw                m3, m3, 3
+    psraw                m4, m4, 3
+%if cpuflag(sse3)
+    psraw                m6, m6, 3
+    psraw                m1, m1, 3
+%endif
+    packuswb             m3, m3, m4
+%if cpuflag(sse3)
+    packuswb             m6, m6, m1
+%endif
+    mov                  srcq, [filterq]
+%if cpuflag(avx2)
+    vpermq               m3, m3, 216
+    vpermq               m6, m6, 216
+%endif
+    movr                 [destq + offsetq], m3
+%if cpuflag(sse3)
+    movr                 [destq + offsetq + mmsize], m6
+%endif
+    add                  offsetq, mmsize * unroll
+    mov                  filterSizeq, filterq
+    cmp                  offsetq, dstWq
+    jb                  .outerloop
+    RET
+%endmacro
+
+INIT_MMX mmxext
+YUV2YUVX_FUNC
+INIT_XMM sse3
+YUV2YUVX_FUNC
+%if HAVE_AVX2_EXTERNAL
+INIT_YMM avx2
+YUV2YUVX_FUNC
+%endif
diff --git a/libs/ffmpeg/libswscale/x86/yuv_2_rgb.asm b/libs/ffmpeg/libswscale/x86/yuv_2_rgb.asm
new file mode 100644
index 000000000000..eeb1d2594208
--- /dev/null
+++ b/libs/ffmpeg/libswscale/x86/yuv_2_rgb.asm
@@ -0,0 +1,316 @@
+;******************************************************************************
+;* software YUV to RGB converter
+;*
+;* Copyright (C) 2001-2007 Michael Niedermayer
+;*           (c) 2010 Konstantin Shishkov
+;*
+;* This file is part of FFmpeg.
+;*
+;* FFmpeg is free software; you can redistribute it and/or
+;* modify it under the terms of the GNU Lesser General Public
+;* License as published by the Free Software Foundation; either
+;* version 2.1 of the License, or (at your option) any later version.
+;*
+;* FFmpeg is distributed in the hope that it will be useful,
+;* but WITHOUT ANY WARRANTY; without even the implied warranty of
+;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;* Lesser General Public License for more details.
+;*
+;* You should have received a copy of the GNU Lesser General 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/x86/x86util.asm"
+
+SECTION_RODATA
+
+; below variables are named like mask_dwXY, which means to preserve dword No.X & No.Y
+mask_dw036 : db -1, -1,  0,  0,  0,  0, -1, -1,  0,  0,  0,  0, -1, -1,  0,  0
+mask_dw147 : db  0,  0, -1, -1,  0,  0,  0,  0, -1, -1,  0,  0,  0,  0, -1, -1
+mask_dw25  : db  0,  0,  0,  0, -1, -1,  0,  0,  0,  0, -1, -1,  0,  0,  0,  0
+rgb24_shuf1: db  0,  1,  6,  7, 12, 13,  2,  3,  8,  9, 14, 15,  4,  5, 10, 11
+rgb24_shuf2: db 10, 11,  0,  1,  6,  7, 12, 13,  2,  3,  8,  9, 14, 15,  4,  5
+rgb24_shuf3: db  4,  5, 10, 11,  0,  1,  6,  7, 12, 13,  2,  3,  8,  9, 14, 15
+gbrp_shuf  : db  0,  8,  1,  9,  2, 10,  3, 11,  4, 12,  5, 13,  6, 14,  7, 15
+pw_00ff: times 8 dw 255
+pb_f8:   times 16 db 248
+pb_e0:   times 16 db 224
+pb_03:   times 16 db 3
+pb_07:   times 16 db 7
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+;
+; YUV420/YUVA420 to RGB/BGR 15/16/24/32
+; R = Y + ((vrCoff * (v - 128)) >> 8)
+; G = Y - ((ugCoff * (u - 128) + vgCoff * (v - 128)) >> 8)
+; B = Y + ((ubCoff * (u - 128)) >> 8)
+;
+;-----------------------------------------------------------------------------
+
+%macro yuv2rgb_fn 3
+
+%if %3 == 32
+    %ifidn %1, yuva
+    %define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index, pa_2index
+    %define GPR_num 7
+    %else
+    %define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index
+    %define GPR_num 6
+    %endif
+%else
+    %ifidn %2, gbrp
+    %define parameters index, image, dst_b, dst_r, pu_index, pv_index, pointer_c_dither, py_2index
+    %define GPR_num 8
+    %else
+    %define parameters index, image, pu_index, pv_index, pointer_c_dither, py_2index
+    %define GPR_num 6
+    %endif
+%endif
+
+%define m_green m2
+%define m_alpha m3
+%define m_y m6
+%define m_u m0
+%define m_v m1
+%ifidn %2, rgb
+%define m_red m1
+%define m_blue m0
+%else
+%define m_red m0
+%define m_blue m1
+%endif
+
+%define time_num 2
+%if ARCH_X86_32
+%define reg_num 8
+%define my_offset [pointer_c_ditherq + 8  * 8]
+%define mu_offset [pointer_c_ditherq + 9  * 8]
+%define mv_offset [pointer_c_ditherq + 10 * 8]
+%define mug_coff  [pointer_c_ditherq + 7  * 8]
+%define mvg_coff  [pointer_c_ditherq + 6  * 8]
+%define my_coff   [pointer_c_ditherq + 3  * 8]
+%define mub_coff  [pointer_c_ditherq + 5  * 8]
+%define mvr_coff  [pointer_c_ditherq + 4  * 8]
+%else ; ARCH_X86_64
+%define reg_num 16
+%define y_offset m8
+%define u_offset m9
+%define v_offset m10
+%define ug_coff  m11
+%define vg_coff  m12
+%define y_coff   m13
+%define ub_coff  m14
+%define vr_coff  m15
+%endif ; ARCH_X86_32/64
+
+cglobal %1_420_%2%3, GPR_num, GPR_num, reg_num, parameters
+
+%if ARCH_X86_64
+    movsxd indexq, indexd
+    VBROADCASTSD y_offset, [pointer_c_ditherq + 8  * 8]
+    VBROADCASTSD u_offset, [pointer_c_ditherq + 9  * 8]
+    VBROADCASTSD v_offset, [pointer_c_ditherq + 10 * 8]
+    VBROADCASTSD ug_coff,  [pointer_c_ditherq + 7  * 8]
+    VBROADCASTSD vg_coff,  [pointer_c_ditherq + 6  * 8]
+    VBROADCASTSD y_coff,   [pointer_c_ditherq + 3  * 8]
+    VBROADCASTSD ub_coff,  [pointer_c_ditherq + 5  * 8]
+    VBROADCASTSD vr_coff,  [pointer_c_ditherq + 4  * 8]
+%endif
+.loop0:
+    movu m_y, [py_2indexq + 2 * indexq]
+    movh m_u, [pu_indexq  +     indexq]
+    movh m_v, [pv_indexq  +     indexq]
+    pxor m4, m4
+    mova m7, m6
+    punpcklbw m0, m4
+    punpcklbw m1, m4
+    mova m2, [pw_00ff]
+    pand m6, m2
+    psrlw m7, 8
+    psllw m0, 3
+    psllw m1, 3
+    psllw m6, 3
+    psllw m7, 3
+%if ARCH_X86_32
+    VBROADCASTSD m2, mu_offset
+    VBROADCASTSD m3, mv_offset
+    VBROADCASTSD m4, my_offset
+    psubsw m0, m2 ; U = U - 128
+    psubsw m1, m3 ; V = V - 128
+    psubw  m6, m4
+    psubw  m7, m4
+    VBROADCASTSD m2, mug_coff
+    VBROADCASTSD m3, mvg_coff
+    VBROADCASTSD m4, my_coff
+    VBROADCASTSD m5, mub_coff
+    pmulhw m2, m0
+    pmulhw m3, m1
+    pmulhw m6, m4
+    pmulhw m7, m4
+    pmulhw m0, m5
+    VBROADCASTSD m4, mvr_coff
+    pmulhw m1, m4
+%else ; ARCH_X86_64
+    psubsw m0, u_offset ; U = U - 128
+    psubsw m1, v_offset ; V = V - 128
+    psubw  m6, y_offset
+    psubw  m7, y_offset
+    mova m2, m0
+    mova m3, m1
+    pmulhw m2, ug_coff
+    pmulhw m3, vg_coff
+    pmulhw m6, y_coff
+    pmulhw m7, y_coff
+    pmulhw m0, ub_coff
+    pmulhw m1, vr_coff
+%endif
+    paddsw m2, m3
+    mova m3, m7
+    mova m5, m7
+    paddsw m3, m0 ; B1 B3 B5 B7 ...
+    paddsw m5, m1 ; R1 R3 R5 R7 ...
+    paddsw m7, m2 ; G1 G3 G5 G7 ...
+    paddsw m0, m6 ; B0 B2 B4 B6 ...
+    paddsw m1, m6 ; R0 R2 R4 R6 ...
+    paddsw m2, m6 ; G0 G2 G4 G6 ...
+
+%if %3 == 24 ; PACK RGB24
+    packuswb m0, m3 ; B0 B2 B4 B6 ... B1 B3 B5 B7 ...
+    packuswb m1, m5 ; R0 R2 R4 R6 ... R1 R3 R5 R7 ...
+    packuswb m2, m7 ; G0 G2 G4 G6 ... G1 G3 G5 G7 ...
+%ifidn %2, gbrp ; PLANAR GBRP
+%define depth 1
+    mova   m4, [gbrp_shuf]
+    pshufb m0, m4
+    pshufb m1, m4
+    pshufb m2, m4
+    movu [imageq], m2
+    movu [dst_bq], m0
+    movu [dst_rq], m1
+    add dst_bq, 8 * depth * time_num
+    add dst_rq, 8 * depth * time_num
+%else
+%define depth 3
+    mova m3, m_red
+    mova m6, m_blue
+    psrldq m_red, 8
+    punpcklbw m3, m2     ; R0 G0 R2 G2 R4 G4 R6 G6 R8 G8 ...
+    punpcklbw m6, m_red  ; B0 R1 B2 R3 B4 R5 B6 R7 B8 R9 ...
+    punpckhbw m2, m_blue ; G1 B1 G3 B3 G5 B5 G7 B7 G9 B9 ...
+    pshufb m3, [rgb24_shuf1] ; r0  g0  r6  g6  r12 g12 r2  g2  r8  g8  r14 g14 r4  g4  r10 g10
+    pshufb m6, [rgb24_shuf2] ; b10 r11 b0  r1  b6  r7  b12 r13 b2  r3  b8  r9  b14 r15 b4  r5
+    pshufb m2, [rgb24_shuf3] ; g5  b5  g11 b11 g1  b1  g7  b7  g13 b13 g3  b3  g9  b9  g15 b15
+    mova   m7, [mask_dw036]
+    mova   m4, [mask_dw147]
+    mova   m5, [mask_dw25]
+    pand   m0, m7, m3      ; r0  g0  --- --- --- --- r2  g2  --- --- --- --- r4  g4  --- ---
+    pand   m1, m4, m6      ; --- --- b0  r1  --- --- --- --- b2  r3  --- --- --- --- b4  r5
+    por    m0, m1
+    pand   m1, m5, m2      ; --- --- --- --- g1  b1  --- --- --- --- g3  b3  --- --- --- ---
+    por    m0, m1          ; r0  g0  b0  r1  g1  b1  r2  g2  b2  r3  g3  b3  r4  g4  b4  r5
+    pand   m1, m7, m2      ; g5  b5  --- --- --- --- g7  b7  --- --- --- --- g9  b9  --- ---
+    pand   m7, m6          ; b10 r11 --- --- --- --- b12 r13 --- --- --- --- b14 r15 --- ---
+    pand   m6, m5          ; --- --- --- --- b6  r7  --- --- --- --- b8  r9  --- --- --- ---
+    por    m1, m6
+    pand   m6, m4, m3      ; --- --- r6  g6  --- --- --- --- r8  g8  --- --- --- --- r10 g10
+    pand   m2, m4          ; --- --- g11 b11 --- --- --- --- g13 b13 --- --- --- --- g15 b15
+    pand   m3, m5          ; --- --- --- --- r12 g12 --- --- --- --- r14 g14 --- --- --- ---
+    por    m2, m7
+    por    m1, m6          ; g5  b5  r6  g6  b6  r7  g7  b7  r8  g8  b8  r9  g9  b9  r10 g10
+    por    m2, m3          ; b10 r11 g11 b11 r12 g12 b12 r13 g13 b13 r14 g14 b14 r15 g15 b15
+    movu [imageq], m0
+    movu [imageq + 16], m1
+    movu [imageq + 32], m2
+%endif ; PLANAR GBRP
+%else ; PACK RGB15/16/32
+    packuswb m0, m1
+    packuswb m3, m5
+    packuswb m2, m2
+    mova m1, m0
+    packuswb m7, m7
+    punpcklbw m0, m3 ; B0 B1 B2 B3 ... B7
+    punpckhbw m1, m3 ; R0 R1 R2 R3 ... R7
+    punpcklbw m2, m7 ; G0 G1 G2 G3 ... G7
+%if %3 == 32 ; PACK RGB32
+%define depth 4
+%ifidn %1, yuv
+    pcmpeqd m3, m3 ; Set alpha empty
+%else
+    movu m3, [pa_2indexq + 2 * indexq] ; Load alpha
+%endif
+    mova m5, m_blue
+    mova m6, m_red
+    punpckhbw m5,     m_green
+    punpcklbw m_blue, m_green
+    punpckhbw m6,     m_alpha
+    punpcklbw m_red,  m_alpha
+    mova m_green, m_blue
+    mova m_alpha, m5
+    punpcklwd m_blue, m_red
+    punpckhwd m_green, m_red
+    punpcklwd m5, m6
+    punpckhwd m_alpha, m6
+    movu [imageq + 0], m_blue
+    movu [imageq + 8  * time_num], m_green
+    movu [imageq + 16 * time_num], m5
+    movu [imageq + 24 * time_num], m_alpha
+%else ; PACK RGB15/16
+%define depth 2
+    %define red_dither m3
+    %define green_dither m4
+    %define blue_dither m5
+    VBROADCASTSD red_dither,   [pointer_c_ditherq + 0 * 8]
+    VBROADCASTSD green_dither, [pointer_c_ditherq + 1 * 8]
+    VBROADCASTSD blue_dither,  [pointer_c_ditherq + 2 * 8]
+%if %3 == 15
+%define gmask pb_03
+%define isRGB15 1
+%else
+%define gmask pb_07
+%define isRGB15 0
+%endif
+    paddusb m0, blue_dither
+    paddusb m2, green_dither
+    paddusb m1, red_dither
+    pand m0, [pb_f8]
+    pand m1, [pb_f8]
+    mova m3, m2
+    psllw m2, 3 - isRGB15
+    psrlw m3, 5 + isRGB15
+    psrlw m0, 3
+    psrlw m1, isRGB15
+    pand m2, [pb_e0]
+    pand m3, [gmask]
+    por m0, m2
+    por m1, m3
+    mova m2, m0
+    punpcklbw m0, m1
+    punpckhbw m2, m1
+    movu [imageq], m0
+    movu [imageq + 8 * time_num], m2
+%endif ; PACK RGB15/16
+%endif ; PACK RGB15/16/32
+
+add imageq, 8 * depth * time_num
+add indexq, 4 * time_num
+js .loop0
+
+RET
+
+%endmacro
+
+INIT_XMM ssse3
+yuv2rgb_fn yuv,  rgb, 24
+yuv2rgb_fn yuv,  bgr, 24
+yuv2rgb_fn yuv,  rgb, 32
+yuv2rgb_fn yuv,  bgr, 32
+yuv2rgb_fn yuva, rgb, 32
+yuv2rgb_fn yuva, bgr, 32
+yuv2rgb_fn yuv,  rgb, 15
+yuv2rgb_fn yuv,  rgb, 16
+%if ARCH_X86_64
+yuv2rgb_fn yuv,  gbrp, 24
+%endif
diff --git a/libs/ffmpeg/libswscale/yuv2rgb.c b/libs/ffmpeg/libswscale/yuv2rgb.c
new file mode 100644
index 000000000000..c62201856d19
--- /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;
+}
diff --git a/libs/musl/src/math/rint.c b/libs/musl/src/math/rint.c
index d9857272747c..4ae965b6a72b 100644
--- a/libs/musl/src/math/rint.c
+++ b/libs/musl/src/math/rint.c
@@ -8,9 +8,7 @@ static const double_t toint = 1 / DBL_EPSILON;
 
 double __cdecl rint(double x)
 {
-#if defined(__GNUC__) && !defined(__clang__)
-    return __builtin_rint(x);
-#elif defined(__SSE_MATH__)
+#if defined(__SSE_MATH__)
     union {double f; uint64_t i;} u = {x};
     int e = u.i>>52 & 0x7ff;
     int s = u.i>>63;
diff --git a/libs/symcrypt/inc/symcrypt_internal.h b/libs/symcrypt/inc/symcrypt_internal.h
index 488711b1036c..1bdd7fa4d229 100644
--- a/libs/symcrypt/inc/symcrypt_internal.h
+++ b/libs/symcrypt/inc/symcrypt_internal.h
@@ -112,6 +112,13 @@
 
 //#define SYMCRYPT_IGNORE_PLATFORM        // #defining this flag disables all platform optimizations.
 
+#ifndef __WINE_PE_BUILD
+#define SYMCRYPT_IGNORE_PLATFORM
+#elif defined __clang_major__ && __clang_major__ < 19
+/* clang versions < 19 don't implement target attributes correctly */
+#define SYMCRYPT_IGNORE_PLATFORM
+#endif
+
 #define SYMCRYPT_CPU_X86            0
 #define SYMCRYPT_CPU_AMD64          0
 #define SYMCRYPT_CPU_ARM            0
diff --git a/libs/symcrypt/lib/a_dispatch.c b/libs/symcrypt/lib/a_dispatch.c
index 361df3051b75..ab4e99a1758c 100644
--- a/libs/symcrypt/lib/a_dispatch.c
+++ b/libs/symcrypt/lib/a_dispatch.c
@@ -22,7 +22,7 @@ const SYMCRYPT_MODULAR_FUNCTIONS g_SymCryptModFns[] = {
     SYMCRYPT_MOD_FUNCTIONS_FDEF_GENERIC,                // Handles any type of modulus
     SYMCRYPT_MOD_FUNCTIONS_FDEF_MONTGOMERY,             // Montgomery, only for odd parity-public moduli
 
-#if SYMCRYPT_CPU_AMD64 && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64
 
     SYMCRYPT_MOD_FUNCTIONS_FDEF369_MONTGOMERY,          // optimized for 384 and 576-bit moduli
     SYMCRYPT_MOD_FUNCTIONS_FDEF_MONTGOMERY_MULX256,     // Special faster code for 256-bit Montgomery moduli, MULX-based code
@@ -76,7 +76,7 @@ const UINT32 g_SymCryptModFnsMask = sizeof( g_SymCryptModFns ) - sizeof( g_SymCr
 //
 const SYMCRYPT_MODULUS_TYPE_SELECTION_ENTRY SymCryptModulusTypeSelections[] =
 {
-#if SYMCRYPT_CPU_AMD64 && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64
     // Mulx used for 0-512 and 577-... bits
     {SymCryptModFntableMontgomeryMulxP384,  SYMCRYPT_CPU_FEATURES_FOR_MULX,  384,   SYMCRYPT_MODULUS_FEATURE_MONTGOMERY | SYMCRYPT_MODULUS_FEATURE_NISTP384 },
     {SymCryptModFntableMontgomeryMulx256,   SYMCRYPT_CPU_FEATURES_FOR_MULX,  256,   SYMCRYPT_MODULUS_FEATURE_MONTGOMERY },
diff --git a/libs/symcrypt/lib/aes-asm.c b/libs/symcrypt/lib/aes-asm.c
index e80f3bc3b847..bd49d2e549ac 100644
--- a/libs/symcrypt/lib/aes-asm.c
+++ b/libs/symcrypt/lib/aes-asm.c
@@ -7,7 +7,7 @@
 
 #include "precomp.h"
 
-#if (SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM) && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM
 
 VOID
 SYMCRYPT_CALL
diff --git a/libs/symcrypt/lib/fdef369_mod.c b/libs/symcrypt/lib/fdef369_mod.c
index a5ac0b864a83..0e9bc3a21a7e 100644
--- a/libs/symcrypt/lib/fdef369_mod.c
+++ b/libs/symcrypt/lib/fdef369_mod.c
@@ -6,7 +6,7 @@
 
 #include "precomp.h"
 
-#if (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64) && defined(__WINE_PE_BUILD)
+#if (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64)
 
 #if !(SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM64)
 #error code in this file is specific to normal digits being 4 64-bit words, and here 3 64-bit words
diff --git a/libs/symcrypt/lib/fdef_general.c b/libs/symcrypt/lib/fdef_general.c
index 1bc2509aaa23..876b1e8aab0d 100644
--- a/libs/symcrypt/lib/fdef_general.c
+++ b/libs/symcrypt/lib/fdef_general.c
@@ -1535,18 +1535,3 @@ SymCryptFdefIntFindSmallDivisor(
 cleanup:
     return res;
 }
-
-#ifndef __WINE_PE_BUILD
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefMaskedCopyAsm(
-    _In_reads_bytes_( nDigits*SYMCRYPT_FDEF_DIGIT_SIZE )        PCBYTE      pbSrc,
-    _Inout_updates_bytes_( nDigits*SYMCRYPT_FDEF_DIGIT_SIZE )   PBYTE       pbDst,
-                                                                UINT32      nDigits,
-                                                                UINT32      mask )
-{
-    SymCryptFdefMaskedCopyC( pbSrc, pbDst, nDigits, mask );
-}
-
-#endif
diff --git a/libs/symcrypt/lib/fdef_int.c b/libs/symcrypt/lib/fdef_int.c
index 0a82df5ee51f..774ea213db4d 100644
--- a/libs/symcrypt/lib/fdef_int.c
+++ b/libs/symcrypt/lib/fdef_int.c
@@ -1249,73 +1249,3 @@ SymCryptFdefIntDivMod(
         SymCryptWipe( &SYMCRYPT_FDEF_INT_PUINT32( piRemainder )[pdDivisor->nDigits * SYMCRYPT_FDEF_DIGIT_NUINT32], (piRemainder->nDigits - pdDivisor->nDigits) * SYMCRYPT_FDEF_DIGIT_SIZE );
     }
 }
-
-#ifndef __WINE_PE_BUILD
-
-UINT32
-SYMCRYPT_CALL
-SymCryptFdefRawAddAsm(
-    _In_reads_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE )   PCUINT32    Src1,
-    _In_reads_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE )   PCUINT32    Src2,
-    _Out_writes_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE ) PUINT32     Dst,
-                                                            UINT32      nDigits )
-{
-    return SymCryptFdefRawAddC( Src1, Src2, Dst, nDigits );
-}
-
-UINT32
-SYMCRYPT_CALL
-SymCryptFdefRawSubAsm(
-    _In_reads_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE )   PCUINT32    pSrc1,
-    _In_reads_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE )   PCUINT32    pSrc2,
-    _Out_writes_bytes_(nDigits * SYMCRYPT_FDEF_DIGIT_SIZE ) PUINT32     pDst,
-                                                            UINT32      nDigits )
-{
-    return SymCryptFdefRawSubC( pSrc1, pSrc2, pDst, nDigits );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefRawMulAsm(
-    _In_reads_(nDigits1*SYMCRYPT_FDEF_DIGIT_NUINT32)                PCUINT32    pSrc1,
-                                                                    UINT32      nDigits1,
-    _In_reads_(nDigits2*SYMCRYPT_FDEF_DIGIT_NUINT32)                PCUINT32    pSrc2,
-                                                                    UINT32      nDigits2,
-    _Out_writes_((nDigits1+nDigits2)*SYMCRYPT_FDEF_DIGIT_NUINT32)   PUINT32     pDst )
-{
-    SymCryptFdefRawMulC( pSrc1, nDigits1, pSrc2, nDigits2, pDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefRawSquareAsm(
-    _In_reads_(nDigits*SYMCRYPT_FDEF_DIGIT_NUINT32)     PCUINT32    pSrc,
-                                                        UINT32      nDigits,
-    _Out_writes_(2*nDigits*SYMCRYPT_FDEF_DIGIT_NUINT32) PUINT32     pDst )
-{
-    SymCryptFdefRawSquareC( pSrc, nDigits, pDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefRawSquareMulx(
-    _In_reads_(nDigits*SYMCRYPT_FDEF_DIGIT_NUINT32)         PCUINT32    pSrc,
-                                                            UINT32      nDigits,
-    _Out_writes_(2*nDigits*SYMCRYPT_FDEF_DIGIT_NUINT32)     PUINT32     pDst )
-{
-    SymCryptFdefRawSquareC( pSrc, nDigits, pDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefRawMulMulx(
-    _In_reads_(nDigits1*SYMCRYPT_FDEF_DIGIT_NUINT32)                PCUINT32    pSrc1,
-                                                                    UINT32      nDigits1,
-    _In_reads_(nDigits2*SYMCRYPT_FDEF_DIGIT_NUINT32)                PCUINT32    pSrc2,
-                                                                    UINT32      nDigits2,
-    _Out_writes_((nDigits1+nDigits2)*SYMCRYPT_FDEF_DIGIT_NUINT32)   PUINT32     pDst )
-{
-    SymCryptFdefRawMulC( pSrc1, nDigits1, pSrc2, nDigits2, pDst );
-}
-
-#endif
diff --git a/libs/symcrypt/lib/fdef_mod.c b/libs/symcrypt/lib/fdef_mod.c
index 27e8f8a69c3b..56f5911dd766 100644
--- a/libs/symcrypt/lib/fdef_mod.c
+++ b/libs/symcrypt/lib/fdef_mod.c
@@ -1332,7 +1332,7 @@ SymCryptFdefModMulMontgomery(
     SymCryptFdefMontgomeryReduce( pmMod, pTmp, &peDst->d.uint32[0] );
 }
 
-#if SYMCRYPT_CPU_AMD64 && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64
 VOID
 SYMCRYPT_CALL
 SymCryptFdefModMulMontgomeryMulx(
@@ -1395,7 +1395,7 @@ SymCryptFdefModSquareMontgomery(
 }
 
 
-#if SYMCRYPT_CPU_AMD64 && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64
 VOID
 SYMCRYPT_CALL
 SymCryptFdefModSquareMontgomeryMulx(
@@ -1470,7 +1470,7 @@ SymCryptFdefModInvMontgomery(
     return scError;
 }
 
-#if SYMCRYPT_CPU_AMD64 && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64
 
 //=====================================
 // 256-bit Montgomery modulus code
@@ -1685,49 +1685,3 @@ SymCryptFdefModSquareMontgomery1024(
 #endif
 
 #endif
-
-#ifndef __WINE_PE_BUILD
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefMontgomeryReduceAsm(
-    _In_                            PCSYMCRYPT_MODULUS      pmMod,
-    _Inout_                         PUINT32                 pSrc,
-    _Out_                           PUINT32                 pDst )
-{
-    SymCryptFdefMontgomeryReduceC( pmMod, pSrc, pDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefModDivSmallPow2Mulx(
-    _In_                        PCSYMCRYPT_MODULUS      pmMod,
-    _In_                        PCSYMCRYPT_MODELEMENT   peSrc,
-    _In_range_(1, NATIVE_BITS)  UINT32                  exp,
-    _Out_                       PSYMCRYPT_MODELEMENT    peDst )
-{
-    SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefMontgomeryReduceMulx(
-    _In_                            PCSYMCRYPT_MODULUS      pmMod,
-    _Inout_                         PUINT32                 pSrc,
-    _Out_                           PUINT32                 pDst )
-{
-    SymCryptFdefMontgomeryReduceC( pmMod, pSrc, pDst );
-}
-
-VOID
-SYMCRYPT_CALL
-SymCryptFdefModDivSmallPow2Asm(
-    _In_                        PCSYMCRYPT_MODULUS      pmMod,
-    _In_                        PCSYMCRYPT_MODELEMENT   peSrc,
-    _In_range_(1, NATIVE_BITS)  UINT32                  exp,
-    _Out_                       PSYMCRYPT_MODELEMENT    peDst )
-{
-    SymCryptFdefModDivSmallPow2Generic( pmMod, peSrc, exp, peDst );
-}
-
-#endif
diff --git a/libs/symcrypt/lib/i386/wipe.asm b/libs/symcrypt/lib/i386/wipe.asm
deleted file mode 100644
index 178149189b19..000000000000
--- a/libs/symcrypt/lib/i386/wipe.asm
+++ /dev/null
@@ -1,171 +0,0 @@
-;
-; Wipe.asm
-;
-; Copyright (c) Microsoft Corporation. Licensed under the MIT license.
-;
-
-        TITLE   wipe.asm
-
-
-        .686
-        .xmm
-
-_TEXT   SEGMENT PARA PUBLIC USE32 'CODE'
-        ASSUME  CS:_TEXT, DS:FLAT, SS:FLAT
-
-        PUBLIC  @SymCryptWipeAsm@8
-
-;VOID
-;SYMCRYPT_CALL
-;SymCryptWipe( _Out_writes_bytes_( cbData )   PVOID  pbData,
-;                                       SIZE_T cbData )
-
-@SymCryptWipeAsm@8    PROC
-
-        ;
-        ; The .FPO provides debugging information for stack frames that do not use
-        ; ebp as a base pointer.
-        ; This stuff not well documented,
-        ; but here is the information I've gathered about the arguments to .FPO
-        ;
-        ; In order:
-        ; cdwLocals: Size of local variables, in DWords
-        ; cdwParams: Size of parameters, in DWords. Given that this is all about
-        ;            stack stuff, I'm assuming this is only about parameters passed
-        ;            on the stack.
-        ; cbProlog : Number of bytes in the prolog code. We sometimes interleaved the
-        ;            prolog code with work for better performance. Most uses of
-        ;            .FPO seem to set this value to 0.
-        ;            The debugger seems to work if the prolog defined by this value
-        ;            contains all the stack adjustments.
-        ; cbRegs   : # registers saved in the prolog. 4 in our case
-        ; fUseBP   : 0 if EBP is not used as base pointer, 1 if EBP is used as base pointer
-        ; cbFrame  : Type of frame.
-        ;            0 = FPO frame (no frame pointer)
-        ;            1 = Trap frame (result of a CPU trap event)
-        ;            2 = TSS frame
-        ;
-        ; Having looked at various occurrences of .FPO in the Windows code it
-        ; seems to be used fairly sloppy, with lots of arguments left 0 even when
-        ; they probably shouldn't be according to the spec.
-        ;
-        .FPO(0,0,0,0,0,0)       ; 3 byte prolog (covers esp adjustment only)
-
-        ; ecx = pbData
-        ; edx = cbData
-
-        ;
-        ; This function will handle any alignment of pbData and any size, but it is optimized for
-        ; the case where pbData is 4-aligned, and cbData is a multiple of 4.
-        ;
-
-        xor     eax,eax
-        cmp     edx,8
-        jb      SymCryptWipeAsmSmall     ; if cbData < 8, this is a rare case
-
-        test    ecx,7
-        jnz     SymCryptWipeAsmUnAligned; if data pointer is unaligned, we jump to the code that aligns the pointer
-                                        ; For well-optimized code the aligned case is the common one, and that is
-                                        ; the fall-through.
-
-SymCryptWipeAsmAligned:
-        ;
-        ; Here ecx is aligned, and edx contains the # bytes left to wipe, and edx >= 8
-        ;
-        ; Our loop wipes in 8-byte increments;
-        ;
-        sub     edx,8
-
-        align   16
-SymCryptWipeAsmLoop:
-        mov     [ecx],eax
-        mov     [ecx+4],eax           ; Wipe 8 bytes
-        add     ecx,8
-        sub     edx,8
-        ja      SymCryptWipeAsmLoop   ; Loop if we have >8 byte to wipe. <= 8 bytes is handled by the code below
-
-        ;
-        ; The end of the buffer to wipe is at ecx + edx + 8 as
-        ; the number of bytes we wiped is 8 less than the number we subtracted from edx.
-        ;
-        ; We know we had 8 or more bytes to wipe, so we just wipe the last 8 bytes.
-        ; This avoids a lot of conditional jumping etc.
-        ;
-        mov     [ecx+edx+8-8],eax
-        mov     [ecx+edx+8-4],eax
-
-SymCryptWipeAsmDone:
-        ret
-
-SymCryptWipeAsmUnaligned:
-        ;
-        ; At this point we know that cbData(rdx) >= 8 and pbData(rcx) is unaligned.
-        ; We wipe 4 bytes and set our pointer & length to the remaining aligned buffer
-        ;
-        mov     [ecx],eax
-        mov     [ecx+4],eax
-        sub     eax,ecx
-        and     eax,7
-        add     ecx,eax
-        sub     edx,eax
-        xor     eax,eax
-
-        ;
-        ; edx = cbData could be less than 4 now. If it is, go directly to the
-        ; tail wiping.
-        ;
-        cmp     edx,8
-        jae     SymCryptWipeAsmAligned  ; if cbData >= 8, do aligned wipes
-
-SymCryptWipeAsmSmall:
-        jmp     dword ptr [SymCryptWipeAsmSmallTable + 4*edx]
-
-SymCryptWipeAsmT4:
-        mov     [ecx],eax
-SymCryptWipeAsmT0:
-        ret
-
-SymCryptWipeAsmT1:
-        mov     [ecx],al
-        ret
-
-SymCryptWipeAsmT3:
-        mov     [ecx+2],al
-SymCryptWipeAsmT2:
-        mov     [ecx],ax
-        ret
-
-SymCryptWipeAsmT5:
-        mov     [ecx],eax
-        mov     [ecx+1],eax
-        ret
-
-SymCryptWipeAsmT6:
-        mov     [ecx],eax
-        mov     [ecx+2],eax
-        ret
-
-SymCryptWipeAsmT7:
-        mov     [ecx],eax
-        mov     [ecx+3],eax
-        ret
-
-
-        align   4
-SymCryptWipeAsmSmallTable   label   dword
-        dd      SymCryptWipeAsmT0
-        dd      SymCryptWipeAsmT1
-        dd      SymCryptWipeAsmT2
-        dd      SymCryptWipeAsmT3
-        dd      SymCryptWipeAsmT4
-        dd      SymCryptWipeAsmT5
-        dd      SymCryptWipeAsmT6
-        dd      SymCryptWipeAsmT7
-
-
-
-@SymCryptWipeAsm@8    ENDP
-
-_TEXT           ENDS
-
-END
diff --git a/libs/symcrypt/lib/libmain.c b/libs/symcrypt/lib/libmain.c
index 03ea5254268a..4c917f73820a 100644
--- a/libs/symcrypt/lib/libmain.c
+++ b/libs/symcrypt/lib/libmain.c
@@ -115,7 +115,7 @@ fatalInfiniteLoop:
     goto fatalInfiniteLoop;
 }
 
-#ifdef __WINE_PE_BUILD
+#if SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_ARM | SYMCRYPT_CPU_ARM64
 
 VOID
 SYMCRYPT_CALL
diff --git a/libs/symcrypt/lib/precomp.h b/libs/symcrypt/lib/precomp.h
index 305fa1ac4b15..6cd122015ea3 100644
--- a/libs/symcrypt/lib/precomp.h
+++ b/libs/symcrypt/lib/precomp.h
@@ -28,18 +28,3 @@
         #define _XCR_XFEATURE_ENABLED_MASK 0
     #endif
 #endif
-
-#ifndef __WINE_PE_BUILD
-#define SymCryptSha256AppendBlocks_xmm_ssse3_asm SymCryptSha256AppendBlocks_ul1
-#define SymCryptXtsAesEncryptInternalAsm SymCryptXtsAesEncryptInternalC
-#define SymCryptXtsAesDecryptInternalAsm SymCryptXtsAesDecryptInternalC
-#define SymCryptAesEncryptAsm SymCryptAesEncryptC
-#define SymCryptAesDecryptAsm SymCryptAesDecryptC
-#define SymCryptAesEcbEncryptAsm SymCryptAesEcbEncryptC
-#define SymCryptAesCbcEncryptAsm(key, chain, src, dst, data) \
-    SymCryptCbcEncrypt(&SymCryptAesBlockCipherNoOpt, key, chain, src, dst, data)
-#define SymCryptAesCbcDecryptAsm(key, chain, src, dst, data) \
-    SymCryptCbcDecrypt(&SymCryptAesBlockCipherNoOpt, key, chain, src, dst, data)
-#define SymCryptAesCtrMsb64Asm(key, chain, src, dst, data) \
-    SymCryptCtrMsb64(&SymCryptAesBlockCipherNoOpt, key, chain, src, dst, data)
-#endif
diff --git a/libs/symcrypt/lib/rsakey.c b/libs/symcrypt/lib/rsakey.c
index 32b802ba7e60..4a2de4831da5 100644
--- a/libs/symcrypt/lib/rsakey.c
+++ b/libs/symcrypt/lib/rsakey.c
@@ -417,7 +417,7 @@ SymCryptRsakeyCalculatePrivateFields(
         //      - First argument > 0: piPhi as the product of p-1's
         //      - Second argument: odd, verified below
         // We also reject public exponent 1, as that is obviously unsafe.
-        if( pkRsakey->au64PubExp[i] == 1 || (pkRsakey->au64PubExp[i] & 1) != 1)
+        if( /* pkRsakey->au64PubExp[i] == 1 || */ (pkRsakey->au64PubExp[i] & 1) != 1)
         {
             scError = SYMCRYPT_INVALID_ARGUMENT;
             goto cleanup;
diff --git a/libs/symcrypt/lib/xtsaes.c b/libs/symcrypt/lib/xtsaes.c
index 55afe374cc03..45e842702e78 100644
--- a/libs/symcrypt/lib/xtsaes.c
+++ b/libs/symcrypt/lib/xtsaes.c
@@ -98,7 +98,7 @@ SymCryptXtsAesKeyCopy(
 #undef SYMCRYPT_AesEcbEncryptXxx
 
 
-#if (SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_ARM) && defined(__WINE_PE_BUILD)
+#if SYMCRYPT_CPU_AMD64 | SYMCRYPT_CPU_X86 | SYMCRYPT_CPU_ARM
 #define SYMCRYPT_AesEcbEncryptXxx SymCryptAesEcbEncryptAsm
 
 #define SYMCRYPT_XtsAesXxx SymCryptXtsAesEncryptInternalAsm
diff --git a/loader/wine.inf.in b/loader/wine.inf.in
index f66d4ead0221..738e98f4a83a 100644
--- a/loader/wine.inf.in
+++ b/loader/wine.inf.in
@@ -790,6 +790,8 @@ HKLM,SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86,"Version",2,"14.42.344
 16422,Windows Media Player,wmplayer.exe
 16422,Windows NT\Accessories,wordpad.exe
 16427,Microsoft Shared\Ink,inkobj.dll
+16427,Microsoft Shared\Ink,rtscom.dll
+16427,Microsoft Shared\Ink,tiptsf.dll
 16427,System\OLE DB,oledb32.dll
 16427,System\OLE DB,msdaps.dll
 16427,System\OLE DB,msdasql.dll
@@ -859,6 +861,7 @@ HKLM,SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86,"Version",2,"14.42.344
 16422,Windows NT\Accessories,wordpad.exe
 16427,Microsoft Shared\TextConv,
 16427,Microsoft Shared\Ink,inkobj.dll
+16427,Microsoft Shared\Ink,tiptsf.dll
 16427,System\OLE DB,oledb32.dll
 16427,System\OLE DB,msdaps.dll
 16427,System\OLE DB,msdasql.dll
diff --git a/po/nl.po b/po/nl.po
index 785183a71acc..75dbfad6af52 100644
--- a/po/nl.po
+++ b/po/nl.po
@@ -5,7 +5,7 @@ msgstr ""
 "Project-Id-Version: Wine\n"
 "Report-Msgid-Bugs-To: https://bugs.winehq.org\n"
 "POT-Creation-Date: N/A\n"
-"PO-Revision-Date: 2025-11-29 18:00+0100\n"
+"PO-Revision-Date: 2026-06-24 12:15+0200\n"
 "Last-Translator: Floris Renaud <jkfloris@dds.nl>\n"
 "Language-Team: Dutch\n"
 "Language: nl\n"
@@ -3817,11 +3817,11 @@ msgstr "Indeo Video Interactive versie 5 video codec"
 
 #: dlls/iyuv_32/iyuv_32.rc:28
 msgid "IYUV codec"
-msgstr ""
+msgstr "IYUV codec"
 
 #: dlls/iyuv_32/iyuv_32.rc:29
 msgid "Intel Indeo IYUV codec"
-msgstr ""
+msgstr "Intel Indeo IYUV codec"
 
 #: dlls/joy.cpl/joy.rc:37
 msgid "Joysticks"
@@ -4039,11 +4039,11 @@ msgstr "'return' verklaring buiten functie"
 
 #: dlls/jscript/jscript.rc:47
 msgid "Can't have 'break' outside of loop"
-msgstr "'break' kan zich niet buiten loop bevinden"
+msgstr "'break' kan zich niet buiten lus bevinden"
 
 #: dlls/jscript/jscript.rc:48
 msgid "Can't have 'continue' outside of loop"
-msgstr "'continue' kan zich niet buiten loop bevinden"
+msgstr "'continue' kan zich niet buiten lus bevinden"
 
 #: dlls/jscript/jscript.rc:49
 msgid "Label redefined"
@@ -4055,7 +4055,7 @@ msgstr "Label niet gevonden"
 
 #: dlls/jscript/jscript.rc:51
 msgid "Expected '@end'"
-msgstr "Verwacht '@end'"
+msgstr "'@end' verwacht"
 
 #: dlls/jscript/jscript.rc:52
 msgid "Conditional compilation is turned off"
@@ -4063,7 +4063,7 @@ msgstr "Conditionele compilatie is uitgeschakeld"
 
 #: dlls/jscript/jscript.rc:53
 msgid "Expected '@'"
-msgstr "Verwacht '@'"
+msgstr "'@' verwacht"
 
 #: dlls/jscript/jscript.rc:97
 msgid "Microsoft JScript compilation error"
@@ -4840,7 +4840,7 @@ msgstr "Bestand bestaat al.\n"
 
 #: dlls/kernelbase/winerror.mc:725
 msgid "Invalid flag number.\n"
-msgstr "Ongeldig vlagnumer.\n"
+msgstr "Ongeldig vlagnummer.\n"
 
 #: dlls/kernelbase/winerror.mc:730
 msgid "Semaphore name not found.\n"
@@ -5035,125 +5035,111 @@ msgid "Invalid oplock message received.\n"
 msgstr "Ongeldig oplockbericht ontvangen.\n"
 
 #: dlls/kernelbase/winerror.mc:970
-#, fuzzy
-#| msgid "Disk is corrupt.\n"
 msgid "Disk is too fragmented.\n"
-msgstr "Schijf is corrupt.\n"
+msgstr "Schijf teveel gefragmenteerd.\n"
 
 #: dlls/kernelbase/winerror.mc:975
 msgid "File cannot be opened because it is in the process of being deleted.\n"
-msgstr ""
+msgstr "Bestand kan niet worden geopend omdat het verwijderd wordt.\n"
 
 #: dlls/kernelbase/winerror.mc:980
 msgid "Short name settings incompatible with global registry setting.\n"
 msgstr ""
+"Korte bestandsnamen zijn in strijd met de algemene registerinstellingen.\n"
 
 #: dlls/kernelbase/winerror.mc:985
 msgid "Short names are not enabled on this volume.\n"
-msgstr ""
+msgstr "Op dit sation zijn korte bestandsnamen niet ingeschakeld.\n"
 
 #: dlls/kernelbase/winerror.mc:990
-#, fuzzy
-#| msgid "Floppy registers inconsistent.\n"
 msgid "Security stream is inconsistent.\n"
-msgstr "Floppyregisters inconsistent.\n"
+msgstr "De beveiligingsstatus is inconsistent.\n"
 
 #: dlls/kernelbase/winerror.mc:995
 msgid "File lock operation cannot be processed due to invalid byte range.\n"
 msgstr ""
+"Bestandsvergrendeling kan niet worden verwerkt door een ongeldig "
+"bytebereik.\n"
 
 #: dlls/kernelbase/winerror.mc:1000
 msgid "Subsystem for supporting image type is not present.\n"
 msgstr ""
+"Subsysteem voor de ondersteuning van dit bestandstype is niet aanwezig.\n"
 
 #: dlls/kernelbase/winerror.mc:1005
 msgid "Notification GUID is already defined.\n"
-msgstr ""
+msgstr "De GUID van de melding is al gedefinieerd.\n"
 
 #: dlls/kernelbase/winerror.mc:1010
-#, fuzzy
-#| msgid "Invalid icon handle.\n"
 msgid "Invalid exception handler.\n"
-msgstr "Ongeldige pictogramhandle.\n"
+msgstr "Ongeldige uitzonderingsverwerker.\n"
 
 #: dlls/kernelbase/winerror.mc:1015
-#, fuzzy
-#| msgid "Duplicate service name.\n"
 msgid "Duplicate privileges for the token.\n"
-msgstr "Dubbele servicenaam.\n"
+msgstr "Dubbele rechten voor het token.\n"
 
 #: dlls/kernelbase/winerror.mc:1020
-#, fuzzy
-#| msgid "Not all objects could be exported.\n"
 msgid "No ranges could be processed.\n"
-msgstr "Niet alle objecten konden worden geëxporteerd.\n"
+msgstr "Bereik kan niet worden verwerkt.\n"
 
 #: dlls/kernelbase/winerror.mc:1025
-#, fuzzy
-#| msgid "Operation canceled by user.\n"
 msgid "Operation not allowed on system file.\n"
-msgstr "Bewerking geannuleerd door gebruiker.\n"
+msgstr "Bewerking niet toegestaan op systeembestand.\n"
 
 #: dlls/kernelbase/winerror.mc:1030
 msgid "Disk resources have been exhausted.\n"
-msgstr ""
+msgstr "Schijfbronnen zijn verbruikt.\n"
 
 #: dlls/kernelbase/winerror.mc:1035
-#, fuzzy
-#| msgid "Invalid key.\n"
 msgid "Invalid token.\n"
-msgstr "Ongeldige sleutel.\n"
+msgstr "Ongeldige token.\n"
 
 #: dlls/kernelbase/winerror.mc:1040
 msgid "Command feature not supported on the device.\n"
-msgstr ""
+msgstr "Deze functie wordt op dit apparaat niet ondersteund.\n"
 
 #: dlls/kernelbase/winerror.mc:1045
 msgid "Message 0x%1 not found in file %2.\n"
 msgstr "Bericht 0x%1 niet gevonden in bestand %2.\n"
 
 #: dlls/kernelbase/winerror.mc:1050
-#, fuzzy
-#| msgid "Sector not found.\n"
 msgid "Scope not found.\n"
-msgstr "Sector niet gevonden.\n"
+msgstr "Bereik niet gevonden.\n"
 
 #: dlls/kernelbase/winerror.mc:1055
-#, fuzzy
-#| msgid "The specified device handle is invalid."
 msgid "The specified Central Access Policy is undefined.\n"
-msgstr "De gespecificeerde apparaatverwijzing is ongeldig."
+msgstr "Het opgegeven centrale toegangsbeleid is niet gedefinieerd.\n"
 
 #: dlls/kernelbase/winerror.mc:1060
 msgid "Central Access Policy from Active Directory is invalid.\n"
-msgstr ""
+msgstr "Ongeldig Active Directory centraal toegangsbeleid.\n"
 
 #: dlls/kernelbase/winerror.mc:1065
-#, fuzzy
-#| msgid "Host unreachable.\n"
 msgid "Device is unreachable.\n"
-msgstr "Host onbereikbaar.\n"
+msgstr "Apparaat is onbereikbaar.\n"
 
 #: dlls/kernelbase/winerror.mc:1070
 msgid "Target device has insufficient resources to complete the operation.\n"
-msgstr ""
+msgstr "Onvoldoende bronnen op het doelapparaat voor deze bewerking.\n"
 
 #: dlls/kernelbase/winerror.mc:1075
 msgid ""
 "A data integrity checksum error occurred. Data in the file stream is "
 "corrupt.\n"
 msgstr ""
+"Fout in de gegevensintegriteit controlesom. Gegevens in de bestandsstroom "
+"zijn beschadigd.\n"
 
 #: dlls/kernelbase/winerror.mc:1080
 msgid ""
 "Cannot modify both KERNEL and normal Extended Attributes in one operation.\n"
 msgstr ""
+"Onmogelijk om KERNEL en normale uitgebreide attributen in één bewerking te "
+"wijzigen.\n"
 
 #: dlls/kernelbase/winerror.mc:1085
-#, fuzzy
-#| msgid "Device does not exist.\n"
 msgid "Device does not support file-level TRIM.\n"
-msgstr "Apparaat bestaat niet.\n"
+msgstr "Apparaat ondersteunt geen TRIM op bestandsniveau.\n"
 
 #: dlls/kernelbase/winerror.mc:1090
 msgid "Invalid address.\n"
@@ -7365,10 +7351,8 @@ msgid "This network connection does not exist.\n"
 msgstr "Deze netwerkverbinding bestaat niet.\n"
 
 #: dlls/kernelbase/winerror.mc:3865
-#, fuzzy
-#| msgid "File or directory corrupt.\n"
 msgid "File or directory is not a reparse point.\n"
-msgstr "Bestand of map corrupt.\n"
+msgstr "Bestand of map is geen reparsepunt.\n"
 
 #: dlls/kernelbase/winerror.mc:3870
 msgid "Call interrupted.\n"
@@ -7419,10 +7403,8 @@ msgid "Call failed.\n"
 msgstr "Oproep mislukt.\n"
 
 #: dlls/kernelbase/winerror.mc:3937
-#, fuzzy
-#| msgid "Unable to unload media.\n"
 msgid "Unable to find matching object.\n"
-msgstr "Niet in staat media te ontladen.\n"
+msgstr "Gelijkaardig object niet kunnen vinden.\n"
 
 #: dlls/kernelbase/winerror.mc:3944
 msgid "No Signature found in file.\n"
@@ -9000,226 +8982,172 @@ msgid "Wine Video 1 video codec"
 msgstr "Wine Video 1 video codec"
 
 #: dlls/msxml3/msxml.mc:31
-#, fuzzy
-#| msgid "Undefined external error."
 msgid "Undefined reference\n"
-msgstr "Ongedefinieerde fout van buitenaf."
+msgstr "Ongedefinieerde verwijzing\n"
 
 #: dlls/msxml3/msxml.mc:38
 msgid "Found self-referential entity\n"
-msgstr ""
+msgstr "Zelf verwijzende referentie gevonden\n"
 
 #: dlls/msxml3/msxml.mc:45
 msgid "Unparsed entity reference\n"
-msgstr ""
+msgstr "Niet-geparseerde entiteitsverwijzing\n"
 
 #: dlls/msxml3/msxml.mc:52
 msgid "Name text contains colon ':'\n"
-msgstr ""
+msgstr "Dubbele punt ':' in de naam\n"
 
 #: dlls/msxml3/msxml.mc:59
 msgid "Namespace prefix hasn't been declared\n"
-msgstr ""
+msgstr "Naam pefix is niet opgegeven\n"
 
 #: dlls/msxml3/msxml.mc:66
-#, fuzzy
-#| msgid "Expected '='"
 msgid "Expected '=' character\n"
-msgstr "Verwacht '='"
+msgstr "'=' teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:73
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected a quote character\n"
-msgstr "Verwacht een operator.\n"
+msgstr "Aanhalingstekens verwacht\n"
 
 #: dlls/msxml3/msxml.mc:80
 msgid "Malformed comment\n"
-msgstr ""
+msgstr "Onjuist geformuleerde opmerking\n"
 
 #: dlls/msxml3/msxml.mc:87
-#, fuzzy
-#| msgid "Invalid character"
 msgid "Invalid name start character\n"
-msgstr "Ongeldig teken"
+msgstr "Ongeldig beginteken van de naam\n"
 
 #: dlls/msxml3/msxml.mc:94
-#, fuzzy
-#| msgid "Invalid character"
 msgid "Invalid name character\n"
-msgstr "Ongeldig teken"
+msgstr "Ongeldig teken van de naam\n"
 
 #: dlls/msxml3/msxml.mc:101
 msgid "The '<' character found in attribute value\n"
-msgstr ""
+msgstr "'<' teken gevonden in de attribuutwaarde\n"
 
 #: dlls/msxml3/msxml.mc:108
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected whitespace character\n"
-msgstr "Verwacht een operator.\n"
+msgstr "Witruimte teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:115
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected end tag character '>'\n"
-msgstr "Verwacht een operator.\n"
+msgstr "Eindtag-teken '>' verwacht\n"
 
 #: dlls/msxml3/msxml.mc:122
-#, fuzzy
-#| msgid "Invalid character(s) in path"
 msgid "Invalid character in DTD content\n"
-msgstr "De naam van het pad bevat ongeldige tekens"
+msgstr "Ongeldig teken in DTD inhoud\n"
 
 #: dlls/msxml3/msxml.mc:129
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected ';' character\n"
-msgstr "';' verwacht"
+msgstr "';' teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:136
-#, fuzzy
-#| msgid "Invalid character(s) in path"
 msgid "Invalid character in entity reference\n"
-msgstr "De naam van het pad bevat ongeldige tekens"
+msgstr "Ongeldig teken in entiteitsverwijzing\n"
 
 #: dlls/msxml3/msxml.mc:143
-#, fuzzy
-#| msgid "Invalid character(s) in path"
 msgid "Invalid character in mixed DTD content\n"
-msgstr "De naam van het pad bevat ongeldige tekens"
+msgstr "Ongeldig teken in gemengde DTD inhoud\n"
 
 #: dlls/msxml3/msxml.mc:150
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected '*' character\n"
-msgstr "Verwacht een operator.\n"
+msgstr "'*' teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:157
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected parenthesis character\n"
-msgstr "Verwacht een operator.\n"
+msgstr "Haakjes-teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:164
-#, fuzzy
-#| msgid "Invalid character(s) in path"
 msgid "Invalid character in DTD enumeration\n"
-msgstr "De naam van het pad bevat ongeldige tekens"
+msgstr "Ongeldig teken in DTD opsomming\n"
 
 #: dlls/msxml3/msxml.mc:171
-#, fuzzy
-#| msgid "Invalid name syntax.\n"
 msgid "Invalid PI syntax\n"
-msgstr "Ongeldige formulering van de naam.\n"
+msgstr "Ongeldige PI formulering\n"
 
 #: dlls/msxml3/msxml.mc:178
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected closing quote character\n"
-msgstr "Verwacht een operator.\n"
+msgstr "Aanhalingsteken sluiten verwacht\n"
 
 #: dlls/msxml3/msxml.mc:185
 msgid "Multiple colon character found\n"
-msgstr ""
+msgstr "Meerdere dubbele punt-tekens gevonden\n"
 
 #: dlls/msxml3/msxml.mc:192
-#, fuzzy
-#| msgid "Invalid character"
 msgid "Invalid Unicode character\n"
-msgstr "Ongeldig teken"
+msgstr "Ongeldig Unicode teken\n"
 
 #: dlls/msxml3/msxml.mc:199
 msgid "Expected whitespace or '?' character\n"
-msgstr ""
+msgstr "Witruimte of '?' teken verwacht\n"
 
 #: dlls/msxml3/msxml.mc:206
 msgid "Unexpected end tag '>' character\n"
-msgstr ""
+msgstr "Onverwacht eindtag-teken '>'\n"
 
 #: dlls/msxml3/msxml.mc:213
-#, fuzzy
-#| msgid "Invalid group attributes.\n"
 msgid "Found duplicate attribute\n"
-msgstr "Ongeldige groepsattributen.\n"
+msgstr "Dubbel attribuut gevonden\n"
 
 #: dlls/msxml3/msxml.mc:220
-#, fuzzy
-#| msgid "Key is invalid.\n"
 msgid "Document root is invalid\n"
-msgstr "Sleutel is ongeldig.\n"
+msgstr "Hoofd-tag is ongeldig\n"
 
 #: dlls/msxml3/msxml.mc:227
-#, fuzzy
-#| msgid "Invalid handle operation.\n"
 msgid "Invalid xml declaration\n"
-msgstr "Foutieve handle handeling.\n"
+msgstr "Ongeldige xml-declaratie\n"
 
 #: dlls/msxml3/msxml.mc:234
-#, fuzzy
-#| msgid "Source is missing.\n"
 msgid "Document root is missing\n"
-msgstr "Bron ontbreekt.\n"
+msgstr "Hoofd-tag ontbreekt\n"
 
 #: dlls/msxml3/msxml.mc:241
 msgid "Unexpected end of input data stream\n"
-msgstr ""
+msgstr "Onverwacht einde van de invoerdatastroom\n"
 
 #: dlls/msxml3/msxml.mc:248
 msgid "Found unexpected CDATA closing markup ']]>'\n"
-msgstr ""
+msgstr "Onverwachte CDATA afsluitmarkering gevonden ']]'\n"
 
 #: dlls/msxml3/msxml.mc:255
 msgid "Found unterminated PI declaration\n"
-msgstr ""
+msgstr "PI-declaratie zonder afsluiting gevonden\n"
 
 #: dlls/msxml3/msxml.mc:262
 msgid "Found unterminated end tag\n"
-msgstr ""
+msgstr "Niet afgesloten eindtag gevonden\n"
 
 #: dlls/msxml3/msxml.mc:269
 msgid "Found unterminated CDATA block\n"
-msgstr ""
+msgstr "CDATA zonder afsluiting gevonden\n"
 
 #: dlls/msxml3/msxml.mc:276
 msgid "Use namespace prefix is reserved\n"
-msgstr ""
+msgstr "Gebruik van voorbehouden naam prefix\n"
 
 #: dlls/msxml3/msxml.mc:283
-#, fuzzy
-#| msgid "The passwords do not match."
 msgid "End tag does not match\n"
-msgstr "De wachtwoorden zijn niet gelijk."
+msgstr "Eind-tag is niet gelijk\n"
 
 #: dlls/msxml3/msxml.mc:290
-#, fuzzy
-#| msgid "Invalid domain name.\n"
 msgid "Invalid encoding name\n"
-msgstr "Ongeldige domeinnaam.\n"
+msgstr "Ongeldige coderingnaam\n"
 
 #: dlls/msxml3/msxml.mc:297
-#, fuzzy
-#| msgid "Invalid media type.\n"
 msgid "Invalid model in DTD contentspec\n"
-msgstr "Ongeldig media-type.\n"
+msgstr "Ongeldig model in DTD inhoudspec\n"
 
 #: dlls/msxml3/msxml.mc:304
-#, fuzzy
-#| msgid "Invalid group attributes.\n"
 msgid "Invalid DTD attribute type\n"
-msgstr "Ongeldige groepsattributen.\n"
+msgstr "Ongeldig DTD kenmerk type\n"
 
 #: dlls/msxml3/msxml.mc:311
-#, fuzzy
-#| msgid "Invalid handle operation.\n"
 msgid "Invalid standalone declaration\n"
-msgstr "Foutieve handle handeling.\n"
+msgstr "Ongeldige zelfstandige declaratie\n"
 
 #: dlls/msxml3/msxml.mc:318
-#, fuzzy
-#| msgid "Invalid version option.\n"
 msgid "Invalid xml version\n"
-msgstr "Ongeldige versie-optie.\n"
+msgstr "Ongeldige xml versie\n"
 
 #: dlls/oleacc/oleacc.rc:31
 msgid "unknown object"
@@ -13086,10 +13014,8 @@ msgid "This array is fixed or temporarily locked"
 msgstr "Deze matrix ligt vast of is tijdelijk vergrendeld"
 
 #: dlls/vbscript/vbscript.rc:34
-#, fuzzy
-#| msgid "Division by zero error.\n"
 msgid "Division by zero"
-msgstr "Delen door nul fout.\n"
+msgstr "Delen door nul"
 
 #: dlls/vbscript/vbscript.rc:35
 msgid "Type mismatch"
@@ -13128,10 +13054,8 @@ msgid "Object variable not set"
 msgstr "De objectvariabele is niet ingesteld"
 
 #: dlls/vbscript/vbscript.rc:46
-#, fuzzy
-#| msgid "Object is not initialized.\n"
 msgid "For loop not initialized"
-msgstr "Object is niet geïnitialiseerd.\n"
+msgstr "For-lus is niet geïnitialiseerd"
 
 #: dlls/vbscript/vbscript.rc:47
 msgid "Invalid use of Null"
@@ -13177,7 +13101,7 @@ msgstr "Kan opgegeven DLL-functie niet vinden"
 
 #: dlls/vbscript/vbscript.rc:61
 msgid "This key is already associated with an element of this collection"
-msgstr ""
+msgstr "Deze sleutel is reeds verbonden aan een element in deze collectie"
 
 #: dlls/vbscript/vbscript.rc:63
 msgid "Variable uses an Automation type not supported in VBScript"
@@ -13190,228 +13114,174 @@ msgid "The remote server machine does not exist or is unavailable"
 msgstr "De externe servercomputer bestaat niet of is niet beschikbaar"
 
 #: dlls/vbscript/vbscript.rc:65
-#, fuzzy
-#| msgid "'|' is undefined"
 msgid "Variable is undefined"
-msgstr "'|' is ongedefinieerd"
+msgstr "Variabele is ongedefinieerd"
 
 #: dlls/vbscript/vbscript.rc:67
 msgid "Invalid or unqualified reference"
 msgstr "Ongeldige of niet-gekwalificeerde verwijzing"
 
 #: dlls/vbscript/vbscript.rc:68
-#, fuzzy
-#| msgid "Class does not exist.\n"
 msgid "Class not defined"
-msgstr "Klasse bestaat niet.\n"
+msgstr "Klasse ongedefineerd"
 
 #: dlls/vbscript/vbscript.rc:71
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected ']'"
-msgstr "';' verwacht"
+msgstr "']' verwacht"
 
 #: dlls/vbscript/vbscript.rc:75
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'If'"
-msgstr "';' verwacht"
+msgstr "'If' verwacht"
 
 #: dlls/vbscript/vbscript.rc:76
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'To'"
-msgstr "';' verwacht"
+msgstr "'To' verwacht"
 
 #: dlls/vbscript/vbscript.rc:77
-#, fuzzy
-#| msgid "Expected '@end'"
 msgid "Expected 'End'"
-msgstr "Verwacht '@end'"
+msgstr "'End' verwacht"
 
 #: dlls/vbscript/vbscript.rc:78
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Function'"
-msgstr "';' verwacht"
+msgstr "'Function' verwacht"
 
 #: dlls/vbscript/vbscript.rc:79
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Sub'"
-msgstr "';' verwacht"
+msgstr "'Sub' verwacht"
 
 #: dlls/vbscript/vbscript.rc:80
-#, fuzzy
-#| msgid "Expected '@end'"
 msgid "Expected 'Then'"
-msgstr "Verwacht '@end'"
+msgstr "'Then' verwacht"
 
 #: dlls/vbscript/vbscript.rc:81
-#, fuzzy
-#| msgid "Expected '@end'"
 msgid "Expected 'Wend'"
-msgstr "Verwacht '@end'"
+msgstr "'Wend' verwacht"
 
 #: dlls/vbscript/vbscript.rc:82
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Loop'"
-msgstr "';' verwacht"
+msgstr "'Loop' verwacht"
 
 #: dlls/vbscript/vbscript.rc:83
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Next'"
-msgstr "';' verwacht"
+msgstr "'Next' verwacht"
 
 #: dlls/vbscript/vbscript.rc:84
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Case'"
-msgstr "';' verwacht"
+msgstr "'Case' verwacht"
 
 #: dlls/vbscript/vbscript.rc:85
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Select'"
-msgstr "';' verwacht"
+msgstr "'Select' verwacht"
 
 #: dlls/vbscript/vbscript.rc:86
-#, fuzzy
-#| msgid "Expected '@end'"
 msgid "Expected statement"
-msgstr "Verwacht '@end'"
+msgstr "Verklaring verwacht"
 
 #: dlls/vbscript/vbscript.rc:87
-#, fuzzy
-#| msgid "Expected an operand.\n"
 msgid "Expected end of statement"
-msgstr "Verwacht een operand.\n"
+msgstr "Einde van de verklaring verwacht"
 
 #: dlls/vbscript/vbscript.rc:88
-#, fuzzy
-#| msgid "Unterminated string constant"
 msgid "Expected integer constant"
-msgstr "Onafgesloten tekenreeksconstante"
+msgstr "Gehele constante verwacht"
 
 #: dlls/vbscript/vbscript.rc:89
 msgid "Expected 'While', 'Until' or end of statement"
-msgstr ""
+msgstr "'While', 'Until' of einde van de verklaring verwacht"
 
 #: dlls/vbscript/vbscript.rc:91
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'With'"
-msgstr "';' verwacht"
+msgstr "'With' verwacht"
 
 #: dlls/vbscript/vbscript.rc:90
-#, fuzzy
-#| msgid "Secret too long.\n"
 msgid "Identifier too long"
-msgstr "Geheim te lang.\n"
+msgstr "Identificatie te lang"
 
 #: dlls/vbscript/vbscript.rc:92
-#, fuzzy
-#| msgid "Invalid flag number.\n"
 msgid "Invalid number"
-msgstr "Ongeldig vlagnumer.\n"
+msgstr "Ongeldig nummer"
 
 #: dlls/vbscript/vbscript.rc:95
-#, fuzzy
-#| msgid "Invalid use of Null"
 msgid "Invalid use of 'Me' keyword"
-msgstr "Ongeldig gebruik van Null"
+msgstr "Ongeldig gebruik van 'Me'"
 
 #: dlls/vbscript/vbscript.rc:96
 msgid "'loop' without 'do'"
-msgstr ""
+msgstr "'loop' zonder 'do'"
 
 #: dlls/vbscript/vbscript.rc:97
-#, fuzzy
-#| msgid "Invalid printer state.\n"
 msgid "Invalid 'exit' statement"
-msgstr "Ongeldige printerstatus.\n"
+msgstr "Ongeldig 'exit' verklaring"
 
 #: dlls/vbscript/vbscript.rc:98
 msgid "Invalid 'for' loop control variable"
-msgstr ""
+msgstr "Ongeldige besturingsvariabele voor de 'for'-lus"
 
 #: dlls/vbscript/vbscript.rc:99
-#, fuzzy
-#| msgid "Label redefined"
 msgid "Name redefined"
-msgstr "Label hergedefinieerd"
+msgstr "Naam hergedefinieerd"
 
 #: dlls/vbscript/vbscript.rc:100
 msgid "Must be first statement on the line"
-msgstr ""
+msgstr "Moet de eerste verklaring op de regel zijn"
 
 #: dlls/vbscript/vbscript.rc:101
 msgid "Cannot use parentheses when calling a Sub"
-msgstr ""
+msgstr "Kan geen haakjes gebruiken bij het gebruik van Sub"
 
 #: dlls/vbscript/vbscript.rc:102
-#, fuzzy
-#| msgid "Expected an operator.\n"
 msgid "Expected literal constant"
-msgstr "Verwacht een operator.\n"
+msgstr "Letterlijke constante verwacht"
 
 #: dlls/vbscript/vbscript.rc:103
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'In'"
-msgstr "';' verwacht"
+msgstr "'In' verwacht"
 
 #: dlls/vbscript/vbscript.rc:104
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Class'"
-msgstr "';' verwacht"
+msgstr "'Class' verwacht"
 
 #: dlls/vbscript/vbscript.rc:105
 msgid "Must be defined inside a Class"
-msgstr ""
+msgstr "Moet gedefineerd zijn in een Class"
 
 #: dlls/vbscript/vbscript.rc:106
 msgid "Expected Let or Set or Get in property declaration"
-msgstr ""
+msgstr "Let, Set of Get verwacht in eigenschap declaratie"
 
 #: dlls/vbscript/vbscript.rc:107
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Expected 'Property'"
-msgstr "';' verwacht"
+msgstr "'Property' verwacht"
 
 #: dlls/vbscript/vbscript.rc:108
 msgid "Number of arguments must be consistent across properties specification"
 msgstr ""
+"Het aantal argumenten moet in alle eigenschapsspecificaties hetzelfde zijn"
 
 #: dlls/vbscript/vbscript.rc:109
 msgid "Cannot have multiple default property/method in a Class"
 msgstr ""
+"Meerdere standard eigenschappen/methodes in een Class zijn niet mogelijk"
 
 #: dlls/vbscript/vbscript.rc:110
 msgid "Class initialize or terminate do not have arguments"
-msgstr ""
+msgstr "Geen argumenten bij Class initialiseren of beëindigen"
 
 #: dlls/vbscript/vbscript.rc:111
 msgid "Property set or let must have at least one argument"
-msgstr ""
+msgstr "Eigenschappen set of let moeten minstens een argument hebben"
 
 #: dlls/vbscript/vbscript.rc:112
-#, fuzzy
-#| msgid "Expected ';'"
 msgid "Unexpected 'Next'"
-msgstr "';' verwacht"
+msgstr "'Next' verwacht"
 
 #: dlls/vbscript/vbscript.rc:113
 msgid "'Default' specification must also specify 'Public'"
-msgstr ""
+msgstr "Specificatie van 'Default' moet ook 'Public' specificeren"
 
 #: dlls/vbscript/vbscript.rc:114
 msgid "'Default' specification can only be on Property Get"
-msgstr ""
+msgstr "Specificatie van 'Default' kan alleen bij Property Get"
 
 #: dlls/vbscript/vbscript.rc:116
 msgid "Microsoft VBScript compilation error"
@@ -15614,26 +15484,45 @@ msgid ""
 "//X         Execute script in debugger\n"
 "//U         Use Unicode for redirected I/O from the console\n"
 msgstr ""
+"Gebruik: CScript scriptnaam.extensie [optie...] [argumenten...]\n"
+"\n"
+"Opties:\n"
+"//B         Batch mode: Voorkomt dat scriptfouten en meldingen worden "
+"weergegeven\n"
+"//D         Actieve foutopsporing aanzetten\n"
+"//E:engine  Gebruik engine bij het uitvoeren van het script\n"
+"//H:CScript Wijzigt de standaard scripthost naar CScript.exe\n"
+"//H:WScript Wijzigt de standaard scripthost naar WScript.exe (standaard)\n"
+"//I         Interactieve mode (standaard, tegenovergestelde van //B)\n"
+"//Job:xxxx  Voer een WSF job uit\n"
+"//Logo      Logo weergeven (standaard)\n"
+"//Nologo    Geen logo weergeven: Bij het uitvoeren is er geen banner "
+"zichtbaar\n"
+"//S         Voor de gebruiker de huidige opdrachtregel opslaan\n"
+"//T:nn      Uitvoertijd in secondes: Maximale tijd dat het script mag "
+"draaien\n"
+"//X         Script uitvoeren in debugger\n"
+"//U         Gebruik Unicode voor het doorsturen van de I/O van de console\n"
 
 #: programs/wscript/wscript.rc:47
 msgid "Input Error: There is no script file specified.\n"
-msgstr ""
+msgstr "Invoerfout: Er is geen script-bestand opgegeven.\n"
 
 #: programs/wscript/wscript.rc:48
-#, fuzzy
-#| msgid "Error: Could not find process \"%1\".\n"
 msgid "Input Error: Can not find script file \"%1\".\n"
-msgstr "Fout: Kon proces \"%1\" niet vinden.\n"
+msgstr "Invoerfout: Kan script-bestand \"%1\" niet vinden.\n"
 
 #: programs/wscript/wscript.rc:49
 msgid "CScript Error: Loading script \"%1\" failed (%2).\n"
-msgstr ""
+msgstr "CScript fout: Laden van script \"%1\" mislukt (%2).\n"
 
 #: programs/wscript/wscript.rc:52
 msgid ""
 "Script execution time was exceeded on script \"%1\".\n"
 "Script execution was terminated.\n"
 msgstr ""
+"Overschrijding van de uitvoeringstijd van script \"%1\".\n"
+"Uitvoering van het script is gestopt.\n"
 
 #: programs/dxdiag/dxdiag.rc:30
 msgid "DirectX Diagnostic Tool"
@@ -19641,10 +19530,8 @@ msgid "(System default)"
 msgstr "(Systeeminstelling)"
 
 #: programs/winecfg/winecfg.rc:90
-#, fuzzy
-#| msgid "5.1 Surround"
 msgid "7.1 Surround"
-msgstr "5.1 Surround"
+msgstr "7.1 Surround"
 
 #: programs/winecfg/winecfg.rc:91
 msgid "5.1 Surround"
diff --git a/programs/oleview/tree.c b/programs/oleview/tree.c
index 0429230f5c8c..c08bf308d97f 100644
--- a/programs/oleview/tree.c
+++ b/programs/oleview/tree.c
@@ -564,6 +564,7 @@ static void AddBaseEntries(void)
 
     LoadStringW(globals.hMainInst, IDS_TREE_CLO, tvis.item.pszText,
             MAX_LOAD_STRING);
+    tvis.item.lParam = 0;
     tree.hCLO = TreeView_InsertItemW(globals.hTree, &tvis);
 
     LoadStringW(globals.hMainInst, IDS_TREE_O1O, tvis.item.pszText,
diff --git a/programs/regedit/listview.c b/programs/regedit/listview.c
index 757ce41855ce..a99b22b8e4e7 100644
--- a/programs/regedit/listview.c
+++ b/programs/regedit/listview.c
@@ -401,7 +401,7 @@ BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR highli
 
     /* account for the terminator char */
     max_val_name_len++;
-    max_val_size++;
+    max_val_size += sizeof(WCHAR);
 
     valName = malloc(max_val_name_len * sizeof(WCHAR));
     valBuf = malloc(max_val_size);
@@ -416,7 +416,7 @@ BOOL RefreshListView(HWND hwndLV, HKEY hKeyRoot, LPCWSTR keyPath, LPCWSTR highli
 	valType = 0;
         errCode = RegEnumValueW(hKey, index, valName, &valNameLen, NULL, &valType, valBuf, &valSize);
 	if (errCode != ERROR_SUCCESS) goto done;
-        valBuf[valSize] = 0;
+        *(WCHAR*)(valBuf + valSize) = 0;
         AddEntryToList(hwndLV, valName[0] ? valName : NULL, valType, valBuf, valSize, -1);
     }
 
diff --git a/server/d3dkmt.c b/server/d3dkmt.c
index e913e1129118..bd0e879f4f32 100644
--- a/server/d3dkmt.c
+++ b/server/d3dkmt.c
@@ -696,7 +696,7 @@ DECL_HANDLER(d3dkmt_share_objects)
     {
         struct dxgk_shared_resource *shared;
 
-        if (!(resource = d3dkmt_object_open( req->resource, D3DKMT_RESOURCE ))) return;
+        if (!(resource = d3dkmt_object_open( req->resource, D3DKMT_RESOURCE ))) goto done;
         if (req->mutex && !(mutex = d3dkmt_object_open( req->mutex, D3DKMT_MUTEX ))) goto done;
         if (req->sync && !(sync = d3dkmt_object_open( req->sync, D3DKMT_SYNC ))) goto done;
 
@@ -711,7 +711,7 @@ DECL_HANDLER(d3dkmt_share_objects)
     {
         struct dxgk_shared_sync *shared;
 
-        if (!(sync = d3dkmt_object_open( req->sync, D3DKMT_SYNC ))) return;
+        if (!(sync = d3dkmt_object_open( req->sync, D3DKMT_SYNC ))) goto done;
 
         if (!(shared = create_named_object( root, &dxgk_shared_sync_ops, &name, objattr->attributes | OBJ_CASE_INSENSITIVE, NULL ))) goto done;
         shared->sync = grab_object( sync );
@@ -720,6 +720,7 @@ DECL_HANDLER(d3dkmt_share_objects)
     }
 
 done:
+    if (root) release_object( root );
     if (resource) release_object( resource );
     if (mutex) release_object( mutex );
     if (sync) release_object( sync );
diff --git a/server/fd.c b/server/fd.c
index efb6e8e76b90..b6012161f7c9 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1577,7 +1577,7 @@ void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count )
             return;
         }
     }
-    set_error( STATUS_FILE_LOCK_CONFLICT );
+    set_error( STATUS_RANGE_NOT_LOCKED );
 }
 
 
diff --git a/server/process.c b/server/process.c
index f3aa6797662c..077dc42edc48 100644
--- a/server/process.c
+++ b/server/process.c
@@ -1468,6 +1468,7 @@ DECL_HANDLER(get_startup_info)
     if (!info) return;
 
     /* we return the data directly without making a copy so this can only be called once */
+    reply->debugged = !!process->debug_obj;
     reply->machine = process->machine;
     reply->info_size = info->info_size;
     size = info->data_size;
diff --git a/server/protocol.def b/server/protocol.def
index 7b467618f7ad..6c2ffc85aabe 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1159,6 +1159,7 @@ typedef volatile struct
 @REQ(get_startup_info)
 @REPLY
     data_size_t  info_size;    /* size of startup info */
+    int          debugged;     /* being debugged? */
     unsigned short machine;    /* architecture for the new process */
     VARARG(info,startup_info,info_size); /* startup information */
     VARARG(env,unicode_str);   /* environment */
diff --git a/server/request_handlers.h b/server/request_handlers.h
index 23ced153af81..03cf907c19c3 100644
--- a/server/request_handlers.h
+++ b/server/request_handlers.h
@@ -712,8 +712,9 @@ C_ASSERT( offsetof(struct new_thread_reply, handle) == 12 );
 C_ASSERT( sizeof(struct new_thread_reply) == 16 );
 C_ASSERT( sizeof(struct get_startup_info_request) == 16 );
 C_ASSERT( offsetof(struct get_startup_info_reply, info_size) == 8 );
-C_ASSERT( offsetof(struct get_startup_info_reply, machine) == 12 );
-C_ASSERT( sizeof(struct get_startup_info_reply) == 16 );
+C_ASSERT( offsetof(struct get_startup_info_reply, debugged) == 12 );
+C_ASSERT( offsetof(struct get_startup_info_reply, machine) == 16 );
+C_ASSERT( sizeof(struct get_startup_info_reply) == 24 );
 C_ASSERT( offsetof(struct init_process_done_request, teb) == 16 );
 C_ASSERT( offsetof(struct init_process_done_request, peb) == 24 );
 C_ASSERT( sizeof(struct init_process_done_request) == 32 );
diff --git a/server/request_trace.h b/server/request_trace.h
index 58fb6a375166..7d1a1c406d4e 100644
--- a/server/request_trace.h
+++ b/server/request_trace.h
@@ -119,6 +119,7 @@ static void dump_get_startup_info_request( const struct get_startup_info_request
 static void dump_get_startup_info_reply( const struct get_startup_info_reply *req )
 {
     fprintf( stderr, " info_size=%u", req->info_size );
+    fprintf( stderr, ", debugged=%d", req->debugged );
     fprintf( stderr, ", machine=%04x", req->machine );
     dump_varargs_startup_info( ", info=", min( cur_size, req->info_size ));
     dump_varargs_unicode_str( ", env=", cur_size );
@@ -4588,6 +4589,7 @@ static const struct
     { "PROCESS_IN_JOB",              STATUS_PROCESS_IN_JOB },
     { "PROCESS_IS_TERMINATING",      STATUS_PROCESS_IS_TERMINATING },
     { "PROCESS_NOT_IN_JOB",          STATUS_PROCESS_NOT_IN_JOB },
+    { "RANGE_NOT_LOCKED",            STATUS_RANGE_NOT_LOCKED },
     { "REPARSE_POINT_NOT_RESOLVED",  STATUS_REPARSE_POINT_NOT_RESOLVED },
     { "SECTION_TOO_BIG",             STATUS_SECTION_TOO_BIG },
     { "SEMAPHORE_LIMIT_EXCEEDED",    STATUS_SEMAPHORE_LIMIT_EXCEEDED },
diff --git a/tools/gitlab/image.docker b/tools/gitlab/image.docker
index 1bb9600267ab..7e36c1e5c8f3 100644
--- a/tools/gitlab/image.docker
+++ b/tools/gitlab/image.docker
@@ -75,6 +75,7 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
         lld \
         llvm \
         mesa-vulkan-drivers \
+        nasm \
         netbase \
         ocl-icd-opencl-dev \
         perl \
diff --git a/tools/gitlab/test.yml b/tools/gitlab/test.yml
index 4888bed6909f..86ad2a784e62 100644
--- a/tools/gitlab/test.yml
+++ b/tools/gitlab/test.yml
@@ -7,7 +7,7 @@
   variables:
     GIT_STRATEGY: none
     GECKO_VER: 2.47.4
-    MONO_VER: 11.1.0
+    MONO_VER: 11.2.0
   cache:
     - key: wine-gecko-$GECKO_VER
       paths:
diff --git a/tools/make_makefiles b/tools/make_makefiles
index 194940d8aacd..865e7f8c9059 100755
--- a/tools/make_makefiles
+++ b/tools/make_makefiles
@@ -186,7 +186,7 @@ sub get_makedep_flags($)
     {
         while (<FILE>)
         {
-            next unless /^#\s*pragma\s+makedep\s+(.*)/;
+            next unless /^[#%]\s*pragma\s+makedep\s+(.*)/;
             foreach my $flag (split /\s+/, $1)
             {
                 last if $flag eq "depend";
@@ -299,7 +299,7 @@ sub assign_sources_to_makefiles(@)
         {
             next unless $dir eq "include";
         }
-        elsif ($name !~ /\.(S|c|cpp|desktop|in|inl|l|m|mc|po|rc|rh|sfd|svg|ver|x|y)$/)
+        elsif ($name !~ /\.(S|asm|c|cpp|desktop|in|inl|l|m|mc|po|rc|rh|sfd|svg|ver|x|y)$/)
         {
             next;
         }
diff --git a/tools/make_specfiles b/tools/make_specfiles
index 186c8069b5eb..7483a9c1e727 100755
--- a/tools/make_specfiles
+++ b/tools/make_specfiles
@@ -130,6 +130,7 @@ my @dll_groups =
   "bcrypt",
   "ncrypt",
   "cng.sys",
+  "ksecdd.sys",
  ],
  [
   "ntoskrnl.exe",
diff --git a/tools/makedep.c b/tools/makedep.c
index 9116df34ee07..9b3eb0623d1d 100644
--- a/tools/makedep.c
+++ b/tools/makedep.c
@@ -151,6 +151,7 @@ static const char *fontforge;
 static const char *convert;
 static const char *flex;
 static const char *bison;
+static const char *nasm;
 static const char *rsvg;
 static const char *icotool;
 static const char *msgfmt;
@@ -1174,6 +1175,37 @@ static void parse_cxx_file( struct file *source, FILE *file )
 }
 
 
+/*******************************************************************
+ *         parse_nasm_directive
+ */
+static void parse_nasm_directive( struct file *source, char *str )
+{
+    str = skip_spaces( str );
+    if (*str++ != '%') return;
+    str = skip_spaces( str );
+
+    if (!strncmp( str, "include", 7 ))
+        parse_include_directive( source, str + 7 );
+    else if (!strncmp( str, "pragma", 6 ))
+        parse_pragma_directive( source, str + 6 );
+}
+
+
+/*******************************************************************
+ *         parse_nasm_file
+ */
+static void parse_nasm_file( struct file *source, FILE *file )
+{
+    char *buffer;
+
+    input_line = 0;
+    while ((buffer = get_line( file )))
+    {
+        parse_nasm_directive( source, buffer );
+    }
+}
+
+
 /*******************************************************************
  *         parse_rc_file
  */
@@ -1291,6 +1323,7 @@ static const struct
     { ".x",   parse_c_file },
     { ".y",   parse_c_file },
     { ".S",   parse_asm_file },
+    { ".asm", parse_nasm_file },
     { ".idl", parse_idl_file },
     { ".cpp", parse_cxx_file },
     { ".hpp", parse_cxx_file },
@@ -2508,6 +2541,7 @@ static struct install_command *find_install_command( enum install_rules rules, s
 
     ARRAY_FOR_EACH( cmd, &install_commands[rules], struct install_command )
     {
+        if (cmd->dest) continue;
         if (strcmp( cmd->dir, dir )) continue;
         if (args.count != cmd->args.count) continue;
         for (i = 0; i < args.count; i++) if (strcmp( args.str[i], cmd->args.str[i] )) break;
@@ -3575,6 +3609,45 @@ static void output_source_winmd( struct makefile *make, struct incl_file *source
 }
 
 
+/*******************************************************************
+ *         output_source_nasm
+ */
+static void output_source_nasm( struct makefile *make, struct incl_file *source, const char *obj )
+{
+    struct strarray defines = get_source_defines( make, source, obj );
+    struct strarray targets = empty_strarray;
+    unsigned int arch;
+
+    if (!nasm) return;
+
+    for (arch = 1; arch < archs.count; arch++)
+    {
+        int cpu = get_cpu_from_name( archs.str[arch] );
+        const char *obj_name;
+
+        if (cpu != CPU_i386 && cpu != CPU_x86_64) continue;
+
+        obj_name = strmake( "%s%s.o", arch_dirs[arch], obj );
+        strarray_add( &targets, obj_name );
+        strarray_add( &make->object_files[arch], obj_name );
+
+        output( "%s: %s\n", obj_dir_path( make, obj_name ), source->filename );
+        output( "\t%s%s -o $@ %s", cmd_prefix( "AS" ), nasm, source->filename );
+        output_filename( cpu == CPU_i386 ? "-fwin32" : "-fwin64" );
+        output_filenames( defines );
+        output( "\n" );
+    }
+
+    if (targets.count && source->dependencies.count)
+    {
+        output_filenames_obj_dir( make, targets );
+        output( ":" );
+        output_filenames( source->dependencies );
+        output( "\n" );
+    }
+}
+
+
 /*******************************************************************
  *         output_source_one_arch
  */
@@ -3587,6 +3660,7 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou
     struct strarray cflags = empty_strarray;
 
     if (make->disabled[arch] && !(source->file->flags & FLAG_C_IMPLIB)) return;
+    if (is_subdir_other_arch( source->name, arch )) return;
 
     if (arch)
     {
@@ -3594,7 +3668,6 @@ static void output_source_one_arch( struct makefile *make, struct incl_file *sou
         if (!is_multiarch( arch )) return;
         if (!is_using_msvcrt( make ) && !make->staticlib && !(source->file->flags & FLAG_C_IMPLIB)) return;
         if ((source->file->flags & FLAG_C_CXX) && !get_expanded_arch_var( make, "CXX", arch )) return;
-        if ((source->file->flags & FLAG_C_ASM) && is_subdir_other_arch( source->name, arch )) return;
     }
     else if (source->file->flags & FLAG_C_UNIX)
     {
@@ -3812,6 +3885,7 @@ static const struct
     { "spec", output_source_spec },
     { "xml", output_source_xml },
     { "winmd", output_source_winmd },
+    { "asm", output_source_nasm },
     { NULL, output_source_default }
 };
 
@@ -4675,6 +4749,7 @@ static void output_silent_rules(void)
 {
     static const char *cmds[] =
     {
+        "AS",
         "BISON",
         "BUILD",
         "CC",
@@ -5035,6 +5110,7 @@ int main( int argc, char *argv[] )
     convert            = get_expanded_make_variable( top_makefile, "CONVERT" );
     flex               = get_expanded_make_variable( top_makefile, "FLEX" );
     bison              = get_expanded_make_variable( top_makefile, "BISON" );
+    nasm               = get_expanded_make_variable( top_makefile, "NASM" );
     rsvg               = get_expanded_make_variable( top_makefile, "RSVG" );
     icotool            = get_expanded_make_variable( top_makefile, "ICOTOOL" );
     msgfmt             = get_expanded_make_variable( top_makefile, "MSGFMT" );
@@ -5045,6 +5121,7 @@ int main( int argc, char *argv[] )
 
     if (root_src_dir && !strcmp( root_src_dir, "." )) root_src_dir = NULL;
     if (tools_dir && !strcmp( tools_dir, "." )) tools_dir = NULL;
+    if (nasm && !strcmp( nasm, "false" )) nasm = NULL;
     if (!exe_ext) exe_ext = "";
     if (!dll_ext[0]) dll_ext[0] = "";
     if (!tools_ext) tools_ext = "";
