From ced7daff70bee03c69199fb01f20fa28a446d108 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:23:17 +0100 Subject: [PATCH 01/48] hires-mic: dedicated branch + plan for a native Windows AirPods microphone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New feature branch (off cross-platform, merges back when ready) to expose the AirPods' hi-res AAC-ELD mic as a native Windows microphone via our own virtual audio driver (SYSVAD-based) instead of a third-party VB-Cable — the Windows counterpart to Linux PR #655. crossplatform/hires-mic/PLAN.md lays out the architecture (AAP driver -> app decode -> LibrePodsMic virtual driver -> Windows mic), the incremental phases, risks (audio-driver complexity, AAC-ELD patents), and references. Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 crossplatform/hires-mic/PLAN.md diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md new file mode 100644 index 000000000..2ef9d8f2a --- /dev/null +++ b/crossplatform/hires-mic/PLAN.md @@ -0,0 +1,72 @@ +# Hi-res AirPods microphone on Windows — feature branch + +**Branch:** `windows-hires-mic` (off `cross-platform`; merges back into it when done). + +**Goal:** expose the AirPods' hi-res (AAC-ELD) microphone as a **native Windows +microphone**, so any app (Teams, Zoom, Discord, OBS…) can use it — the same +feature the Linux side is adding in +[PR #655](https://github.com/librepods-org/librepods/pull/655), but with a +self-contained **virtual audio driver** instead of PipeWire. + +## Why a driver (not VB-Cable) + +Windows has no API to "create a virtual microphone" — it needs a virtual audio +device driver. We already ship a signed kernel driver (`LibrePodsAAP`), so a +second one is the clean, dependency-free path (no third-party VB-Cable). Base it +on Microsoft's **SYSVAD** sample (a virtual audio device with capture + render +endpoints, no hardware). NOTE: audio drivers use **PortCls/AVStream** or the +newer **ACX** framework — different from the KMDF+BRB approach of `LibrePodsAAP`. + +## Architecture + +``` +AirPods ──AAP / L2CAP──▶ LibrePodsAAP driver ──IOCTL──▶ app + │ decode AAC-ELD (FFmpeg / libavcodec) + │ → PCM + ▼ + LibrePodsMic virtual audio driver + │ + ▼ + Windows sees a "LibrePods Microphone" + (Teams / Zoom / Discord / OBS / …) +``` + +The protocol (enable-mic control command, uplink packet framing, AAC-ELD params) +is platform-neutral and comes from PR #655 — it lands in the shared +`crossplatform-rust` crate (`aacp`/`media_controller`), gated per platform for +the sink. + +## Phases (incremental, each independently testable) + +1. **Virtual-mic driver base** — build + test-sign + install SYSVAD (or a trimmed + fork) so Windows shows a "LibrePods Microphone" capture endpoint. Prove it + appears in Sound settings and apps. *(driver: `windows-driver/LibrePodsMic/`)* +2. **PCM bridge** — an IOCTL/shared-ring for user mode to push PCM samples into + the driver; feed a test tone / a WAV → verify it's audible on the virtual mic + (record in Voice Recorder / Audacity). +3. **Protocol port** — from PR #655: the AAP command that enables the hi-res mic, + the uplink packet framing + watchdog, and AAC-ELD decoding via FFmpeg + (libavcodec) — in the shared crate, `platform::MicSink` for the OS sink. +4. **Integration** — talk into the AirPods → decoded audio reaches the virtual + mic. Conversation-awareness pause during capture, AGC toggle, settings + persistence (mirror #655). + +## Risks / open questions + +- **Audio driver complexity** — WaveRT buffering, formats, timing. SYSVAD is a + large sample; getting a stable capture endpoint is the bulk of the work. +- **AAC-ELD patents** — the decoder (FFmpeg) is patent-encumbered; distribution + implications (PR #655 raises the same). Keep the decoder optional / documented. +- **Latency** — L2CAP → decode → driver ring; needs a small, steady buffer. +- **Test-signing** — same Test Mode requirement as the AAP driver. + +## References + +- Microsoft SYSVAD (virtual audio device sample), and the ACX audio samples. +- LibrePods PR #655 (Linux hi-res mic: AAC-ELD + PipeWire) — the protocol RE. +- `../windows-driver/LibrePodsAAP/` — our existing driver + build/sign/install loop. + +## Status + +Phase 1 not started. This branch holds the plan + (to come) the `LibrePodsMic` +driver and the shared-crate mic path. From f9f8a1722a13f2ecd3d103f78b36da08820a41f2 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:31:26 +0100 Subject: [PATCH 02/48] =?UTF-8?q?hires-mic(Phase=201):=20LibrePodsMic=20vi?= =?UTF-8?q?rtual-audio=20driver=20base=20(ACX=20AudioCodec)=20=E2=80=94=20?= =?UTF-8?q?builds?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Import the Microsoft ACX AudioCodec sample (MIT, from Windows-driver-samples audio/Acx/Samples) as the base for the virtual microphone driver: a ROOT-enumerated (software, no-hardware) audio device with a capture circuit, built on ACX over KMDF — the same framework family as LibrePodsAAP (vs SYSVAD's PortCls). Confirmed it BUILDS with VS2026 + WDK 28000 (AudioCodec.sys, EXIT 0) — resolving the biggest Phase-1 unknown. README notes origin/license + status. Next: install the ROOT device + verify a virtual mic appears, then trim to capture-only and add the PCM bridge. Co-Authored-By: Claude Opus 4.8 --- .../AudioCodec/Driver/AudioCodec.inf | Bin 0 -> 8526 bytes .../AudioCodec/Driver/AudioCodec.sln | 60 + .../AudioCodec/Driver/AudioCodec.vcxproj | 174 +++ .../Driver/AudioCodec.vcxproj.Filters | 42 + .../LibrePodsMic/AudioCodec/Driver/Device.cpp | 439 ++++++ .../LibrePodsMic/AudioCodec/Driver/Driver.cpp | 129 ++ .../AudioCodec/Driver/DriverSettings.h | 54 + .../LibrePodsMic/AudioCodec/Driver/ReadMe.txt | 42 + .../AudioCodec/Driver/Resources.rc | 12 + .../LibrePodsMic/Common/CaptureCircuit.cpp | 799 ++++++++++ .../LibrePodsMic/Common/CircuitHelper.cpp | 620 ++++++++ .../LibrePodsMic/Common/CircuitHelper.h | 135 ++ .../LibrePodsMic/Common/KeywordDetector.cpp | 484 ++++++ .../LibrePodsMic/Common/KeywordDetector.h | 145 ++ .../LibrePodsMic/Common/NewDelete.cpp | 91 ++ .../LibrePodsMic/Common/NewDelete.h | 58 + .../LibrePodsMic/Common/Private.h | 922 +++++++++++ .../LibrePodsMic/Common/RenderCircuit.cpp | 807 ++++++++++ .../LibrePodsMic/Common/SamplesCommon.vcxproj | 179 +++ .../LibrePodsMic/Common/SaveData.cpp | 1103 ++++++++++++++ .../LibrePodsMic/Common/SaveData.h | 259 ++++ .../LibrePodsMic/Common/SimPeakMeter.cpp | 106 ++ .../LibrePodsMic/Common/SimPeakMeter.h | 51 + .../LibrePodsMic/Common/StreamEngine.cpp | 1345 +++++++++++++++++ .../LibrePodsMic/Common/StreamEngine.h | 449 ++++++ .../LibrePodsMic/Common/ToneGenerator.cpp | 297 ++++ .../LibrePodsMic/Common/ToneGenerator.h | 88 ++ .../LibrePodsMic/Common/Trace_macros.h | 470 ++++++ .../LibrePodsMic/Common/WaveReader.cpp | 769 ++++++++++ .../LibrePodsMic/Common/WaveReader.h | 196 +++ .../LibrePodsMic/Inc/AudioFormats.h | 959 ++++++++++++ .../LibrePodsMic/Inc/cpp_utils.h | 71 + .../windows-driver/LibrePodsMic/README.md | 32 + .../LibrePodsMic/Shared/Public.h | 342 +++++ .../LibrePodsMic/Shared/Trace.h | 33 + 35 files changed, 11762 insertions(+) create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.inf create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.sln create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj.Filters create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Driver.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/DriverSettings.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/ReadMe.txt create mode 100644 crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Resources.rc create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/Private.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/RenderCircuit.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/SaveData.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/SaveData.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/Trace_macros.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Inc/AudioFormats.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Inc/cpp_utils.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/README.md create mode 100644 crossplatform/windows-driver/LibrePodsMic/Shared/Public.h create mode 100644 crossplatform/windows-driver/LibrePodsMic/Shared/Trace.h diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.inf b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.inf new file mode 100644 index 0000000000000000000000000000000000000000..889f9bdb830f65d86bba72afb1f8c1999a6e2186 GIT binary patch literal 8526 zcmeI1TTdHD6vyYeQonV_097Cv8E*6F+X_c?u_V=H& z1|yR8p|ZR?*K^LC`<(szugC6@`+?uL?i;t2JPWSkE?wV!a#ybBPTjBW+7;Y) zuIs+%y~kLWnM*g||K87O{S`a(>@d=!b>Ws+U2tW0#;=fqHSoO?_Mb5NJI`a*W+~9l z1NXx1xHhed+jmu0qg8edS_Q@%uFhx+ddjTaq22J~THj=R-@Rs3yR?3eRhkjJIo?0f z68wGlinsb@_Oy65=)YlPANYpv&5$pm>Loix!y@fk0;R@I^?vr4Yv5=nctxSG?lH5= zThwT$U{n}+MPKdbj6F+eX@FZaY5gAmg9O$Ap~s zrKLB_p15uFVczS5q`FT_CzTe=Gb2b9=bBjVZjJY!X*$4rUVD$h;#+2d$JyKZonIRu6SG}uZJagxjg*aX~mlkXTF3}bs$Mf+Y{u_^_XXMxjbh5m=k$nxbQObX^Js`Mo*lakiF2eLHedbq>Z1c<9c zm|MvGp?{)v3(BMR6+9i1gXAX*zVPP|r{v$-jCTFG+nP&nMwE zZN5r4xBxxZXv`k-r)bQ!?`y{~`>uE{COR%FmOq$B3#5Cd4@S;qdV-pUvNQt} zlkGx^r)i6p%ma5#N4lQwD1oDl1ms2K<>f2i=E96RHwlJOZ*+y27c^ehK7HSk_ehG9 zcf}NU7|sYk&4~dJ2Sb=!c!q1cpqH{M*_Y{MjK+7TQJNef2AeFSGsj-b0p!pYxpF8-9}PJ@Kn)ppE1RSmXFdES_|GEMOa77r|CEvT3r4~Can%0r3Y8~ zSZW9E27hUh%1$wxUW$e+#slE?p*Rh*H0*`Z>{}it%Y`HI3vop;cNcC|Y45-zjTuf! z_6qrq;uB=~+SPmDRFDcW3lZNC7sdh&Py<9$x4^T>Kz;8VV1 zdE9Pt#2Wih}9&3p#9(1M|H1Dbz#GMpas1i&EY4lH`3{YcPJT+VjgWB}1@mb19vrPFTHHpTm8;JWPaN+Z z%EuI;B>#e!`?YT?7m(}*mA}*JF_pyM_#Q3q|>SXetiED z*y7%Cu4Scm+kT_w1-xo`ZP497oYHM!5e>AA?;|``3<-0V@5Nnp_|fAm;^7%K`i1?A!1dk>%t@q?GrDPw28B^ebM@1sdYKT@D|$yncK zbMhPK^d)1v69npOV0=ryVW*WBeB+}<$o^~oRJvm-!d?40<>bmYduT(rbt;Ys#!L7o z&m!NZyG@g~qECZ%mT$9TZgZACKY7J#XgC74?y;gPX5SZ#+fC=h`;cY#k@M-NJj>pT zyg#NgtY{0$ti?sk>n2;nIj6V#cpvE~_dJ=wCgN>A?w;K;@}SIaAGbsKcdaC!zW;4S zRyEm5zlN>o?%Bk%bi7B-vy}ofx?zSpnygixN}f!y#xiF4kS;x0@{O-aSUpP>DnSpY zv=ztR1DH1&B;M@yNTkYw>KF1AieE9dnRd(1=FLW0vr*E#ee{dwRV_A+!%_7>p0R?= zR9AZLb1(C>R*TyAzRI#Y_cW%>>^F)(JqsXYX6nw0hT^{A6ayeaF@;s*TCVGrKjmg`0 zKfRHjH<62KkwGrwdXtCm>(VLeZr7lPrqi-k)pV3MUXTNayHLnO8a|^alHDoKQca;p zZrCB`S5?q-QO{{!LKW7m-&js=QrTU3r_A{=Ex9*v9)QU^gWh>qrZ_s{5&RnBcWz=fLRr13kO<$dv|y|+;i z@jn6ECg*8q97lC6%1bj|EP6G{552&Zvsy^b=`AVcY}(T z^%^H$_cGb^au#*#$f?2}X>5&N-RnSoDF0}S`8S^+|1=MR4TQIGS-t74us*zl4w@a@ zq!J8^SNweZPB)bw{ zmpz|r^fqWM^Zv|jv6NU(6F+v}duN)ntz6t3;wvZhr}0KTW8XZim=t-?}EpM8(zc1t#z^<~_0EpZ&6Au_RO}tpYiH zxA>4(@fTdHbsEe(+)Jz(|L!s!UwTK3d|Uo|*=Pl-0Bu%9vM(BuhS9t)n<0$Wpp*y1 Yy=mTM_l=%(6iZ$%ad%vKyCVnw0f>n2vj6}9 literal 0 HcmV?d00001 diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.sln b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.sln new file mode 100644 index 000000000..8e953b60e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.sln @@ -0,0 +1,60 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31409.214 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SamplesCommon", "SamplesCommon", "{0DF6D5E6-3B78-414B-B37B-85D9CA454487}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AudioCodec", "AudioCodec", "{0D3B6287-146E-4700-B2EE-11D520014FEA}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SamplesCommon", "..\..\Common\SamplesCommon.vcxproj", "{6A946D59-6690-4ED0-A77D-7D4C3D4B3241}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AudioCodec", "AudioCodec.vcxproj", "{C575002D-5FDE-43C7-AB19-EE846A20083A}" + ProjectSection(ProjectDependencies) = postProject + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241} = {6A946D59-6690-4ED0-A77D-7D4C3D4B3241} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|ARM64.Build.0 = Debug|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|x64.ActiveCfg = Debug|x64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|x64.Build.0 = Debug|x64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Debug|x64.Deploy.0 = Debug|x64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|ARM64.ActiveCfg = Release|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|ARM64.Build.0 = Release|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|ARM64.Deploy.0 = Release|ARM64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|x64.ActiveCfg = Release|x64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|x64.Build.0 = Release|x64 + {C575002D-5FDE-43C7-AB19-EE846A20083A}.Release|x64.Deploy.0 = Release|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|ARM64.Build.0 = Debug|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|x64.ActiveCfg = Debug|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|x64.Build.0 = Debug|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Debug|x64.Deploy.0 = Debug|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|ARM64.ActiveCfg = Release|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|ARM64.Build.0 = Release|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|ARM64.Deploy.0 = Release|ARM64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|x64.ActiveCfg = Release|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|x64.Build.0 = Release|x64 + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241} = {0DF6D5E6-3B78-414B-B37B-85D9CA454487} + {C575002D-5FDE-43C7-AB19-EE846A20083A} = {0D3B6287-146E-4700-B2EE-11D520014FEA} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8E3043F2-1C76-4A4A-9C60-A645BD6CBF24} + EndGlobalSection +EndGlobal diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj new file mode 100644 index 000000000..e4370b5d7 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + + + + + + + + + + + + + + 1 + 1 + 1 + 31 + {C575002D-5FDE-43C7-AB19-EE846A20083A} + {497e31cb-056b-4f31-abb8-447fd55ee5a5} + v4.5 + 12.0 + Debug + AudioCodec + $(LatestTargetPlatformVersion) + + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Windows Driver + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Windows Driver + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Windows Driver + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Windows Driver + + + + + + + + + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + + true + true + ..\..\common\trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\..\common;..\..\inc;..\..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + $(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;..\..\Common\$(IntDir)\SamplesCommon.lib;%(AdditionalDependencies) + + + + + true + true + ..\..\common\trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\..\common;..\..\inc;..\..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + $(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;..\..\Common\$(IntDir)\SamplesCommon.lib;%(AdditionalDependencies) + + + + + true + true + ..\..\common\trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\..\common;..\..\inc;..\..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + $(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;..\..\Common\$(IntDir)\SamplesCommon.lib;%(AdditionalDependencies) + + + + + true + true + ..\..\common\trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR);..\..\common;..\..\inc;..\..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + $(DDK_LIB_PATH)\libcntpr.lib;wpprecorder.lib;acx\km\$(ACX_VERSION_MAJOR).$(ACX_VERSION_MINOR)\acxstub.lib;..\..\Common\$(IntDir)\SamplesCommon.lib;%(AdditionalDependencies) + + + + + + + + + diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj.Filters b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj.Filters new file mode 100644 index 000000000..0b882019e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.vcxproj.Filters @@ -0,0 +1,42 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + + + + Driver Files + + + + + Header Files + + + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp new file mode 100644 index 000000000..6a94a66a5 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp @@ -0,0 +1,439 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Device.cpp - Device handling events for example driver. + +Abstract: + + This file contains the device entry points and callbacks. + +Environment: + + Kernel-mode Driver Framework + +--*/ + +#include +#include +#include "public.h" +#include +#include +#include +#include +#include "streamengine.h" +#include "DriverSettings.h" + +#ifndef __INTELLISENSE__ +#include "device.tmh" +#endif + +UNICODE_STRING g_RegistryPath = { 0 }; // This is used to store the registry settings path for the driver + +ULONG DeviceDriverTag = DRIVER_TAG; + +ULONG IdleTimeoutMsec = IDLE_TIMEOUT_MSEC; + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +CopyRegistrySettingsPath( + _In_ PUNICODE_STRING RegistryPath +) +/*++ + +Routine Description: + +Copies the following registry path to a global variable. + +\REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\\Parameters + +Arguments: + +RegistryPath - Registry path passed to DriverEntry + +Returns: + +NTSTATUS - SUCCESS if able to configure the framework + +--*/ + +{ + PAGED_CODE(); + + // + // Initializing the unicode string, so that if it is not allocated it will not be deallocated too. + // + RtlInitUnicodeString(&g_RegistryPath, nullptr); + + g_RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR); + + g_RegistryPath.Buffer = (PWCH)ExAllocatePool2(POOL_FLAG_PAGED, g_RegistryPath.MaximumLength, DRIVER_TAG); + + if (g_RegistryPath.Buffer == nullptr) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlAppendUnicodeToString(&g_RegistryPath, RegistryPath->Buffer); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +Codec_EvtBusDeviceAdd( + _In_ WDFDRIVER Driver, + _Inout_ PWDFDEVICE_INIT DeviceInit +) +/*++ + +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. We create and initialize a device object to + represent a new instance of the device. All the software resources + should be allocated in this callback. + +Arguments: + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + ACX_DEVICEINIT_CONFIG devInitCfg; + ACX_DEVICE_CONFIG devCfg; + WDFDEVICE device = nullptr; + PCODEC_DEVICE_CONTEXT devCtx; + WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Driver); + + // + // The driver calls this DDI in its AddDevice callback before creating the PnP device. + // ACX uses this call to add default/standard settings for the device to be created. + // + ACX_DEVICEINIT_CONFIG_INIT(&devInitCfg); + RETURN_IF_FAILED(AcxDeviceInitInitialize(DeviceInit, &devInitCfg)); + + // + // Initialize the pnpPowerCallbacks structure. Callback events for PNP + // and Power are specified here. If you don't supply any callbacks, + // the Framework will take appropriate default actions based on whether + // DeviceInit is initialized to be an FDO, a PDO or a filter device + // object. + // + WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks); + pnpPowerCallbacks.EvtDevicePrepareHardware = Codec_EvtDevicePrepareHardware; + pnpPowerCallbacks.EvtDeviceReleaseHardware = Codec_EvtDeviceReleaseHardware; + pnpPowerCallbacks.EvtDeviceD0Entry = Codec_EvtDeviceD0Entry; + pnpPowerCallbacks.EvtDeviceD0Exit = Codec_EvtDeviceD0Exit; + WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_DEVICE_CONTEXT); + attributes.EvtCleanupCallback = Codec_EvtDeviceContextCleanup; + + RETURN_NTSTATUS_IF_FAILED(WdfDeviceCreate(&DeviceInit, &attributes, &device)); + + // + // Init Codec's device context. + // + devCtx = GetCodecDeviceContext(device); + ASSERT(devCtx != nullptr); + + devCtx->Render = nullptr; + devCtx->Capture = nullptr; + devCtx->ExcludeD3Cold = WdfFalse; + + // + // The driver calls this DDI in its AddDevice callback after creating the PnP + // device. ACX uses this call to apply any post device settings. + // + ACX_DEVICE_CONFIG_INIT(&devCfg); + RETURN_NTSTATUS_IF_FAILED(AcxDeviceInitialize(device, &devCfg)); + + // + // Tell the framework to set the SurpriseRemovalOK in the DeviceCaps so + // that you don't get the popup in usermode (on Win2K) when you surprise + // remove the device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + pnpCaps.SurpriseRemovalOK = WdfTrue; + WdfDeviceSetPnpCapabilities(device, &pnpCaps); + + // + // Create a render circuit and capture circuit and add them to the current + // device context. These circuits will be added to the device when the + // prepare hardware callback is called. + // + RETURN_NTSTATUS_IF_FAILED(CodecR_AddStaticRender(device, &CODEC_RENDER_COMPONENT_GUID, &renderCircuitName)); + + RETURN_NTSTATUS_IF_FAILED(CodecC_AddStaticCapture(device, &CODEC_CAPTURE_COMPONENT_GUID, &MIC_CUSTOM_NAME, &captureCircuitName)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Codec_EvtDevicePrepareHardware( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourceList, + _In_ WDFCMRESLIST ResourceListTranslated +) +/*++ + +Routine Description: + + In this callback, the driver does whatever is necessary to make the + hardware ready to use. + +Arguments: + + Device - handle to a device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + + UNREFERENCED_PARAMETER(ResourceList); + UNREFERENCED_PARAMETER(ResourceListTranslated); + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // NOTE: Download firmware here. + + // NOTE: Register streaming h/w resources here. + + // + // Set power policy data. + // + RETURN_NTSTATUS_IF_FAILED(Codec_SetPowerPolicy(Device)); + + // + // Setting up the data saving (CSaveData) and wave file reader (CWaveReader) + // utility classes which will be used by the virtual streaming engine. + // + RETURN_NTSTATUS_IF_FAILED(CSaveData::SetDeviceObject(WdfDeviceWdmGetDeviceObject(Device))); + + RETURN_NTSTATUS_IF_FAILED(CSaveData::InitializeWorkItems(WdfDeviceWdmGetDeviceObject(Device))); + + RETURN_NTSTATUS_IF_FAILED(CWaveReader::InitializeWorkItems(WdfDeviceWdmGetDeviceObject(Device))); + + // + // The driver uses this DDI to associate a circuit to a device. After + // this call the circuit is not visible until the device goes in D0. + // For a real driver there should be a check here to make sure the + // circuit has not been added already (there could be a situation where + // prepareHardware is called multiple times and releaseHardware is only + // called once). + // + + ASSERT(devCtx->Render); + RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Render)); + + ASSERT(devCtx->Capture); + RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Capture)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Codec_EvtDeviceReleaseHardware( + _In_ WDFDEVICE Device, + _In_ WDFCMRESLIST ResourceListTranslated +) +/*++ + +Routine Description: + + In this callback, the driver releases the h/w resources allocated in the + prepare h/w callback. + +Arguments: + + Device - handle to a device + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PCODEC_DEVICE_CONTEXT devCtx; + + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(ResourceListTranslated); + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // The driver uses this DDI to delete a circuit from the current device. + // + RETURN_NTSTATUS_IF_FAILED(AcxDeviceRemoveCircuit(Device, devCtx->Render)); + RETURN_NTSTATUS_IF_FAILED(AcxDeviceRemoveCircuit(Device, devCtx->Capture)); + + // NOTE: Release streaming h/w resources here. + + CSaveData::DestroyWorkItems(); + CWaveReader::DestroyWorkItems(); + + status = STATUS_SUCCESS; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Codec_EvtDeviceD0Entry( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(PreviousState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +NTSTATUS +Codec_EvtDeviceD0Exit( + _In_ WDFDEVICE Device, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + NTSTATUS status = STATUS_SUCCESS; + POWER_ACTION powerAction; + + PAGED_CODE(); + + powerAction = WdfDeviceGetSystemPowerAction(Device); + + // + // Update the power policy D3-cold info for Connected Standby. + // + if (TargetState == WdfPowerDeviceD3 && powerAction == PowerActionNone) + { + PCODEC_DEVICE_CONTEXT devCtx; + WDF_TRI_STATE excludeD3Cold = WdfTrue; + ACX_DX_EXIT_LATENCY latency; + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Get the current exit latency. + // + latency = AcxDeviceGetCurrentDxExitLatency(Device, + WdfDeviceGetSystemPowerAction(Device), + TargetState); + + // + // If the current exit latency for the ACX device is responsive + // (not instant or fast) then D3-cold does not need to be excluded. + // Otherwise, D3-cold should be excluded because if the hardware + // goes into this state it will take too long to go back into D0 + // and respond. + // + if (latency == AcxDxExitLatencyResponsive) + { + excludeD3Cold = WdfFalse; + } + + if (devCtx->ExcludeD3Cold != excludeD3Cold) + { + devCtx->ExcludeD3Cold = excludeD3Cold; + + RETURN_NTSTATUS_IF_FAILED(Codec_SetPowerPolicy(Device)); + } + } + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Codec_SetPowerPolicy( + _In_ WDFDEVICE Device +) +{ + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Init the idle policy structure. + // + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; + WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT(&idleSettings, IdleCannotWakeFromS0); + idleSettings.IdleTimeout = IDLE_POWER_TIMEOUT; + idleSettings.IdleTimeoutType = SystemManagedIdleTimeoutWithHint; + idleSettings.ExcludeD3Cold = devCtx->ExcludeD3Cold; + + RETURN_NTSTATUS_IF_FAILED(WdfDeviceAssignS0IdleSettings(Device, &idleSettings)); + + return status; +} + +VOID +Codec_EvtDeviceContextCleanup( + _In_ WDFOBJECT WdfDevice +) +/*++ + +Routine Description: + + In this callback, it cleans up device context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + nullptr + +--*/ +{ + WDFDEVICE device; + PCODEC_DEVICE_CONTEXT devCtx; + + device = (WDFDEVICE)WdfDevice; + devCtx = GetCodecDeviceContext(device); + ASSERT(devCtx != nullptr); + + if (devCtx->Capture) + { + CodecC_CircuitCleanup(devCtx->Capture); + } +} diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Driver.cpp b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Driver.cpp new file mode 100644 index 000000000..aca3e86f1 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Driver.cpp @@ -0,0 +1,129 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + +Module Name: + + Driver.cpp + +Abstract: + + This file contains the driver entry points and callbacks. + +Environment: + + Kernel-mode Driver Framework + +--*/ + +#include "public.h" +#include "cpp_utils.h" + +#ifndef __INTELLISENSE__ +#include "driver.tmh" +#endif + +_Use_decl_annotations_ +void AudioCodecDriverUnload( + _In_ WDFDRIVER Driver +) +{ + PAGED_CODE(); + + if (!Driver) + { + ASSERT(FALSE); + return; + } + + WPP_CLEANUP(WdfDriverWdmGetDriverObject(Driver)); + + if (g_RegistryPath.Buffer != nullptr) + { + ExFreePool(g_RegistryPath.Buffer); + RtlZeroMemory(&g_RegistryPath, sizeof(g_RegistryPath)); + } + + return; +} + +INIT_CODE_SEG +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath +) +/*++ + +Routine Description: + DriverEntry initializes the driver and is the first routine called by the + system after the driver is loaded. DriverEntry specifies the other entry + points in the function driver, such as EvtDevice and DriverUnload. + +Parameters Description: + + DriverObject - represents the instance of the function driver that is loaded + into memory. DriverEntry must initialize members of DriverObject before it + returns to the caller. DriverObject is allocated by the system before the + driver is loaded, and it is released by the system after the system unloads + the function driver from memory. + + RegistryPath - represents the driver specific path in the Registry. + The function driver can use the path to store driver related data between + reboots. The path does not store hardware instance specific data. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG wdfCfg; + ACX_DRIVER_CONFIG acxCfg; + WDFDRIVER driver; + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + WPP_INIT_TRACING(DriverObject, RegistryPath); + + auto exit = scope_exit([&status, &DriverObject]() { + if (!NT_SUCCESS(status)) + { + WPP_CLEANUP(DriverObject); + + if (g_RegistryPath.Buffer != nullptr) + { + ExFreePool(g_RegistryPath.Buffer); + RtlZeroMemory(&g_RegistryPath, sizeof(g_RegistryPath)); + } + } + }); + + RETURN_NTSTATUS_IF_FAILED(CopyRegistrySettingsPath(RegistryPath)); + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + WDF_DRIVER_CONFIG_INIT(&wdfCfg, Codec_EvtBusDeviceAdd); + wdfCfg.EvtDriverUnload = AudioCodecDriverUnload; + + // + // Create a framework driver object to represent our driver. + // + RETURN_NTSTATUS_IF_FAILED(WdfDriverCreate(DriverObject, RegistryPath, &attributes, &wdfCfg, &driver)); + + // + // Initializing the ACX driver configuration struct which contains size and flags + // elements. + // + ACX_DRIVER_CONFIG_INIT(&acxCfg); + + // + // The driver calls this DDI in its DriverEntry callback after creating the WDF driver + // object. ACX uses this call to apply any post driver settings. + // + RETURN_NTSTATUS_IF_FAILED(AcxDriverInitialize(driver, &acxCfg)); + + return status; +} diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/DriverSettings.h b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/DriverSettings.h new file mode 100644 index 000000000..84ac730a5 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/DriverSettings.h @@ -0,0 +1,54 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + DriverSettings.h + +Abstract: + + Contains guid definitions and other definitions used by the render and capture circuits + for this specific driver. Driver developers should replace these definitions with their + own. + +Environment: + + Kernel mode + +--*/ + +// Defining the component ID for the capture circuit. This ID uniquely identifies the circuit instance (vendor specific): +DEFINE_GUID(CODEC_CAPTURE_COMPONENT_GUID, 0xc3ee9ec6, 0x8e8c, 0x49e9, 0xaf, 0x4b, 0xa7, 0xfc, 0x28, 0xe9, 0xd2, 0xe7); + +// Defines a custom name for the capture circuit bridge pin: +DEFINE_GUID(MIC_CUSTOM_NAME, 0xd5649dc4, 0x2fa2, 0x418b, 0xb2, 0x78, 0x39, 0x7, 0x64, 0x6b, 0x3, 0xe); + +// Defining the component ID for the render circuit. This ID uniquely identifies the circuit instance (vendor specific): +DEFINE_GUID(CODEC_RENDER_COMPONENT_GUID, 0xd03deb75, 0xe5b2, 0x45f7, 0x91, 0xfa, 0xf7, 0xae, 0x42, 0xdd, 0xf, 0xe0); + +// This is always the definition for the system container guid: +DEFINE_GUID(SYSTEM_CONTAINER_GUID, 0x00000000, 0x0000, 0x0000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + +// Driver developers should update this guid if the container is a device rather than a +// system. Otherwise, this GUID should stay the same: +DEFINE_GUID(DEVICE_CONTAINER_GUID, 0x00000000, 0x0000, 0x0000, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); + +// AudioCodec driver tag: +#define DRIVER_TAG (ULONG) 'CduA' + +// The idle timeout in msec for power policy structure: +#define IDLE_TIMEOUT_MSEC (ULONG) 10000 + +// The WPP control GUID defined in Trace.h should also be updated to be unique. + +// This string must match the string defined in AudioCodec.inf for the microphone name: +DECLARE_CONST_UNICODE_STRING(captureCircuitName, L"Microphone0"); + +// This string must match the string defined in AudioCodec.inf for the speaker name: +DECLARE_CONST_UNICODE_STRING(renderCircuitName, L"Speaker0"); diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/ReadMe.txt b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/ReadMe.txt new file mode 100644 index 000000000..ebc61c6da --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/ReadMe.txt @@ -0,0 +1,42 @@ +======================================================================== + AudioCodec Project Overview +======================================================================== + +This file contains a summary of what you will find in each of the files that make up your project. + +AudioCodec.vcxproj + This is the main project file for projects generated using an Application Wizard. + It contains information about the version of the product that generated the file, and + information about the platforms, configurations, and project features selected with the + Application Wizard. + +AudioCodec.vcxproj.filters + This is the filters file for VC++ projects generated using an Application Wizard. + It contains information about the association between the files in your project + and the filters. This association is used in the IDE to show grouping of files with + similar extensions under a specific node (for e.g. ".cpp" files are associated with the + "Source Files" filter). + +Driver.cpp & Driver.h + DriverEntry and WDFDRIVER related functionality and callbacks. Driver developers should + make changes to these files for their specific driver as necessary. + +Device.cpp & Device.h + WDFDEVICE related functionality and callbacks. Driver developers should make changes to + these files for their specific driver as necessary. + +Trace.h + Definitions for WPP tracing. + +DriverSettings.h + Contains guid definitions and other definitions used by the render and capture circuits + for this specific driver. Driver developers should replace these definitions with their + own. + +///////////////////////////////////////////////////////////////////////////// + +Learn more about Kernel Mode Driver Framework here: + +http://msdn.microsoft.com/en-us/library/ff544296(v=VS.85).aspx + +///////////////////////////////////////////////////////////////////////////// diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Resources.rc b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Resources.rc new file mode 100644 index 000000000..60cfd1939 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Resources.rc @@ -0,0 +1,12 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Audio Codec Acx Sample Driver" +#define VER_INTERNALNAME_STR "AudioCodec.sys" +#define VER_ORIGINALFILENAME_STR "AudioCodec.sys" + +#include "common.ver" + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp new file mode 100644 index 000000000..f255316b1 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp @@ -0,0 +1,799 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + CaptureCircuit.cpp + +Abstract: + + Capture Circuit. This file contains routines to create and handle + capture circuit. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include +#include +#include +#include "AudioFormats.h" +#include "streamengine.h" +#include "cpp_utils.h" +#include "circuithelper.h" + +#ifndef __INTELLISENSE__ +#include "captureCircuit.tmh" +#endif + +// +// Controls how the custom name of the bridge pin is read. +// +BOOL g_UseCustomInfName = TRUE; + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtAcxPinSetDataFormat( + _In_ ACXPIN Pin, + _In_ ACXDATAFORMAT DataFormat +) +/*++ + +Routine Description: + + This ACX pin callback sets the device/mixed format. + +Return Value: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(DataFormat); + + PAGED_CODE(); + + // NOTE: update device/mixed format here. + + return STATUS_NOT_SUPPORTED; +} + +/////////////////////////////////////////////////////////// +// +// For more information on volume element see: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/ksnodetype-volume +// +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtVolumeAssignLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _In_ LONG VolumeLevel +) +{ + PAGED_CODE(); + + ASSERT(Volume); + PVOLUME_ELEMENT_CONTEXT volumeCtx = GetVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel != ALL_CHANNELS_ID) + { + volumeCtx->VolumeLevel[Channel] = VolumeLevel; + } + else + { + for (ULONG i = 0; i < MAX_CHANNELS; ++i) + { + volumeCtx->VolumeLevel[i] = VolumeLevel; + } + } + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtVolumeRetrieveLevelCallback( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _Out_ LONG * VolumeLevel +) +{ + PAGED_CODE(); + + ASSERT(Volume); + PVOLUME_ELEMENT_CONTEXT volumeCtx = GetVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel == ALL_CHANNELS_ID) + { + Channel = 0; + } + + *VolumeLevel = volumeCtx->VolumeLevel[Channel]; + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateVolumeElement( + _In_ ACXCIRCUIT Circuit, + _Out_ ACXVOLUME* Element +) +/*++ + +Routine Description: + + This routine creates a volume element. + +Return Value: + + NT status value +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + ACX_VOLUME_CALLBACKS volumeCallbacks; + ACX_VOLUME_CONFIG volumeCfg; + VOLUME_ELEMENT_CONTEXT * volumeCtx; + + PAGED_CODE(); + + // + // The driver uses this DDI to assign its volume element callbacks. + // + ACX_VOLUME_CALLBACKS_INIT(&volumeCallbacks); + volumeCallbacks.EvtAcxVolumeAssignLevel = CodecC_EvtVolumeAssignLevelCallback; + volumeCallbacks.EvtAcxVolumeRetrieveLevel = CodecC_EvtVolumeRetrieveLevelCallback; + + // + // Create Volume element + // + ACX_VOLUME_CONFIG_INIT(&volumeCfg); + volumeCfg.ChannelsCount = MAX_CHANNELS; + volumeCfg.Minimum = VOLUME_LEVEL_MINIMUM; + volumeCfg.Maximum = VOLUME_LEVEL_MAXIMUM; + volumeCfg.SteppingDelta = VOLUME_STEPPING; + volumeCfg.Callbacks = &volumeCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, VOLUME_ELEMENT_CONTEXT); + attributes.ParentObject = Circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxVolumeCreate(Circuit, &attributes, &volumeCfg, Element)); + + ASSERT(*Element != nullptr); + volumeCtx = GetVolumeElementContext(*Element); + ASSERT(volumeCtx); + + // + // (max + min)/2 puts it in the middle of the valid range, divide that by the stepping to get the nearest + // valid step, multiply that by stepping to put it back at a level value. + // + volumeCtx->VolumeLevel[0] = (VOLUME_LEVEL_MAXIMUM + VOLUME_LEVEL_MINIMUM) / 2 / VOLUME_STEPPING * VOLUME_STEPPING; + volumeCtx->VolumeLevel[1] = (VOLUME_LEVEL_MAXIMUM + VOLUME_LEVEL_MINIMUM) / 2 / VOLUME_STEPPING * VOLUME_STEPPING; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtAcxPinRetrieveName( + _In_ ACXPIN Pin, + _Out_ PUNICODE_STRING Name +) +/*++ + +Routine Description: + + If g_UseCustomInfName is false then the ACX + pin callback EvtAcxPinRetrieveName calls this + function in order to retrieve the pin name. + +Return Value: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(Pin); + + PAGED_CODE(); + + return RtlUnicodeStringPrintf(Name, L"CustomName2"); +} + +VOID +CodecC_EvtPinContextCleanup( + _In_ WDFOBJECT WdfPin +) +/*++ + +Routine Description: + + In this callback, it cleans up pin context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + nullptr + +--*/ +{ + UNREFERENCED_PARAMETER(WdfPin); +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CircuitCleanup( + _In_ ACXCIRCUIT Circuit +) +{ + PCODEC_CAPTURE_CIRCUIT_CONTEXT circuitCtx; + + PAGED_CODE(); + + // + // Remove the static capture circuit. + // + circuitCtx = GetCaptureCircuitContext(Circuit); + ASSERT(circuitCtx != nullptr); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName +) +/*++ + +Routine Description: + + Creates the static capture circuit (pictured below) + and adds it to the device context. This is called + when a new device is detected and the AddDevice + call is made by the pnp manager. + + ****************************************************** + * Capture Circuit * + * * + * +-----------------------+ * + * | | * + * | +-------------+ | * + * Host ------>| | Volume Node | |---> Bridge * + * Pin | +-------------+ | Pin * + * | | * + * +-----------------------+ * + * * + ****************************************************** + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + PCAPTURE_DEVICE_CONTEXT captureDevCtx; + ACXCIRCUIT captureCircuit = nullptr; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Alloc audio context to current device. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CAPTURE_DEVICE_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(WdfObjectAllocateContext(Device, &attributes, (PVOID*)&captureDevCtx)); + ASSERT(captureDevCtx); + + // + // Create a capture circuit associated with this child device. + // + RETURN_NTSTATUS_IF_FAILED(CodecC_CreateCaptureCircuit(Device, ComponentGuid, MicCustomName, CircuitName, &captureCircuit)); + + devCtx->Capture = captureCircuit; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Capture_AllocateSupportedFormats( + _In_ WDFDEVICE Device, + _In_reads_bytes_(CodecCapturePinCount) ACXPIN Pin[], + _In_ ACXCIRCUIT Circuit, + _In_ size_t CodecCapturePinCount +) +{ + UNREFERENCED_PARAMETER(CodecCapturePinCount); + + NTSTATUS status = STATUS_SUCCESS; + ACXDATAFORMAT formatPcm44100c1; + ACXDATAFORMAT formatPcm48000c1; + ACXDATAFORMATLIST formatList; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + /////////////////////////////////////////////////////////// + // + // Allocate the formats this circuit supports. + // + + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm44100c1, Circuit, Device, &formatPcm44100c1)); + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm48000c1, Circuit, Device, &formatPcm48000c1)); + + /////////////////////////////////////////////////////////// + // + // Define supported formats for the host pin. + // + + // + // The raw processing mode list is associated with each single circuit + // by ACX. A driver uses this DDI to retrieve the built-in raw + // data-format list. + // + RETURN_NTSTATUS_IF_TRUE(CodecCaptureHostPin >= CodecCapturePinCount, STATUS_INVALID_PARAMETER); + formatList = AcxPinGetRawDataFormatList(Pin[CodecCaptureHostPin]); + RETURN_NTSTATUS_IF_TRUE(formatList == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + // + // The driver uses this DDI to add data formats to the raw + // processing mode list associated with the current circuit. + // + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c1)); + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm48000c1)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName, + _Out_ ACXCIRCUIT* Circuit +) +/*++ + +Routine Description: + + This routine builds the CODEC capture circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + ACXCIRCUIT circuit; + CODEC_CAPTURE_CIRCUIT_CONTEXT* circuitCtx; + ACXPIN pin[CodecCapturePinCount]; + + PAGED_CODE(); + + // + // Init output value. + // + *Circuit = nullptr; + + /////////////////////////////////////////////////////////// + // + // Create a circuit. + // + { + PACXCIRCUIT_INIT circuitInit = nullptr; + ACX_CIRCUIT_PNPPOWER_CALLBACKS powerCallbacks; + + // + // The driver uses this DDI to allocate an ACXCIRCUIT_INIT + // structure. This opaque structure is used when creating + // a standalone audio circuit representing an audio device. + // + circuitInit = AcxCircuitInitAllocate(Device); + + // + // A driver uses this DDI to free the allocated + // ACXCIRCUIT_INIT structure when an error is detected. + // Normally the structures is deleted/cleared by ACX when + // an ACX circuit is created successfully. + // + auto circuitInitScope = scope_exit([&circuitInit]() { + if (circuitInit) { + AcxCircuitInitFree(circuitInit); + } + }); + + // + // The driver uses this DDI to specify the Component ID + // of the ACX circuit. This ID is a guid that uniquely + // identifies the circuit instance (vendor specific). + // + AcxCircuitInitSetComponentId(circuitInit, ComponentGuid); + + // + // The driver uses this DDI to specify the circuit name. + // For standalone circuits, this is the audio device name + // which is used by clients to open handles to the audio devices. + // + (VOID)AcxCircuitInitAssignName(circuitInit, CircuitName); + + // + // The driver uses this DDI to specify the circuit type. The + // circuit type can be AcxCircuitTypeRender, AcxCircuitTypeCapture, + // AcxCircuitTypeOther, or AcxCircuitTypeMaximum (for validation). + // + AcxCircuitInitSetCircuitType(circuitInit, AcxCircuitTypeCapture); + + // + // The driver uses this DDI to assign its (if any) power callbacks. + // + ACX_CIRCUIT_PNPPOWER_CALLBACKS_INIT(&powerCallbacks); + powerCallbacks.EvtAcxCircuitPowerUp = CodecC_EvtCircuitPowerUp; + powerCallbacks.EvtAcxCircuitPowerDown = CodecC_EvtCircuitPowerDown; + AcxCircuitInitSetAcxCircuitPnpPowerCallbacks(circuitInit, &powerCallbacks); + + // + // The driver uses this DDI to register for a stream-create callback. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxCreateStreamCallback(circuitInit, CodecC_EvtCircuitCreateStream)); + + // + // The driver uses this DDI to create a new ACX circuit. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_CAPTURE_CIRCUIT_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitCreate(Device, &attributes, &circuitInit, &circuit)); + + circuitInitScope.release(); + + circuitCtx = GetCaptureCircuitContext(circuit); + ASSERT(circuitCtx); + } + + // + // Post circuit creation initialization. + // + + /////////////////////////////////////////////////////////// + // + // Create volume element. + // + { + ACXELEMENT elements[CaptureElementCount] = { 0 }; + + RETURN_NTSTATUS_IF_FAILED(CodecC_CreateVolumeElement(circuit, (ACXVOLUME*)&elements[CaptureVolumeIndex])); + + // + // Saving the volume element in the circuit context. + // + circuitCtx->VolumeElement = (ACXVOLUME)elements[CaptureVolumeIndex]; + + // + // The driver uses this DDI post circuit creation to add ACXELEMENTs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddElements(circuit, elements, SIZEOF_ARRAY(elements))); + } + + /////////////////////////////////////////////////////////// + // + // Create the pins for the circuit. + // + { + ACX_PIN_CALLBACKS pinCallbacks; + ACX_PIN_CONFIG pinCfg; + CODEC_PIN_CONTEXT* pinCtx; + + /////////////////////////////////////////////////////////// + // + // Create capture streaming pin. + // + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + pinCallbacks.EvtAcxPinSetDataFormat = CodecC_EvtAcxPinSetDataFormat; + + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSource; + pinCfg.Communication = AcxPinCommunicationSink; + pinCfg.Category = &KSCATEGORY_AUDIO; + pinCfg.PinCallbacks = &pinCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecC_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &(pin[CodecCaptureHostPin]))); + + ASSERT(pin[CodecCaptureHostPin] != nullptr); + pinCtx = GetCodecPinContext(pin[CodecCaptureHostPin]); + ASSERT(pinCtx); + pinCtx->CodecPinType = CodecPinTypeHost; + + /////////////////////////////////////////////////////////// + // + // Create capture endpoint pin. + // + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + ACX_PIN_CONFIG_INIT(&pinCfg); + + pinCfg.Type = AcxPinTypeSink; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSNODETYPE_MICROPHONE; + pinCfg.PinCallbacks = &pinCallbacks; + + // Specify how to read the custom name. + if (g_UseCustomInfName) + { + pinCfg.Name = MicCustomName; + } + else + { + pinCallbacks.EvtAcxPinRetrieveName = CodecC_EvtAcxPinRetrieveName; + } + g_UseCustomInfName = !g_UseCustomInfName; + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &(pin[CodecCaptureBridgePin]))); + + ASSERT(pin[CodecCaptureBridgePin] != nullptr); + } + + /////////////////////////////////////////////////////////// + // + // Add audio jack to bridge pin. + // For more information on audio jack see: https://docs.microsoft.com/en-us/windows/win32/api/devicetopology/ns-devicetopology-ksjack_description + // + { + ACX_JACK_CONFIG jackCfg; + ACXJACK jack; + PJACK_CONTEXT jackCtx; + + ACX_JACK_CONFIG_INIT(&jackCfg); + jackCfg.Description.ChannelMapping = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + jackCfg.Description.Color = RGB(0, 0, 0); + jackCfg.Description.ConnectionType = AcxConnTypeAtapiInternal; + jackCfg.Description.GeoLocation = AcxGeoLocFront; + jackCfg.Description.GenLocation = AcxGenLocPrimaryBox; + jackCfg.Description.PortConnection = AcxPortConnIntegratedDevice; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, JACK_CONTEXT); + attributes.ParentObject = pin[CodecCaptureBridgePin]; + + RETURN_NTSTATUS_IF_FAILED(AcxJackCreate(pin[CodecCaptureBridgePin], &attributes, &jackCfg, &jack)); + + ASSERT(jack != nullptr); + + jackCtx = GetJackContext(jack); + ASSERT(jackCtx); + jackCtx->Dummy = 0; + + RETURN_NTSTATUS_IF_FAILED(AcxPinAddJacks(pin[CodecCaptureBridgePin], &jack, 1)); + } + + RETURN_NTSTATUS_IF_FAILED(Capture_AllocateSupportedFormats(Device, pin, circuit, CodecCapturePinCount)); + + /////////////////////////////////////////////////////////// + // + // The driver uses this DDI post circuit creation to add ACXPINs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, pin, CodecCapturePinCount)); + + // + // Set output value. + // + *Circuit = circuit; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtCircuitPowerUp( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(PreviousState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +CodecC_EvtCircuitPowerDown( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(TargetState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtCircuitCreateStream( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ PACXSTREAM_INIT StreamInit, + _In_ ACXDATAFORMAT StreamFormat, + _In_ const GUID * SignalProcessingMode, + _In_ ACXOBJECTBAG VarArguments +) +/*++ + +Routine Description: + + This routine creates a stream for the specified circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PCAPTURE_DEVICE_CONTEXT devCtx; + WDF_OBJECT_ATTRIBUTES attributes; + ACXSTREAM stream; + STREAMENGINE_CONTEXT * streamCtx; + ACX_STREAM_CALLBACKS streamCallbacks; + ACX_RT_STREAM_CALLBACKS rtCallbacks; + CCaptureStreamEngine * streamEngine = nullptr; + CODEC_CAPTURE_CIRCUIT_CONTEXT * circuitCtx; + CODEC_PIN_CONTEXT * pinCtx; + + auto streamEngineScope = scope_exit([&streamEngine]() { + + if (streamEngine) + { + delete streamEngine; + } + + }); + + PAGED_CODE(); + UNREFERENCED_PARAMETER(SignalProcessingMode); + UNREFERENCED_PARAMETER(VarArguments); + + ASSERT(IsEqualGUID(*SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)); + + devCtx = GetCaptureDeviceContext(Device); + ASSERT(devCtx != nullptr); + + circuitCtx = GetCaptureCircuitContext(Circuit); + ASSERT(circuitCtx != nullptr); + + pinCtx = GetCodecPinContext(Pin); + ASSERT(pinCtx != nullptr); + + // + // Init streaming callbacks. + // + ACX_STREAM_CALLBACKS_INIT(&streamCallbacks); + streamCallbacks.EvtAcxStreamPrepareHardware = EvtStreamPrepareHardware; + streamCallbacks.EvtAcxStreamReleaseHardware = EvtStreamReleaseHardware; + streamCallbacks.EvtAcxStreamRun = EvtStreamRun; + streamCallbacks.EvtAcxStreamPause = EvtStreamPause; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxStreamCallbacks(StreamInit, &streamCallbacks)); + + // + // Init RT streaming callbacks. + // + ACX_RT_STREAM_CALLBACKS_INIT(&rtCallbacks); + rtCallbacks.EvtAcxStreamGetHwLatency = EvtStreamGetHwLatency; + rtCallbacks.EvtAcxStreamAllocateRtPackets = EvtStreamAllocateRtPackets; + rtCallbacks.EvtAcxStreamFreeRtPackets = EvtStreamFreeRtPackets; + rtCallbacks.EvtAcxStreamGetCapturePacket = CodecC_EvtStreamGetCapturePacket; + rtCallbacks.EvtAcxStreamGetCurrentPacket = EvtStreamGetCurrentPacket; + rtCallbacks.EvtAcxStreamGetPresentationPosition = EvtStreamGetPresentationPosition; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxRtStreamCallbacks(StreamInit, &rtCallbacks)); + + // + // Buffer notifications are supported. + // + AcxStreamInitSetAcxRtStreamSupportsNotifications(StreamInit); + + // + // Create the stream. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, STREAMENGINE_CONTEXT); + attributes.EvtDestroyCallback = EvtStreamDestroy; + RETURN_NTSTATUS_IF_FAILED(AcxRtStreamCreate(Device, Circuit, &attributes, &StreamInit, &stream)); + + streamCtx = GetStreamEngineContext(stream); + ASSERT(streamCtx); + + // + // Create the virtual streaming engine which will control + // streaming logic for the capture circuit. + // + streamEngine = new (POOL_FLAG_NON_PAGED, DeviceDriverTag) CCaptureStreamEngine(stream, StreamFormat); + RETURN_NTSTATUS_IF_TRUE(streamEngine == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + streamCtx->StreamEngine = (PVOID)streamEngine; + + streamEngine = nullptr; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecC_EvtStreamGetCapturePacket( + _In_ ACXSTREAM Stream, + _Out_ ULONG * LastCapturePacket, + _Out_ ULONGLONG * QPCPacketStart, + _Out_ BOOLEAN * MoreData +) +{ + PSTREAMENGINE_CONTEXT ctx; + CCaptureStreamEngine* streamEngine = nullptr; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = static_cast(ctx->StreamEngine); + + return streamEngine->GetCapturePacket(LastCapturePacket, QPCPacketStart, MoreData); +} + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.cpp new file mode 100644 index 000000000..157b6fa2d --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.cpp @@ -0,0 +1,620 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + CircuitHelper.cpp + +Abstract: + + This module contains helper functions for circuits. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include "CircuitHelper.h" + +#ifndef __INTELLISENSE__ +#include "CircuitHelper.tmh" +#endif + +const ULONG _DSP_STREAM_PROPERTY_UI4_VALUE = 1; + +PAGED_CODE_SEG +NTSTATUS AllocateFormat( + _In_ KSDATAFORMAT_WAVEFORMATEXTENSIBLE WaveFormat, + _In_ ACXCIRCUIT Circuit, + _In_ WDFDEVICE Device, + _Out_ ACXDATAFORMAT* Format +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + ACX_DATAFORMAT_CONFIG formatCfg; + ACX_DATAFORMAT_CONFIG_INIT_KS(&formatCfg, &WaveFormat); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, FORMAT_CONTEXT); + attributes.ParentObject = Circuit; + + // + // Creates an ACXDATAFORMAT handle for the given wave format. + // + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatCreate(Device, &attributes, &formatCfg, Format)); + + ASSERT((*Format) != NULL); + FORMAT_CONTEXT* formatCtx; + formatCtx = GetFormatContext(*Format); + ASSERT(formatCtx); + UNREFERENCED_PARAMETER(formatCtx); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS CreateStreamBridge( + _In_ ACX_STREAM_BRIDGE_CONFIG StreamCfg, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ DSP_PIN_CONTEXT* PinCtx, + _In_ BOOL Render) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + attributes.ParentObject = Pin; + + ACX_OBJECTBAG_CONFIG objBagCfg; + ACXOBJECTBAG objBag = NULL; + ACX_OBJECTBAG_CONFIG_INIT(&objBagCfg); + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = Circuit; + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagCreate(&attributes, &objBagCfg, &objBag)); + + DECLARE_CONST_ACXOBJECTBAG_DRIVER_PROPERTY_NAME(msft, TestUI4); + RETURN_NTSTATUS_IF_FAILED(AcxObjectBagAddUI4(objBag, &TestUI4, _DSP_STREAM_PROPERTY_UI4_VALUE)); + + // + // Add a stream BRIDGE. + // + PCGUID inModes[] = { + &AUDIO_SIGNALPROCESSINGMODE_RAW, + &AUDIO_SIGNALPROCESSINGMODE_DEFAULT, + }; + + if (Render) + { + StreamCfg.InModesCount = SIZEOF_ARRAY(inModes); + StreamCfg.InModes = inModes; + } + + // + // Do not specify InModes for capture - this will prevent the ACX framework from adding created streams to this stream + // bridge automatically. We want to add the stream bridges manually since we don't want KWS streams added. + // + StreamCfg.OutMode = &AUDIO_SIGNALPROCESSINGMODE_RAW; + StreamCfg.OutStreamVarArguments = objBag; + + // + // Uncomment this line to reverse the change-state sequence notifications. + // + // streamCfg.Flags |= AcxStreamBridgeInvertChangeStateSequence; + + ACXSTREAMBRIDGE streamBridge = NULL; + RETURN_NTSTATUS_IF_FAILED(AcxStreamBridgeCreate(Circuit, &attributes, &StreamCfg, &streamBridge)); + + if (!Render) + { + PinCtx->HostStreamBridge = streamBridge; + } + + RETURN_NTSTATUS_IF_FAILED(AcxPinAddStreamBridges(Pin, &streamBridge, 1)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS ConnectRenderCircuitElements( + _In_ ACXAUDIOENGINE AudioEngineElement, + _In_ ACXCIRCUIT Circuit +) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + + // + // Explicitly connect the circuit/elements. Note that driver doesn't + // need to perform this step when circuit/elements are connected in the + // same order as they were added to the circuit. By default ACX connects + // the elements starting from the sink circuit pin and ending with the + // source circuit pin for both render and capture devices. + // + // Circuit layout + // ----------------------------------------- + // | | + // | -------------------- | + // Host -0->|-----1->| |-0-------->|-3-> Bridge Pin + // | | Audio Engine | | + // Offload -1->|-----2->| Node |-3--| | + // | |------------------| | | + // | | | + // Loopback <-2-|<------------------------------ | | + // | | + // | | + // |---------------------------------------| + // + + ACX_CONNECTION connections[4]; + + ACX_CONNECTION_INIT(&connections[0], Circuit, AudioEngineElement); + connections[0].FromPin.Id = RenderHostPin; + connections[0].ToPin.Id = 1; + + ACX_CONNECTION_INIT(&connections[1], Circuit, AudioEngineElement); + connections[1].FromPin.Id = RenderOffloadPin; + connections[1].ToPin.Id = 2; + + ACX_CONNECTION_INIT(&connections[2], AudioEngineElement, Circuit); + connections[2].ToPin.Id = RenderLoopbackPin; + connections[2].FromPin.Id = 3; + + ACX_CONNECTION_INIT(&connections[3], AudioEngineElement, Circuit); + connections[3].ToPin.Id = RenderBridgePin; + connections[3].FromPin.Id = 0; + + // + // Add the connections linking circuit to elements. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddConnections(Circuit, connections, SIZEOF_ARRAY(connections))); + + return status; + +} + +PAGED_CODE_SEG +NTSTATUS +Codec_GetModeFromAttributeList( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _Out_ GUID * SignalProcessingMode + ) +{ + NTSTATUS status = STATUS_NO_MORE_ENTRIES; + PKSATTRIBUTE attributeHeader = NULL; + PAGED_CODE(); + *SignalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT; + + status = FindKsAttributeById(Attributes, + AttributesSize, + &KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE, + sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE), + &attributeHeader); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + ASSERT(attributeHeader->Attribute == KSATTRIBUTEID_AUDIOSIGNALPROCESSING_MODE); + ASSERT(attributeHeader->Size == sizeof(KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE)); + + KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE* signalProcessingModeAttribute; + signalProcessingModeAttribute = (KSATTRIBUTE_AUDIOSIGNALPROCESSING_MODE*)attributeHeader; + *SignalProcessingMode = signalProcessingModeAttribute->SignalProcessingMode; + status = STATUS_SUCCESS; +exit: + return status; +} + +struct AFX_FIND_KSATTRIBUTE_BY_ID +{ + const _GUID * Id; + ULONG Size; + PKSATTRIBUTE Attribute; +}; + +PAGED_CODE_SEG +NTSTATUS +FindKsAttributeByIdVisitor( + _In_ PKSATTRIBUTE AttributeHeader, + _In_ PVOID Context, + _Out_ BOOLEAN * bContinue + ) +{ + NTSTATUS status = STATUS_SUCCESS; + AFX_FIND_KSATTRIBUTE_BY_ID * ctx = (AFX_FIND_KSATTRIBUTE_BY_ID *)Context; + PAGED_CODE(); + // Default: continue searching. + *bContinue = TRUE; + + if (IsEqualGUIDAligned(AttributeHeader->Attribute, *ctx->Id)) + { + // Validate its size. + if (AttributeHeader->Size < ctx->Size) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + ctx->Attribute = AttributeHeader; + *bContinue = FALSE; + } +exit: + return status; +} + +PAGED_CODE_SEG +NTSTATUS +FindKsAttributeById( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _In_ const _GUID * AttributeId, + _In_ ULONG AttributeSize, + _Out_ PKSATTRIBUTE * AttributeHeader + ) +{ + PAGED_CODE(); + NTSTATUS status; + AFX_FIND_KSATTRIBUTE_BY_ID ctx = {0}; + *AttributeHeader = NULL; + ctx.Id = AttributeId; + ctx.Size = AttributeSize; + status = TraverseKsAttributeList(Attributes, AttributesSize, FindKsAttributeByIdVisitor, &ctx); + if (!NT_SUCCESS(status)) + { + goto exit; + } + if (ctx.Attribute == NULL) + { + status = STATUS_NO_MORE_ENTRIES; + goto exit; + } + *AttributeHeader = ctx.Attribute; +exit: + return status; +} + +PAGED_CODE_SEG +NTSTATUS +TraverseKsAttributeList( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _In_ PFN_KSATTRIBUTES_VISITOR Visitor, + _In_ PVOID Context + ) +{ + PAGED_CODE(); + NTSTATUS status = STATUS_SUCCESS; + ULONG cbRemaining = 0; + PKSATTRIBUTE attributeHeader = NULL; + ASSERT(Visitor); + // + // Note: multiple-item ptr must have a FILE_QUAD_ALIGNMENT only in relation to the Pin's format size. + // I.e., it is not guaranteed that the attributes are FILE_QUAD_ALIGNMENT in memory, unless the caller reallocates + // them before calling this function (which is currently not done by anyone in any driver/sample). + // + //ASSERT((ULONG_PTR)Attributes == (((ULONG_PTR)Attributes + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT)); + if (AttributesSize < sizeof(KSMULTIPLE_ITEM)) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + if (Attributes->Size < sizeof(KSMULTIPLE_ITEM)) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + if (AttributesSize < Attributes->Size) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + cbRemaining = Attributes->Size; + // + // Init ptr / size of attributes of list. + // + cbRemaining -= sizeof(KSMULTIPLE_ITEM); + attributeHeader = (PKSATTRIBUTE)(Attributes + 1); + for (ULONG i = 0; i < Attributes->Count; i++) + { + BOOLEAN bContinue = TRUE; + size_t cbAttribute = 0; + + if (cbRemaining < sizeof(KSATTRIBUTE)) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + if (attributeHeader->Size < sizeof(KSATTRIBUTE)) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + if (cbRemaining < attributeHeader->Size) + { + status = STATUS_INVALID_PARAMETER; + goto exit; + } + // + // Invoke the descriptor enumeration routine. + // + status = Visitor(attributeHeader, Context, &bContinue); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + if (!bContinue) + { + break; + } + // + // Adjust pointer and buffer size to next attribute (QWORD aligned) + // + cbAttribute = CODEC_ALIGN_SIZE_UP_CONSTANT(attributeHeader->Size, FILE_QUAD_ALIGNMENT); + if (cbRemaining < cbAttribute) + { + // + // Out of buffer, check if this was the last attribute. + // + if (i + 1 != Attributes->Count) + { + // + // This was not the last attribute, nevertheless there is no more buffer, error out. + // + status = STATUS_INVALID_PARAMETER; + goto exit; + } + // This was the final attribute. Exit loop with success status. + break; + } + // Check next attribute. + attributeHeader = (PKSATTRIBUTE)(((PBYTE)attributeHeader) + cbAttribute); + cbRemaining -= (ULONG)cbAttribute; + } + // Normalize success code. + status = STATUS_SUCCESS; +exit: + return status; +} + +PAGED_CODE_SEG +NTSTATUS +EvtJackRetrievePresence( + _In_ ACXJACK Jack, + _In_ PBOOLEAN IsConnected +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(Jack); + UNREFERENCED_PARAMETER(IsConnected); + + NTSTATUS status = STATUS_SUCCESS; + + // + // Because this is a sample we always return true (jack is present). A real driver should check + // if the device is actually present before returning true. + // + *IsConnected = true; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CreateAudioJack( + _In_ ULONG ChannelMapping, + _In_ ULONG Color, + _In_ ACX_JACK_CONNECTION_TYPE ConnectionType, + _In_ ACX_JACK_GEO_LOCATION GeoLocation, + _In_ ACX_JACK_GEN_LOCATION GenLocation, + _In_ ACX_JACK_PORT_CONNECTION PortConnection, + _In_ ULONG Flags, + _In_ ACXPIN BridgePin + ) +{ + PAGED_CODE(); + + NTSTATUS status = STATUS_SUCCESS; + ACX_JACK_CONFIG jackCfg; + ACXJACK jack; + PJACK_CONTEXT jackCtx; + ACX_JACK_CALLBACKS jackCallbacks; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + ACX_JACK_CONFIG_INIT(&jackCfg); + jackCfg.Description.ChannelMapping = ChannelMapping; + jackCfg.Description.Color = Color; + jackCfg.Description.ConnectionType = ConnectionType; + jackCfg.Description.GeoLocation = GeoLocation; + jackCfg.Description.GenLocation = GenLocation; + jackCfg.Description.PortConnection = PortConnection; + jackCfg.Flags = Flags; + + ACX_JACK_CALLBACKS_INIT(&jackCallbacks); + jackCallbacks.EvtAcxJackRetrievePresenceState = EvtJackRetrievePresence; + jackCfg.Callbacks = &jackCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, JACK_CONTEXT); + attributes.ParentObject = BridgePin; + + status = AcxJackCreate(BridgePin, &attributes, &jackCfg, &jack); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + ASSERT(jack != nullptr); + + jackCtx = GetJackContext(jack); + ASSERT(jackCtx); + jackCtx->Dummy = 0; + + status = AcxPinAddJacks(BridgePin, &jack, 1); + +exit: + return status; +} + +PAGED_CODE_SEG +VOID +CpuResourcesCallbackHelper +( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request, + _In_ ACXELEMENT Element +) +{ + NTSTATUS ntStatus = STATUS_NOT_SUPPORTED; + ULONG_PTR outDataCb = 0; + ACX_REQUEST_PARAMETERS params; + ULONG minSize = sizeof(ULONG); + + PAGED_CODE(); + + ACX_REQUEST_PARAMETERS_INIT(¶ms); + AcxRequestGetParameters(Request, ¶ms); + + if ((params.Type != AcxRequestTypeProperty) || + (params.Parameters.Property.ItemType != AcxItemTypeElement)) + { + // Return to acx + (VOID) AcxCircuitDispatchAcxRequest((ACXCIRCUIT)Object, Request); + Request = NULL; + goto exit; + } + + if (Element == NULL) + { + ntStatus = STATUS_NOT_SUPPORTED; + goto exit; + } + + ULONG elementId = params.Parameters.Property.ItemId; + ULONG currentElementId = AcxElementGetId(Element); + ULONG valueCb = params.Parameters.Property.ValueCb; + + if (valueCb != 0) + { + if (params.Parameters.Property.Value == NULL) + { + ntStatus = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + } + + // + // Check to see if the current node is the peakmeter node, if not then return the call to ACX + // + if (elementId != currentElementId) + { + (VOID) AcxCircuitDispatchAcxRequest((ACXCIRCUIT)Object, Request); + Request = NULL; + goto exit; + } + + if (params.Parameters.Property.Verb == AcxPropertyVerbGet) + { + + if (valueCb == 0) + { + outDataCb = minSize; + ntStatus = STATUS_BUFFER_OVERFLOW; + goto exit; + } + else if (valueCb < minSize) + { + outDataCb = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + goto exit; + } + else + { + *((PULONG)params.Parameters.Property.Value) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU; + params.Parameters.Property.ValueCb = sizeof(ULONG); + outDataCb = params.Parameters.Property.ValueCb; + ntStatus = STATUS_SUCCESS; + } + } + else if (params.Parameters.Property.Verb == AcxPropertyVerbBasicSupport) + { + if ((valueCb != sizeof(ULONG)) && (valueCb != sizeof(KSPROPERTY_DESCRIPTION))) + { + outDataCb = minSize; + ntStatus = STATUS_BUFFER_OVERFLOW; + goto exit; + } + + if (valueCb >= sizeof(KSPROPERTY_DESCRIPTION)) + { + // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it + // + PKSPROPERTY_DESCRIPTION PropDesc = (PKSPROPERTY_DESCRIPTION)params.Parameters.Property.Value; + + PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET; + PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION); + PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General; + PropDesc->PropTypeSet.Id = VT_UI4; + PropDesc->PropTypeSet.Flags = 0; + PropDesc->MembersListCount = 0; + PropDesc->Reserved = 0; + outDataCb = sizeof(KSPROPERTY_DESCRIPTION); + ntStatus = STATUS_SUCCESS; + } + else if (valueCb >= sizeof(ULONG)) + { + // if return buffer can hold a ULONG, return the access flags + // + *((PULONG)params.Parameters.Property.Value) = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET; + outDataCb = minSize; + ntStatus = STATUS_SUCCESS; + } + else if (valueCb > 0) + { + outDataCb = 0; + ntStatus = STATUS_BUFFER_TOO_SMALL; + } + else + { + outDataCb = minSize; + ntStatus = STATUS_BUFFER_OVERFLOW; + } + } + else + { + // + // Just give it back to ACX. After this call the request is gone. + // + (VOID) AcxCircuitDispatchAcxRequest((ACXCIRCUIT)Object, Request); + Request = NULL; + goto exit; + } + +exit: + if (Request != NULL) + { + WdfRequestCompleteWithInformation(Request, ntStatus, outDataCb); + } +} // EvtAudioCpuResourcesCallback diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.h b/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.h new file mode 100644 index 000000000..11863210d --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/CircuitHelper.h @@ -0,0 +1,135 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + CircuitHelper.h + +Abstract: + + This module contains helper functions for endpoints. + +Environment: + + Kernel mode + +--*/ + +// size_t +// __inline +// CODEC_ALIGN_SIZE_DOWN_CONSTANT( +// IN size_t Length, +// IN size_t AlignTo +// ) +#define CODEC_ALIGN_SIZE_DOWN_CONSTANT(Length, AlignTo) ((Length) & ~((AlignTo)-1)) + +#define CODEC_ALIGN_SIZE_DOWN CODEC_ALIGN_SIZE_DOWN_CONSTANT + +// size_t +// __inline +// CODEC_ALIGN_SIZE_UP_CONSTANT( +// IN size_t Length, +// IN size_t AlignTo +// ) +#define CODEC_ALIGN_SIZE_UP_CONSTANT(Length, AlignTo) CODEC_ALIGN_SIZE_DOWN_CONSTANT((Length) + (AlignTo)-1, (AlignTo)) + +#define CODEC_ALIGN_SIZE_UP CODEC_ALIGN_SIZE_UP_CONSTANT + +PAGED_CODE_SEG +NTSTATUS +Codec_GetModeFromAttributeList( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _Out_ GUID * SignalProcessingMode + ); + +// +// Enumeration visitor callback. +// +typedef +NTSTATUS +(EVT_KSATTRIBUTES_VISITOR)( + _In_ PKSATTRIBUTE AttributeHeader, + _In_ PVOID Context, + _Out_ BOOLEAN * bContinue + ); + +typedef EVT_KSATTRIBUTES_VISITOR *PFN_KSATTRIBUTES_VISITOR; + +static +PAGED_CODE_SEG +EVT_KSATTRIBUTES_VISITOR FindKsAttributeByIdVisitor; + +PAGED_CODE_SEG +NTSTATUS +FindKsAttributeById( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _In_ const _GUID * AttributeId, + _In_ ULONG AttributeSize, + _Out_ PKSATTRIBUTE * AttributeHeader + ); + +PAGED_CODE_SEG +NTSTATUS +TraverseKsAttributeList( + _In_ const PKSMULTIPLE_ITEM Attributes, + _In_ ULONG AttributesSize, + _In_ PFN_KSATTRIBUTES_VISITOR Visitor, + _In_ PVOID Context + ); + +PAGED_CODE_SEG +NTSTATUS AllocateFormat( + _In_ KSDATAFORMAT_WAVEFORMATEXTENSIBLE WaveFormat, + _In_ ACXCIRCUIT Circuit, + _In_ WDFDEVICE Device, + _Out_ ACXDATAFORMAT* Format +); + +PAGED_CODE_SEG +NTSTATUS CreateStreamBridge( + _In_ ACX_STREAM_BRIDGE_CONFIG StreamCfg, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ DSP_PIN_CONTEXT* PinCtx, + _In_ BOOL Render +); + +PAGED_CODE_SEG +NTSTATUS ConnectRenderCircuitElements( + _In_ ACXAUDIOENGINE AudioEngineElement, + _In_ ACXCIRCUIT Circuit +); + +PAGED_CODE_SEG +NTSTATUS CreateAudioJack( + _In_ ULONG ChannelMapping, + _In_ ULONG Color, + _In_ ACX_JACK_CONNECTION_TYPE ConnectionType, + _In_ ACX_JACK_GEO_LOCATION GeoLocation, + _In_ ACX_JACK_GEN_LOCATION GenLocation, + _In_ ACX_JACK_PORT_CONNECTION PortConnection, + _In_ ULONG Flags, + _In_ ACXPIN BridgePin +); + +PAGED_CODE_SEG +NTSTATUS EvtJackRetrievePresence( + _In_ ACXJACK Jack, + _In_ PBOOLEAN IsConnected +); + +PAGED_CODE_SEG +VOID CpuResourcesCallbackHelper( + _In_ WDFOBJECT Object, + _In_ WDFREQUEST Request, + _In_ ACXELEMENT Element +); + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.cpp new file mode 100644 index 000000000..5ca38f9eb --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.cpp @@ -0,0 +1,484 @@ +/*++ + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + KeywordDetector.cpp + +Abstract: + + Sample keyword detector management. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include +#include +#include +#include "streamengine.h" +#include "KeywordDetector.h" + +PAGED_CODE_SEG +CKeywordDetector::CKeywordDetector() + : + m_streamRunning(FALSE), + m_qpcStartCapture(0), + m_nLastQueuedPacket(-1), + m_SoundDetectorArmed1(FALSE), + m_SoundDetectorArmed2(FALSE), + m_SoundDetectorData1(0), + m_SoundDetectorData2(0), + m_ullKeywordStartTimestamp(0), + m_ullKeywordStopTimestamp(0) +{ + PAGED_CODE(); + + // Initialize our pool of packets and the list structures + KeInitializeSpinLock(&PacketPoolSpinLock); + KeInitializeSpinLock(&PacketFifoSpinLock); + ResetFifo(); +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::ReadKeywordTimestampRegistry() +{ + PAGED_CODE(); + + NTSTATUS ntStatus; + PDRIVER_OBJECT DriverObject; + HANDLE DriverKey; + + RTL_QUERY_REGISTRY_TABLE paramTable[] = { + // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength + { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"KeywordDetectorStartTimestamp", &m_ullKeywordStartTimestamp, (REG_QWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_QWORD, &m_ullKeywordStartTimestamp, sizeof(ULONGLONG) }, + { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"KeywordDetectorStopTimestamp", &m_ullKeywordStopTimestamp, (REG_QWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_QWORD, &m_ullKeywordStopTimestamp, sizeof(ULONGLONG) }, + { NULL, 0, NULL, NULL, 0, NULL, 0 } + }; + + DriverObject = WdfDriverWdmGetDriverObject(WdfGetDriver()); + DriverKey = NULL; + ntStatus = IoOpenDriverRegistryKey(DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &DriverKey); + + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, + (PCWSTR) DriverKey, + ¶mTable[0], + NULL, + NULL); + if (DriverKey) + { + ZwClose(DriverKey); + } + + return ntStatus; +} + + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::ResetDetector(_In_ GUID eventId) +{ + PAGED_CODE(); + + if (eventId == CONTOSO_KEYWORD1) + { + m_SoundDetectorData1 = 0; + m_SoundDetectorArmed1 = FALSE; + } + else if(eventId == CONTOSO_KEYWORD2) + { + m_SoundDetectorData2 = 0; + m_SoundDetectorArmed2 = FALSE; + } + else if(eventId == GUID_NULL) + { + // When DownloadDetectorData is called to set the pattern for multiple keywords + // at once, all keyword detectors must be reset. Also used during keyword detector + // initialization and cleanup to restore it back to initial state and power down. + m_SoundDetectorData1 = 0; + m_SoundDetectorArmed1 = FALSE; + m_SoundDetectorData2 = 0; + m_SoundDetectorArmed2 = FALSE; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::DownloadDetectorData(_In_ GUID eventId, _In_ LONGLONG Data) +{ + PAGED_CODE(); + + // reset the detector for this event Id + ResetDetector(eventId); + + // In this example, the driver supports detection data + // set with a single call for both detectors, or each + // detector set individually. + if (eventId == CONTOSO_KEYWORD1) + { + m_SoundDetectorData1 = Data; + } + else if(eventId == CONTOSO_KEYWORD2) + { + m_SoundDetectorData2 = Data; + } + else if(eventId == GUID_NULL) + { + // in this simplified example "Data" is set on both detectors, + // however in a real system "Data" could be a data structure which + // contains different values for each detector. + m_SoundDetectorData1 = m_SoundDetectorData2 = Data; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + return STATUS_SUCCESS; +} + +// The following function is only applicable to single keyword detection systems, +// and assumes keyword detector #1. +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::GetDetectorData(_In_ GUID eventId, _Out_ LONGLONG *Data) +{ + PAGED_CODE(); + + if (eventId == CONTOSO_KEYWORD1) + { + *Data = m_SoundDetectorData1; + } + else if(eventId == CONTOSO_KEYWORD2) + { + *Data = m_SoundDetectorData2; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONGLONG CKeywordDetector::GetStartTimestamp() +{ + PAGED_CODE(); + + return m_ullKeywordStartTimestamp; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +ULONGLONG CKeywordDetector::GetStopTimestamp() +{ + PAGED_CODE(); + + return m_ullKeywordStopTimestamp; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CKeywordDetector::ResetFifo() +{ + PAGED_CODE(); + + m_qpcStartCapture = 0; + m_nLastQueuedPacket = (-1); + InitializeListHead(&PacketPoolHead); + InitializeListHead(&PacketFifoHead); + + for (int i = 0; i < ARRAYSIZE(PacketPool); i++) + { + InsertTailList(&PacketPoolHead, &PacketPool[i].ListEntry); + } + return; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::SetArmed(_In_ GUID eventId, _In_ BOOLEAN Arm) +{ + PAGED_CODE(); + + BOOL previousArming = FALSE; + NTSTATUS ntStatus = STATUS_SUCCESS; + + // the previous state is "armed" if either detector is armed. + // this reflects the fact that both detectors are sharing the + // same stream. + previousArming = m_SoundDetectorArmed1 || m_SoundDetectorArmed2; + + if (eventId == CONTOSO_KEYWORD1) + { + m_SoundDetectorArmed1 = Arm; + } + else if(eventId == CONTOSO_KEYWORD2) + { + m_SoundDetectorArmed2 = Arm; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + if (Arm && !previousArming && m_qpcStartCapture == 0) + { + StartBufferingStream(); + } + else if (!Arm && previousArming && !m_streamRunning) + { + // if it's not actively streaming and everything has been disarmed, + // then stop buffering. + ResetFifo(); + } + + return ntStatus; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::GetArmed(_In_ GUID eventId, _Out_ BOOLEAN *Arm) +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (eventId == CONTOSO_KEYWORD1) + { + *Arm = m_SoundDetectorArmed1; + } + else if(eventId == CONTOSO_KEYWORD2) + { + *Arm = m_SoundDetectorArmed2; + } + else + { + return STATUS_INVALID_PARAMETER; + } + + return ntStatus; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CKeywordDetector::Run() +{ + PAGED_CODE(); + + if (m_qpcStartCapture == 0) + { + StartBufferingStream(); + } + + m_streamRunning = TRUE; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CKeywordDetector::Stop() +{ + PAGED_CODE(); + + ResetFifo(); + m_streamRunning = FALSE; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CKeywordDetector::StartBufferingStream() +{ + LARGE_INTEGER qpc; + LARGE_INTEGER qpcFrequency; + + PAGED_CODE(); + + qpc = KeQueryPerformanceCounter(&qpcFrequency); + m_qpcStartCapture = qpc.QuadPart; + m_qpcFrequency = qpcFrequency.QuadPart; + + return; +} + +PAGED_CODE_SEG +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID CKeywordDetector::NotifyDetection() +{ + PAGED_CODE(); + + // A detection will only happen if armed and the + // stream is already running. If there isn't a client + // running, then set the stream start time to align + // with this detection. + if (!m_streamRunning) + { + StartBufferingStream(); + + // The following code is for testing purposes only. + // m_qpcFrequency is defined to be the number of ticks in 1 second. + // Use the stream start time (the current time retrieved in StartBufferStream) to + // mark when the keyword ended, and the start time minus 1 second worth of ticks + // to mark when the keyword started. Also, adjust the stream start time to align + // to this new keyword start time, so that the simulated stream contains the full keyword. + + m_ullKeywordStopTimestamp = m_qpcStartCapture; // stop time is the current time + m_qpcStartCapture = m_qpcStartCapture - m_qpcFrequency; // buffer start time is 1 second ago + m_ullKeywordStartTimestamp = m_qpcStartCapture; // buffer start time = keyword start time + + } + else + { + // The following code is for testing purposes only. + // If the stream is running, we cannot modify qpcStartCapture to be in + // the past, so instead make the keyword start & stop times fit within the + // time period that the keyword has been running. If it has been running + // for more than 1 second, then set the keyword start time to be 1 second back + // into the stream, as though we just figured out there was a keyword there. + // If it has been running less than one second, then the keyword size ends + // up being however long the stream has been running. + + LARGE_INTEGER qpc; + qpc = KeQueryPerformanceCounter(NULL); + + m_ullKeywordStopTimestamp = qpc.QuadPart; // stop time is the current time + + if (m_qpcStartCapture < (qpc.QuadPart - m_qpcFrequency)) + { + m_ullKeywordStartTimestamp = (qpc.QuadPart - m_qpcFrequency); + } + else + { + m_ullKeywordStartTimestamp = m_qpcStartCapture; + } + + } + + return; +} + +_IRQL_requires_min_(DISPATCH_LEVEL) +VOID CKeywordDetector::DpcRoutine(_In_ LONGLONG PerformanceCounter, _In_ LONGLONG PerformanceFrequency) +{ + LONGLONG currentPacket; + LONGLONG packetsToQueue; + + // TODO: the timer only runs when the stream is open, but really for KWS it should be building up a collection of burst data + // in the queue from 1.5 sec before the trigger happens. Is there some way to simulate that behavior here? Without doing that, + // there isn't really a burst that happens, just a trickle because while the timestamps will be right, the queue won't contain + // anything until the timer fires at the normal rate. + + if (m_qpcStartCapture <= 0) + { + return; + } + + currentPacket = (PerformanceCounter - m_qpcStartCapture) * (SamplesPerSecond / SamplesPerPacket) / PerformanceFrequency; + packetsToQueue = currentPacket - m_nLastQueuedPacket; + + while (packetsToQueue > 0) + { + LIST_ENTRY* packetListEntry; + PACKET_ENTRY* packetEntry; + + do + { + packetListEntry = ExInterlockedRemoveHeadList(&PacketPoolHead, &PacketPoolSpinLock); + if (packetListEntry != NULL) break; + + // Pool is empty, no room to buffer more, an overrun is occurring. Drop and reuse the + // oldest packet from head of fifo. + + // Since the pool is empty, the fifo should be full. However, although unlikely, the + // driver might empty the fifo before this routine removes a packet. In that case, the + // pool should have packets available again. Therefore this is a retry loop. + packetListEntry = ExInterlockedRemoveHeadList(&PacketFifoHead, &PacketFifoSpinLock); + if (packetListEntry != NULL) break; + } while (TRUE); + + packetEntry = CONTAINING_RECORD(packetListEntry, PACKET_ENTRY, ListEntry); + + packetEntry->PacketNumber = ++m_nLastQueuedPacket; + packetEntry->QpcWhenSampled = m_qpcStartCapture + (packetEntry->PacketNumber * PerformanceFrequency * SamplesPerPacket / SamplesPerSecond); + + // TODO: this should really put something real in the buffer. Use the sine tone generator maybe? + RtlZeroMemory(&packetEntry->Samples[0], sizeof(packetEntry->Samples)); + + ExInterlockedInsertTailList(&PacketFifoHead, packetListEntry, &PacketFifoSpinLock); + + packetsToQueue -= 1; + } +} + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS CKeywordDetector::GetReadPacket +( + _In_ ULONG PacketCount, + _In_ ULONG PacketSize, + _Out_writes_(PacketSize) PVOID *Packets, + _Out_ ULONG *PacketNumber, + _Out_ ULONG64 *PerformanceCounterValue, + _Out_ BOOLEAN *MoreData +) +{ + NTSTATUS ntStatus; + BYTE *packetData; + PACKET_ENTRY *packetEntry; + LIST_ENTRY *packetListEntry = NULL; + + packetListEntry = ExInterlockedRemoveHeadList(&PacketFifoHead, &PacketFifoSpinLock); + if (packetListEntry == NULL) + { + ntStatus = STATUS_DEVICE_NOT_READY; + goto Exit; + } + packetEntry = CONTAINING_RECORD(packetListEntry, PACKET_ENTRY, ListEntry); + + ntStatus = RtlLongLongToULong(packetEntry->PacketNumber, PacketNumber); + if (!NT_SUCCESS(ntStatus)) + { + goto Exit; + } + + packetData = (PBYTE) Packets[(*PacketNumber) % PacketCount]; + + *PerformanceCounterValue = packetEntry->QpcWhenSampled; + *MoreData = !IsListEmpty(&PacketFifoHead); + + // TODO: the packet size here needs to line up to the packet size allocated. + // Also, handle the first packet offset + RtlCopyMemory(packetData, packetEntry->Samples, min(sizeof(packetEntry->Samples), PacketSize)); + +Exit: + if (packetListEntry != NULL) + { + ExInterlockedInsertTailList(&PacketPoolHead, packetListEntry, &PacketPoolSpinLock); + } + + return ntStatus; +} diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.h b/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.h new file mode 100644 index 000000000..2d5b1311e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/KeywordDetector.h @@ -0,0 +1,145 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + KeywordDetector.h + +Abstract: + + Sample Keyword Detector. + + +--*/ + +#pragma once + +typedef struct +{ + SOUNDDETECTOR_PATTERNHEADER Header; + LONGLONG ContosoDetectorConfigurationData; +} CONTOSO_KEYWORDCONFIGURATION; + +typedef struct +{ + SOUNDDETECTOR_PATTERNHEADER Header; + LONGLONG ContosoDetectorResultData; + ULONGLONG KeywordStartTimestamp; + ULONGLONG KeywordStopTimestamp; + GUID EventId; +} CONTOSO_KEYWORDDETECTIONRESULT; + +DEFINE_GUID(CONTOSO_KEYWORDCONFIGURATION_IDENTIFIER2, +0x207f3d0c, 0x5c79, 0x496f, 0xa9, 0x4c, 0xd3, 0xd2, 0x93, 0x4d, 0xbf, 0xa9); + +// {A537F559-2D67-463B-B10E-BEB750A21F31} +DEFINE_GUID(CONTOSO_KEYWORD1, +0xa537f559, 0x2d67, 0x463b, 0xb1, 0xe, 0xbe, 0xb7, 0x50, 0xa2, 0x1f, 0x31); +// {655E417A-80A5-4A77-B3F1-512EAF67ABCF} +DEFINE_GUID(CONTOSO_KEYWORD2, +0x655e417a, 0x80a5, 0x4a77, 0xb3, 0xf1, 0x51, 0x2e, 0xaf, 0x67, 0xab, 0xcf); + +#define KEYWORDDETECTOR_POOLTAG 'KWS0' + +class CKeywordDetector +{ +public: + PAGED_CODE_SEG + CKeywordDetector(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS ResetDetector(_In_ GUID eventId); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS DownloadDetectorData(_In_ GUID eventId, _In_ LONGLONG Data); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS GetDetectorData(_In_ GUID eventId, _Out_ LONGLONG *Data); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + ULONGLONG GetStartTimestamp(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + ULONGLONG GetStopTimestamp(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS SetArmed(_In_ GUID eventId, _In_ BOOLEAN Arm); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID NotifyDetection(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS GetArmed(_In_ GUID eventId, _Out_ BOOLEAN *Arm); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID Run(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID Stop(); + + _IRQL_requires_min_(DISPATCH_LEVEL) + VOID DpcRoutine(_In_ LONGLONG PerformanceCounter, _In_ LONGLONG PerformanceFrequency); + + _IRQL_requires_max_(PASSIVE_LEVEL) + NTSTATUS GetReadPacket(_In_ ULONG PacketCount, _In_ ULONG PacketSize, _Out_writes_(PacketSize) PVOID *Packets, _Out_ ULONG *PacketNumber, _Out_ ULONGLONG *PerformanceCount, _Out_ BOOLEAN *MoreData); + +private: + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID ResetFifo(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS ReadKeywordTimestampRegistry(); + + _IRQL_requires_max_(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID StartBufferingStream(); + + // The Contoso keyword detector processes 10ms packets of 16KHz 16-bit PCM + // audio samples + static const int SamplesPerSecond = 16000; + static const int SamplesPerPacket = (10 * SamplesPerSecond / 1000); + + typedef struct + { + LIST_ENTRY ListEntry; + LONGLONG PacketNumber; + LONGLONG QpcWhenSampled; + UINT16 Samples[SamplesPerPacket]; + } PACKET_ENTRY; + + BOOLEAN m_streamRunning; + + BOOLEAN m_SoundDetectorArmed1; + BOOLEAN m_SoundDetectorArmed2; + LONGLONG m_SoundDetectorData1; + LONGLONG m_SoundDetectorData2; + + LONGLONG m_qpcStartCapture; + LONGLONG m_qpcFrequency; + LONGLONG m_nLastQueuedPacket; + + ULONGLONG m_ullKeywordStartTimestamp; + ULONGLONG m_ullKeywordStopTimestamp; + + KSPIN_LOCK PacketPoolSpinLock; + LIST_ENTRY PacketPoolHead; + PACKET_ENTRY PacketPool[1 * SamplesPerSecond / SamplesPerPacket]; // Enough storage for 1 second of audio data + + KSPIN_LOCK PacketFifoSpinLock; + LIST_ENTRY PacketFifoHead; + +}; + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.cpp new file mode 100644 index 000000000..a2bee67dd --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.cpp @@ -0,0 +1,91 @@ +/*++ + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. +Module Name: + newdelete.cpp +Abstract: + Contains overloaded placement new and delete operators +Environment: + Kernel mode +--*/ + +#include "private.h" +#include "NewDelete.h" + +/***************************************************************************** + * ::new(POOL_FLAGS) + ***************************************************************************** + * New function for creating objects with a specified pool flags. + */ +PVOID operator new( + _In_ size_t size, + _In_ POOL_FLAGS poolFlags +) +{ + PVOID result = ExAllocatePool2(poolFlags, size, 'wNwS'); + + return result; +} + +/***************************************************************************** + * ::new(POOL_FLAGS, TAG) + ***************************************************************************** + * New function for creating objects with specified pool flags and allocation tag. + */ +PVOID operator new( + _In_ size_t size, + _In_ POOL_FLAGS poolFlags, + _In_ ULONG tag +) +{ + PVOID result = ExAllocatePool2(poolFlags, size, tag); + + return result; +} + +void __cdecl operator delete(PVOID buffer) +{ + if (buffer) + { + ExFreePool(buffer); + } +} + +void __cdecl operator delete(PVOID buffer, ULONG tag) +{ + if (buffer) + { + ExFreePoolWithTag(buffer, tag); + } +} + +void __cdecl operator delete(_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer, _In_ size_t cbSize) +{ + UNREFERENCED_PARAMETER(cbSize); + + if (buffer) + { + ExFreePool(buffer); + } +} + +void __cdecl operator delete[](_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer) +{ + if (buffer) + { + ExFreePool(buffer); + } +} + +void __cdecl operator delete[](_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer, _In_ size_t cbSize) +{ + UNREFERENCED_PARAMETER(cbSize); + + if (buffer) + { + ExFreePool(buffer); + } +} + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.h b/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.h new file mode 100644 index 000000000..aee6d8bdd --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/NewDelete.h @@ -0,0 +1,58 @@ +/*++ +Copyright (c) Microsoft Corporation. All rights reserved. + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. +Module Name: + NewDelete.h +Abstract: + Contains overloaded placement new and delete operators +Environment: + Kernel mode +--*/ + +/***************************************************************************** + * ::new(POOL_FLAGS) + ***************************************************************************** + * New function for creating objects with a specified pool flags. + */ +PVOID operator new( + _In_ size_t size, + _In_ POOL_FLAGS poolFlags +); + +/***************************************************************************** + * ::new(POOL_FLAGS, TAG) + ***************************************************************************** + * New function for creating objects with specified pool flags and allocation tag. + */ +PVOID operator new( + _In_ size_t size, + _In_ POOL_FLAGS poolFlags, + _In_ ULONG tag +); + +/***************************************************************************** + * ::delete() + ***************************************************************************** + * Delete function. + */ +void __cdecl operator delete(PVOID buffer); + +/***************************************************************************** + * ::delete() + ***************************************************************************** + * Delete function. + */ +void __cdecl operator delete(PVOID buffer, ULONG tag); + +void __cdecl operator delete[](PVOID pVoid, _In_ size_t cbSize); + +void __cdecl operator delete(_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer, _In_ size_t cbSize); + +void __cdecl operator delete[](_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer); + +void __cdecl operator delete[](_Pre_maybenull_ __drv_freesMem(Mem) PVOID buffer, _In_ size_t cbSize); + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/Private.h b/crossplatform/windows-driver/LibrePodsMic/Common/Private.h new file mode 100644 index 000000000..677cc3a10 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/Private.h @@ -0,0 +1,922 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Private.h + +Abstract: + + Contains structure definitions and function prototypes private to + the Common library. + +Environment: + + Kernel mode + +--*/ + +#ifndef _PRIVATE_H_ +#define _PRIVATE_H_ + + +#include +#include +#include "cpp_utils.h" +#include +#include +#include +#include "NewDelete.h" + +/* make prototypes usable from C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include "Trace.h" + +#include +#include + +#define PAGED_CODE_SEG __declspec(code_seg("PAGE")) +#define INIT_CODE_SEG __declspec(code_seg("INIT")) + +extern const GUID DSP_CIRCUIT_SPEAKER_GUID; +extern const GUID DSP_CIRCUIT_MICROPHONE_GUID; +extern const GUID DSP_CIRCUIT_UNIVERSALJACK_RENDER_GUID; +extern const GUID DSP_CIRCUIT_UNIVERSALJACK_CAPTURE_GUID; + +///////////////////////////////////////////////////////// +// +// Driver wide definitions +// + +// Copied from cfgmgr32.h +#if !defined(MAX_DEVICE_ID_LEN) +#define MAX_DEVICE_ID_LEN 200 +#endif + +// Number of millisecs per sec. +#define MS_PER_SEC 1000 + +// Number of hundred nanosecs per sec. +#define HNS_PER_SEC 10000000 + +#define REQUEST_TIMEOUT_SECONDS 5 + +#undef MIN +#undef MAX +#define MIN(a,b) ((a) > (b) ? (b) : (a)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#ifndef BOOL +typedef int BOOL; +#endif + +#ifndef SIZEOF_ARRAY +#define SIZEOF_ARRAY(ar) (sizeof(ar)/sizeof((ar)[0])) +#endif // !defined(SIZEOF_ARRAY) + +#ifndef RGB +#define RGB(r, g, b) (DWORD)(r << 16 | g << 8 | b) +#endif + +#define ALL_CHANNELS_ID UINT32_MAX +#define MAX_CHANNELS 2 + +// +// Ks support. +// +#define KSPROPERTY_TYPE_ALL KSPROPERTY_TYPE_BASICSUPPORT | \ + KSPROPERTY_TYPE_GET | \ + KSPROPERTY_TYPE_SET + +// +// Define struct to hold signal processing mode and corresponding +// list of supported formats. +// +typedef struct +{ + GUID SignalProcessingMode; + KSDATAFORMAT_WAVEFORMATEXTENSIBLE* FormatList; + ULONG FormatListCount; +} SUPPORTED_FORMATS_LIST; + +// +// Define CAPTURE device context. +// +typedef struct _CAPTURE_DEVICE_CONTEXT { + ACXCIRCUIT Circuit; + BOOLEAN FirstTimePrepareHardware; +} CAPTURE_DEVICE_CONTEXT, * PCAPTURE_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CAPTURE_DEVICE_CONTEXT, GetCaptureDeviceContext) + +// +// Define RENDER device context. +// +typedef struct _RENDER_DEVICE_CONTEXT { + ACXCIRCUIT Circuit; + BOOLEAN FirstTimePrepareHardware; +} RENDER_DEVICE_CONTEXT, * PRENDER_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RENDER_DEVICE_CONTEXT, GetRenderDeviceContext) + +// +// Define circuit/stream element context. +// +typedef struct _ELEMENT_CONTEXT { + BOOLEAN Dummy; +} ELEMENT_CONTEXT, *PELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ELEMENT_CONTEXT, GetElementContext) + +// +// Define circuit/stream element context. +// +typedef struct _MUTE_ELEMENT_CONTEXT { + BOOL MuteState[MAX_CHANNELS]; +} MUTE_ELEMENT_CONTEXT, *PMUTE_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MUTE_ELEMENT_CONTEXT, GetMuteElementContext) + +// +// Define circuit/stream element context. +// +typedef struct _VOLUME_ELEMENT_CONTEXT { + LONG VolumeLevel[MAX_CHANNELS]; +} VOLUME_ELEMENT_CONTEXT, *PVOLUME_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(VOLUME_ELEMENT_CONTEXT, GetVolumeElementContext) + +#define VOLUME_STEPPING 0x8000 +#define VOLUME_LEVEL_MAXIMUM 0x00000000 +#define VOLUME_LEVEL_MINIMUM (-96 * 0x10000) + +// +// Define mute timer context. +// +typedef struct _MUTE_TIMER_CONTEXT { + ACXELEMENT MuteElement; + ACXEVENT Event; +} MUTE_TIMER_CONTEXT, *PMUTE_TIMER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MUTE_TIMER_CONTEXT, GetMuteTimerContext) + +// +// Define format context. +// +typedef struct _FORMAT_CONTEXT { + BOOLEAN Dummy; +} FORMAT_CONTEXT, *PFORMAT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(FORMAT_CONTEXT, GetFormatContext) + +// +// Define jack context. +// +typedef struct _JACK_CONTEXT { + ULONG Dummy; +} JACK_CONTEXT, * PJACK_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(JACK_CONTEXT, GetJackContext) + +// +// Define audio engine context. +// +typedef struct _ENGINE_CONTEXT { + ACXDATAFORMAT MixFormat; +} ENGINE_CONTEXT, * PENGINE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(ENGINE_CONTEXT, GetEngineContext) + +// +// Define stream audio engine context. +// +typedef struct _STREAMAUDIOENGINE_CONTEXT { + BOOLEAN Dummy; +} STREAMAUDIOENGINE_CONTEXT, * PSTREAMAUDIOENGINE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(STREAMAUDIOENGINE_CONTEXT, GetStreamAudioEngineContext) + +// +// Define keyword spotter context +// +typedef struct _KEYWORDSPOTTER_CONTEXT { + ACXPNPEVENT Event; + PVOID KeywordDetector; +} KEYWORDSPOTTER_CONTEXT, * PKEYWORDSPOTTER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(KEYWORDSPOTTER_CONTEXT, GetKeywordSpotterContext) + +// +// Define pnp event context. +// +typedef struct _PNPEVENT_CONTEXT { + BOOLEAN Dummy; +} PNPEVENT_CONTEXT, * PPNPEVENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PNPEVENT_CONTEXT, GetPnpEventContext) + +// +// Define peakmeter element context. +// +typedef struct _PEAKMETER_ELEMENT_CONTEXT { + LONG PeakMeterLevel[MAX_CHANNELS]; +} PEAKMETER_ELEMENT_CONTEXT, * PPEAKMETER_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(PEAKMETER_ELEMENT_CONTEXT, GetPeakMeterElementContext) + +// +// Define DSP circuit's peakmeter element context. +// +typedef struct _DSP_PEAKMETER_ELEMENT_CONTEXT +{ + PVOID peakMeter; +} DSP_PEAKMETER_ELEMENT_CONTEXT, *PDSP_PEAKMETER_ELEMENT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_PEAKMETER_ELEMENT_CONTEXT, GetDspPeakMeterElementContext) + +// +// Define stream engine context. +// +typedef struct _STREAMENGINE_CONTEXT { + PVOID StreamEngine; +} STREAMENGINE_CONTEXT, * PSTREAMENGINE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(STREAMENGINE_CONTEXT, GetStreamEngineContext) + +#define PEAKMETER_STEPPING_DELTA 0x1000 +#define PEAKMETER_MAXIMUM LONG_MAX +#define PEAKMETER_MINIMUM LONG_MIN + +///////////////////////////////////////////////////////////// +// Codec driver defintions +// + +typedef enum _CODEC_PIN_TYPE { + CodecPinTypeHost, + CodecPinTypeOffload, + CodecPinTypeLoopback, + CodecPinTypeKeyword, + CodecPinTypeDevice +} CODEC_PIN_TYPE, * PCODEC_PIN_TYPE; + +typedef struct _CODEC_PIN_CONTEXT { + CODEC_PIN_TYPE CodecPinType; +} CODEC_PIN_CONTEXT, * PCODEC_PIN_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_PIN_CONTEXT, GetCodecPinContext) + +/////////////////////////////////////////////////////////// +// Dsp driver definitions +// + +typedef enum { + CaptureHostPin = 0, + CaptureBridgePin = 1, + CaptureKWSPin = 2, + CapturePinCount = 3 +} CAPTURE_PIN_TYPE; + +typedef enum { + RenderHostPin = 0, + RenderOffloadPin = 1, + RenderLoopbackPin = 2, + RenderBridgePin = 3, + RenderPinCount = 4 +} RENDER_PIN_TYPE; + +typedef struct _DSP_PIN_CONTEXT { + ACXTARGETCIRCUIT TargetCircuit; + ULONG TargetPinId; + RENDER_PIN_TYPE RenderPinType; + CAPTURE_PIN_TYPE CapturePinType; + + // The stream bridge below will only be valid for the Capture circuit Bridge Pin + + // Host stream bridge will be used to ensure host stream creations are passed + // to the downlevel circuits. Since the HostStreamBridge won't have InModes set, + // the ACX framework will not add streams automatically. We will add streams for + // non KWS pin. + ACXSTREAMBRIDGE HostStreamBridge; +} DSP_PIN_CONTEXT, * PDSP_PIN_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_PIN_CONTEXT, GetDspPinContext) + +///////////////////////////////////////////////////////////// +// Multicircuit Dsp driver definitions +// + +// +// Circuit context for multi circuit dsp circuits. +// +typedef struct _DSP_CIRCUIT_CONTEXT +{ + ACXAUDIOENGINE AudioEngineElement; + ACXPEAKMETER PeakMeterElement; + PVOID peakMeter; + ACXKEYWORDSPOTTER KeywordSpotter; + BOOLEAN IsRenderCircuit; +} DSP_CIRCUIT_CONTEXT, *PDSP_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_CIRCUIT_CONTEXT, GetDspCircuitContext) + +typedef struct _DSP_ENGINE_CONTEXT +{ + ACXDATAFORMAT MixFormat; + BOOLEAN GFxEnabled; +} DSP_ENGINE_CONTEXT, *PDSP_ENGINE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_ENGINE_CONTEXT, GetDspEngineContext) + +typedef struct _DSP_STREAMAUDIOENGINE_CONTEXT +{ + BOOLEAN LFxEnabled; +} DSP_STREAMAUDIOENGINE_CONTEXT, *PDSP_STREAMAUDIOENGINE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_STREAMAUDIOENGINE_CONTEXT, GetDspStreamAudioEngineContext) + +///////////////////////////////////////////////////////// +// +// Codec Render (speaker) definitions +// + +// +// Define render circuit context. +// +typedef struct _CODEC_RENDER_CIRCUIT_CONTEXT { + ACXVOLUME VolumeElement; + ACXMUTE MuteElement; + ACXPEAKMETER PeakMeterElement; + ACXAUDIOENGINE AudioEngineElement; +} CODEC_RENDER_CIRCUIT_CONTEXT, * PCODEC_RENDER_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_RENDER_CIRCUIT_CONTEXT, GetRenderCircuitContext) + +typedef enum { + CodecRenderHostPin = 0, + CodecRenderBridgePin = 1, + CodecRenderPinCount = 2 +} CODEC_RENDER_PINS; + +typedef enum { + RenderVolumeIndex = 0, + RenderMuteIndex = 1, + RenderElementCount = 2 +} CODEC_RENDER_ELEMENTS; + +// Render callbacks. + +EVT_ACX_CIRCUIT_CREATE_STREAM CodecR_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CodecR_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CodecR_EvtCircuitPowerDown; +EVT_ACX_STREAM_SET_RENDER_PACKET CodecR_EvtStreamSetRenderPacket; +EVT_ACX_STREAM_GET_CAPTURE_PACKET CodecR_EvtStreamGetLoopbackPacket; +EVT_ACX_PIN_SET_DATAFORMAT CodecR_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CodecR_EvtPinContextCleanup; +EVT_ACX_MUTE_ASSIGN_STATE CodecR_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE CodecR_EvtMuteRetrieveState; +EVT_ACX_VOLUME_ASSIGN_LEVEL CodecR_EvtVolumeAssignLevel; +EVT_ACX_VOLUME_RETRIEVE_LEVEL CodecR_EvtVolumeRetrieveLevel; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL CodecR_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_RAMPED_VOLUME_ASSIGN_LEVEL CodecR_EvtRampedVolumeAssignLevel; +EVT_ACX_AUDIOENGINE_RETRIEVE_BUFFER_SIZE_LIMITS CodecR_EvtAcxAudioEngineRetrieveBufferSizeLimits; +EVT_ACX_AUDIOENGINE_RETRIEVE_EFFECTS_STATE CodecR_EvtAcxAudioEngineRetrieveEffectsState; +EVT_ACX_AUDIOENGINE_ASSIGN_EFFECTS_STATE CodecR_EvtAcxAudioEngineAssignEffectsState; +EVT_ACX_AUDIOENGINE_ASSIGN_ENGINE_FORMAT CodecR_EvtAcxAudioEngineAssignEngineDeviceFormat; +EVT_ACX_AUDIOENGINE_RETRIEVE_ENGINE_FORMAT CodecR_EvtAcxAudioEngineRetrieveEngineMixFormat; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_EFFECTS_STATE CodecR_EvtAcxStreamAudioEngineRetrieveEffectsState; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_EFFECTS_STATE CodecR_EvtAcxStreamAudioEngineAssignEffectsState; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_PRESENTATION_POSITION CodecR_EvtAcxStreamAudioEngineRetrievePresentationPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_CURRENT_WRITE_POSITION CodecR_EvtAcxStreamAudioEngineAssignCurrentWritePosition; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_LINEAR_BUFFER_POSITION CodecR_EvtAcxStreamAudioEngineRetrieveLinearBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LAST_BUFFER_POSITION CodecR_EvtAcxStreamAudioEngineAssignLastBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LOOPBACK_PROTECTION CodecR_EvtAcxStreamAudioEngineAssignLoopbackProtection; + +PAGED_CODE_SEG +NTSTATUS +CodecR_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// Codec Capture (microphone) definitions +// + +// +// Define capture circuit context. +// +typedef struct _CODEC_CAPTURE_CIRCUIT_CONTEXT { + ACXVOLUME BoostElement; + ACXVOLUME VolumeElement; + ACXKEYWORDSPOTTER KeywordSpotter; +} CODEC_CAPTURE_CIRCUIT_CONTEXT, * PCODEC_CAPTURE_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_CAPTURE_CIRCUIT_CONTEXT, GetCaptureCircuitContext) + +typedef enum { + CodecCaptureHostPin = 0, + CodecCaptureBridgePin = 1, + CodecCapturePinCount = 2 +} CODEC_CAPTURE_PINS; + +typedef enum { + CaptureVolumeIndex = 0, + CaptureElementCount = 1 +} CAPTURE_ELEMENTS; + +// Capture callbacks. + +EVT_ACX_CIRCUIT_CREATE_STREAM CodecC_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CodecC_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CodecC_EvtCircuitPowerDown; +EVT_ACX_VOLUME_ASSIGN_LEVEL CodecC_EvtVolumeAssignLevelCallback; +EVT_ACX_VOLUME_RETRIEVE_LEVEL CodecC_EvtVolumeRetrieveLevelCallback; +EVT_ACX_VOLUME_ASSIGN_LEVEL CodecC_EvtBoostAssignLevelCallback; +EVT_ACX_VOLUME_RETRIEVE_LEVEL CodecC_EvtBoostRetrieveLevelCallback; +EVT_ACX_STREAM_GET_CAPTURE_PACKET CodecC_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT CodecC_EvtAcxPinSetDataFormat; +EVT_ACX_PIN_RETRIEVE_NAME CodecC_EvtAcxPinRetrieveName; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CodecC_EvtPinContextCleanup; +EVT_ACX_KEYWORDSPOTTER_RETRIEVE_ARM CodecC_EvtAcxKeywordSpotterRetrieveArm; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_ARM CodecC_EvtAcxKeywordSpotterAssignArm; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_PATTERNS CodecC_EvtAcxKeywordSpotterAssignPatterns; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_RESET CodecC_EvtAcxKeywordSpotterAssignReset; + +PAGED_CODE_SEG +NTSTATUS +CodecC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// MicArray definitions +// + +// +// Define MicArray circuit context. +// +typedef struct _MICARRAY_CIRCUIT_CONTEXT { + ACXMUTE MuteElement; + ACXVOLUME VolumeElement; + ACXPEAKMETER PeakMeterElement; + ACXKEYWORDSPOTTER KeywordSpotter; +} MICARRAY_CIRCUIT_CONTEXT, * PMICARRAY_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MICARRAY_CIRCUIT_CONTEXT, GetMicArrayCircuitContext) + +typedef enum { + MicArrayVolumeIndex = 0, + MicArrayMuteIndex = 1, + MicArrayPeakmeterIndex = 2, + MicArrayKWSIndex = 3, + MicArrayElementCount = 4 +} MICARRAY_ELEMENTS; + +// MicArray callbacks. + +EVT_ACX_MUTE_ASSIGN_STATE MicArray_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE MicArray_EvtMuteRetrieveState; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL MicArray_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_CIRCUIT_CREATE_STREAM MicArray_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP MicArray_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN MicArray_EvtCircuitPowerDown; +EVT_ACX_VOLUME_ASSIGN_LEVEL MicArray_EvtVolumeAssignLevelCallback; +EVT_ACX_VOLUME_RETRIEVE_LEVEL MicArray_EvtVolumeRetrieveLevelCallback; +EVT_ACX_STREAM_GET_CAPTURE_PACKET MicArray_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT MicArray_EvtAcxPinSetDataFormat; +EVT_ACX_PIN_RETRIEVE_NAME MicArray_EvtAcxPinRetrieveName; +EVT_WDF_DEVICE_CONTEXT_CLEANUP MicArray_EvtPinContextCleanup; +EVT_ACX_KEYWORDSPOTTER_RETRIEVE_ARM MicArray_EvtAcxKeywordSpotterRetrieveArm; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_ARM MicArray_EvtAcxKeywordSpotterAssignArm; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_PATTERNS MicArray_EvtAcxKeywordSpotterAssignPatterns; +EVT_ACX_KEYWORDSPOTTER_ASSIGN_RESET MicArray_EvtAcxKeywordSpotterAssignReset; +EVT_ACX_PIN_CONNECTED MicArray_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED MicArray_EvtPinDisconnected; +EVT_WDF_DEVICE_CONTEXT_CLEANUP MicArray_EvtDeviceContextCleanup; +EVT_ACX_OBJECT_PROCESS_REQUEST MicArray_EvtPinProposeDataFormat2Callback; +EVT_ACX_OBJECT_PREPROCESS_REQUEST MicArray_EvtAudioCpuResourcesCallback; + +PAGED_CODE_SEG +NTSTATUS +MicArray_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ GUID MicCustomName, + _In_ UNICODE_STRING CircuitName, + _Out_ ACXCIRCUIT * Circuit +); + +PAGED_CODE_SEG +NTSTATUS +MicArray_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +///////////////////////////////////////////////////////// +// +// Microphone (external: headphone) definitions +// + +// +// Define MicrophoneHp circuit context. +// +typedef struct _MICROPHONEHP_CIRCUIT_CONTEXT { + ACXMUTE MuteElement; + ACXVOLUME VolumeElement; + ACXPEAKMETER PeakMeterElement; +} MICROPHONEHP_CIRCUIT_CONTEXT, * PMICROPHONEHP_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(MICROPHONEHP_CIRCUIT_CONTEXT, GetMicrophoneHpCircuitContext) + +typedef enum { + MicrophoneHpVolumeIndex = 0, + MicrophoneHpMuteIndex = 1, + MicrophoneHpPeakmeterIndex = 2, + MicrophoneHpElementCount = 3 +} MICROPHONEHP_ELEMENTS; + +// MicrophoneHp callbacks. + +EVT_ACX_MUTE_ASSIGN_STATE MicrophoneHp_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE MicrophoneHp_EvtMuteRetrieveState; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL MicrophoneHp_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_CIRCUIT_CREATE_STREAM MicrophoneHp_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP MicrophoneHp_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN MicrophoneHp_EvtCircuitPowerDown; +EVT_ACX_VOLUME_ASSIGN_LEVEL MicrophoneHp_EvtVolumeAssignLevelCallback; +EVT_ACX_VOLUME_RETRIEVE_LEVEL MicrophoneHp_EvtVolumeRetrieveLevelCallback; +EVT_ACX_STREAM_GET_CAPTURE_PACKET MicrophoneHp_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT MicrophoneHp_EvtAcxPinSetDataFormat; +EVT_ACX_PIN_RETRIEVE_NAME MicrophoneHp_EvtAcxPinRetrieveName; +EVT_WDF_DEVICE_CONTEXT_CLEANUP MicrophoneHp_EvtPinContextCleanup; +EVT_ACX_PIN_CONNECTED MicrophoneHp_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED MicrophoneHp_EvtPinDisconnected; +EVT_ACX_OBJECT_PREPROCESS_REQUEST MicrophoneHp_EvtAudioCpuResourcesCallback; + +PAGED_CODE_SEG +NTSTATUS +MicrophoneHp_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ GUID MicCustomName, + _In_ UNICODE_STRING CircuitName, + _Out_ ACXCIRCUIT * Circuit +); + +PAGED_CODE_SEG +NTSTATUS +MicrophoneHp_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +///////////////////////////////////////////////////////// +// +// Speaker definitions +// + +// +// Define circuit context for Speaker and SpeakerHp. +// +typedef struct _DSP_RENDER_CIRCUIT_CONTEXT { + ACXPEAKMETER PeakMeterElement; + ACXAUDIOENGINE AudioEngineElement; + PVOID PeakMeter; +} DSP_RENDER_CIRCUIT_CONTEXT, * PDSP_RENDER_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_RENDER_CIRCUIT_CONTEXT, GetSpeakerCircuitContext) + +// Speaker callbacks. + +EVT_ACX_CIRCUIT_CREATE_STREAM Speaker_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP Speaker_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN Speaker_EvtCircuitPowerDown; +EVT_ACX_STREAM_SET_RENDER_PACKET Speaker_EvtStreamSetRenderPacket; +EVT_ACX_STREAM_GET_CAPTURE_PACKET Speaker_EvtStreamGetLoopbackPacket; +EVT_ACX_PIN_SET_DATAFORMAT Speaker_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP Speaker_EvtPinContextCleanup; +EVT_ACX_PIN_CONNECTED Speaker_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED Speaker_EvtPinDisconnected; + +//Render Audio Engine callbacks. + +EVT_ACX_MUTE_ASSIGN_STATE Speaker_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE Speaker_EvtMuteRetrieveState; +EVT_ACX_VOLUME_RETRIEVE_LEVEL Speaker_EvtVolumeRetrieveLevel; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL Speaker_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_RAMPED_VOLUME_ASSIGN_LEVEL Speaker_EvtRampedVolumeAssignLevel; +EVT_ACX_AUDIOENGINE_RETRIEVE_BUFFER_SIZE_LIMITS Speaker_EvtAcxAudioEngineRetrieveBufferSizeLimits; +EVT_ACX_AUDIOENGINE_RETRIEVE_EFFECTS_STATE Speaker_EvtAcxAudioEngineRetrieveEffectsState; +EVT_ACX_AUDIOENGINE_ASSIGN_EFFECTS_STATE Speaker_EvtAcxAudioEngineAssignEffectsState; +EVT_ACX_AUDIOENGINE_ASSIGN_ENGINE_FORMAT Speaker_EvtAcxAudioEngineAssignEngineDeviceFormat; +EVT_ACX_AUDIOENGINE_RETRIEVE_ENGINE_FORMAT Speaker_EvtAcxAudioEngineRetrieveEngineMixFormat; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_EFFECTS_STATE Speaker_EvtAcxStreamAudioEngineRetrieveEffectsState; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_EFFECTS_STATE Speaker_EvtAcxStreamAudioEngineAssignEffectsState; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_PRESENTATION_POSITION Speaker_EvtAcxStreamAudioEngineRetrievePresentationPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_CURRENT_WRITE_POSITION Speaker_EvtAcxStreamAudioEngineAssignCurrentWritePosition; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_LINEAR_BUFFER_POSITION Speaker_EvtAcxStreamAudioEngineRetrieveLinearBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LAST_BUFFER_POSITION Speaker_EvtAcxStreamAudioEngineAssignLastBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LOOPBACK_PROTECTION Speaker_EvtAcxStreamAudioEngineAssignLoopbackProtection; + +PAGED_CODE_SEG +NTSTATUS +Speaker_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +Speaker_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ UNICODE_STRING CircuitName, + _In_ BOOLEAN IsHeadphones, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// HDMI definitions +// + +// +// Define HDMI circuit context. +// +typedef struct _DSP_HDMI_CIRCUIT_CONTEXT { + ACXVOLUME VolumeElement; + ACXMUTE MuteElement; + ACXPEAKMETER PeakmeterElement; +} DSP_HDMI_CIRCUIT_CONTEXT, * PDSP_HDMI_CIRCUIT_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_HDMI_CIRCUIT_CONTEXT, GetHDMICircuitContext) + +typedef enum { + HDMIVolumeIndex = 0, + HDMIMuteIndex = 1, + HDMIPeakmeterIndex = 2, + HDMIElementCount = 3 +} HDMI_ELEMENTS; + +typedef enum { + HDMIHostPin = 0, + HDMILoopbackPin = 1, + HDMIBridgePin = 2, + HDMIPinCount = 3 +} HDMI_PIN_TYPE; + +typedef struct _HDMI_PIN_CONTEXT { + ACXTARGETCIRCUIT TargetCircuit; + ULONG TargetPinId; + HDMI_PIN_TYPE PinType; + CAPTURE_PIN_TYPE CapturePinType; +} HDMI_PIN_CONTEXT, * PHDMI_PIN_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HDMI_PIN_CONTEXT, GetHDMIPinContext) + +typedef struct _HDMI_STREAM_CONTEXT { + HDMI_PIN_TYPE PinType; + CAPTURE_PIN_TYPE CapturePinType; +} HDMI_STREAM_CONTEXT, * PHDMI_STREAM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(HDMI_STREAM_CONTEXT, GetHDMIStreamContext) + +// HDMI callbacks. +EVT_ACX_CIRCUIT_CREATE_STREAM HDMI_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP HDMI_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN HDMI_EvtCircuitPowerDown; +EVT_ACX_STREAM_SET_RENDER_PACKET HDMI_EvtStreamSetRenderPacket; +EVT_ACX_STREAM_GET_CAPTURE_PACKET HDMI_EvtStreamGetLoopbackPacket; +EVT_ACX_PIN_SET_DATAFORMAT HDMI_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP HDMI_EvtPinContextCleanup; +EVT_ACX_PIN_CONNECTED HDMI_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED HDMI_EvtPinDisconnected; +EVT_WDF_DEVICE_CONTEXT_CLEANUP HDMI_EvtDeviceContextCleanup; +EVT_ACX_MUTE_ASSIGN_STATE HDMI_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE HDMI_EvtMuteRetrieveState; +EVT_ACX_VOLUME_ASSIGN_LEVEL HDMI_EvtRampedVolumeAssignLevel; +EVT_ACX_VOLUME_RETRIEVE_LEVEL HDMI_EvtVolumeRetrieveLevel; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL HDMI_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_OBJECT_PREPROCESS_REQUEST HDMI_EvtAudioCpuResourcesCallback; + +PAGED_CODE_SEG +NTSTATUS +HDMI_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +HDMI_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ UNICODE_STRING CircuitName, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// Multi circuit codec Render (speaker) definitions +// + +// Uses the same circuit context, render pin, and render element definitions as Codec Render. + +// Render callbacks. +EVT_ACX_CIRCUIT_CREATE_STREAM RenderMC_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP RenderMC_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN RenderMC_EvtCircuitPowerDown; +EVT_ACX_PIN_SET_DATAFORMAT RenderMC_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP RenderMC_EvtPinContextCleanup; +EVT_ACX_MUTE_ASSIGN_STATE RenderMC_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE RenderMC_EvtMuteRetrieveState; +EVT_ACX_VOLUME_RETRIEVE_LEVEL RenderMC_EvtVolumeRetrieveLevel; +EVT_ACX_RAMPED_VOLUME_ASSIGN_LEVEL RenderMC_EvtRampedVolumeAssignLevel; + +PAGED_CODE_SEG +NTSTATUS +RenderMC_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName, + _In_ const UNICODE_STRING * Uri, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// Multi circuit codec Capture (microphone) definitions +// + +// Uses the same circuit context, render pin, and render element definitions as Codec Capture. + +// Capture callbacks. +EVT_ACX_CIRCUIT_CREATE_STREAM CaptureMC_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CaptureMC_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CaptureMC_EvtCircuitPowerDown; +EVT_ACX_STREAM_GET_CAPTURE_PACKET CaptureMC_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT CaptureMC_EvtAcxPinSetDataFormat; +EVT_ACX_PIN_RETRIEVE_NAME CaptureMC_EvtAcxPinRetrieveName; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CaptureMC_EvtPinContextCleanup; + +PAGED_CODE_SEG +NTSTATUS +CaptureMC_CreateCaptureCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName, + _In_ const UNICODE_STRING * Uri, + _Out_ ACXCIRCUIT * Circuit +); + +///////////////////////////////////////////////////////// +// +// Multi circuit dsp Render (speaker) definitions +// + +// Uses the same circuit context, render pin, and render element definitions as Codec Render. + +// Render callbacks. +EVT_ACX_CIRCUIT_COMPOSITE_CIRCUIT_INITIALIZE RenderMCDsp_EvtCircuitCompositeCircuitInitialize; +EVT_ACX_CIRCUIT_COMPOSITE_INITIALIZE RenderMCDsp_EvtCircuitCompositeInitialize; +EVT_WDF_DEVICE_CONTEXT_CLEANUP RenderMCDsp_EvtCircuitContextCleanup; +EVT_WDF_DEVICE_PREPARE_HARDWARE RenderMCDsp_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE RenderMCDsp_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT RenderMCDsp_EvtDeviceSelfManagedIoInit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP RenderMCDsp_EvtDeviceContextCleanup; +EVT_ACX_CIRCUIT_CREATE_STREAM RenderMCDsp_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP RenderMCDsp_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN RenderMCDsp_EvtCircuitPowerDown; +EVT_ACX_STREAM_SET_RENDER_PACKET RenderMCDsp_EvtStreamSetRenderPacket; +EVT_ACX_PIN_SET_DATAFORMAT RenderMCDsp_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP RenderMCDsp_EvtPinContextCleanup; +EVT_ACX_PIN_CONNECTED RenderMCDsp_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED RenderMCDsp_EvtPinDisconnected; + +// Render Audio Engine +EVT_ACX_MUTE_ASSIGN_STATE DspR_EvtMuteAssignState; +EVT_ACX_MUTE_RETRIEVE_STATE DspR_EvtMuteRetrieveState; +EVT_ACX_VOLUME_RETRIEVE_LEVEL DspR_EvtVolumeRetrieveLevel; +EVT_ACX_PEAKMETER_RETRIEVE_LEVEL DspR_EvtPeakMeterRetrieveLevelCallback; +EVT_ACX_RAMPED_VOLUME_ASSIGN_LEVEL DspR_EvtRampedVolumeAssignLevel; +EVT_ACX_AUDIOENGINE_RETRIEVE_BUFFER_SIZE_LIMITS DspR_EvtAcxAudioEngineRetrieveBufferSizeLimits; +EVT_ACX_AUDIOENGINE_RETRIEVE_EFFECTS_STATE DspR_EvtAcxAudioEngineRetrieveEffectsState; +EVT_ACX_AUDIOENGINE_ASSIGN_EFFECTS_STATE DspR_EvtAcxAudioEngineAssignEffectsState; +EVT_ACX_AUDIOENGINE_RETRIEVE_ENGINE_FORMAT DspR_EvtAcxAudioEngineRetrieveEngineMixFormat; +EVT_ACX_AUDIOENGINE_ASSIGN_ENGINE_FORMAT DspR_EvtAcxAudioEngineAssignEngineDeviceFormat; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_EFFECTS_STATE DspR_EvtAcxStreamAudioEngineRetrieveEffectsState; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_EFFECTS_STATE DspR_EvtAcxStreamAudioEngineAssignEffectsState; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_PRESENTATION_POSITION DspR_EvtAcxStreamAudioEngineRetrievePresentationPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_CURRENT_WRITE_POSITION DspR_EvtAcxStreamAudioEngineAssignCurrentWritePosition; +EVT_ACX_STREAMAUDIOENGINE_RETRIEVE_LINEAR_BUFFER_POSITION DspR_EvtAcxStreamAudioEngineRetrieveLinearBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LAST_BUFFER_POSITION DspR_EvtAcxStreamAudioEngineAssignLastBufferPosition; +EVT_ACX_STREAMAUDIOENGINE_ASSIGN_LOOPBACK_PROTECTION DspR_EvtAcxStreamAudioEngineAssignLoopbackProtection; + +PAGED_CODE_SEG +NTSTATUS +RenderMCDsp_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS CreateRenderCircuit( + _In_ PACXCIRCUIT_INIT CircuitInit, + _In_ UNICODE_STRING CircuitName, + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT* Circuit +); + +PAGED_CODE_SEG +NTSTATUS CreateRenderMCDspPin( + _In_ ACX_PIN_TYPE PinType, + _In_ ACXCIRCUIT Circuit, + _In_ ACX_PIN_COMMUNICATION Communication, + _In_ const GUID* Category, + _In_ ACX_PIN_CALLBACKS* PinCallbacks, + _In_ bool Mic, + _Out_ ACXPIN* Pin +); + +PAGED_CODE_SEG +NTSTATUS CreateAudioEngine( + _In_ ACXCIRCUIT Circuit, + _In_reads_(PinCount) ACXPIN* Pins, + _In_ ULONG PinCount, + _Out_ ACXAUDIOENGINE* AudioEngineElement +); + +///////////////////////////////////////////////////////// +// +// Multi circuit dsp Capture (microphone) definitions +// + +// Uses the same circuit context, capture pin and capture element definitions as Codec Capture. + +// Capture callbacks. +EVT_ACX_CIRCUIT_COMPOSITE_CIRCUIT_INITIALIZE CaptureMCDsp_EvtCircuitCompositeCircuitInitialize; +EVT_ACX_CIRCUIT_COMPOSITE_INITIALIZE CaptureMCDsp_EvtCircuitCompositeInitialize; +EVT_WDF_DEVICE_PREPARE_HARDWARE CaptureMCDsp_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE CaptureMCDsp_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_SELF_MANAGED_IO_INIT CaptureMCDsp_EvtDeviceSelfManagedIoInit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CaptureMCDsp_EvtDeviceContextCleanup; +EVT_ACX_CIRCUIT_CREATE_STREAM CaptureMCDsp_EvtCircuitCreateStream; +EVT_ACX_CIRCUIT_POWER_UP CaptureMCDsp_EvtCircuitPowerUp; +EVT_ACX_CIRCUIT_POWER_DOWN CaptureMCDsp_EvtCircuitPowerDown; +EVT_ACX_STREAM_GET_CAPTURE_PACKET CaptureMCDsp_EvtStreamGetCapturePacket; +EVT_ACX_PIN_SET_DATAFORMAT CaptureMCDsp_EvtAcxPinSetDataFormat; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CaptureMCDsp_EvtPinContextCleanup; +EVT_ACX_PIN_CONNECTED CaptureMCDsp_EvtPinConnected; +EVT_ACX_PIN_DISCONNECTED CaptureMCDsp_EvtPinDisconnected; + +PAGED_CODE_SEG +NTSTATUS +CaptureMCDsp_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS CreateCaptureCircuit( + _In_ PACXCIRCUIT_INIT CircuitInit, + _In_ UNICODE_STRING CircuitName, + _In_ WDFDEVICE Device, + _Out_ ACXCIRCUIT* Circuit +); + +PAGED_CODE_SEG +NTSTATUS CreateCaptureMCDspPin( + _In_ ACX_PIN_TYPE PinType, + _In_ ACXCIRCUIT Circuit, + _In_ ACX_PIN_COMMUNICATION Communication, + _In_ const GUID* Category, + _In_ ACX_PIN_CALLBACKS* PinCallbacks, + _In_ bool Mic, + _Out_ ACXPIN* Pin +); + +/* make internal prototypes usable from C++ */ +#ifdef __cplusplus +} +#endif + + + +#endif // _PRIVATE_H_ diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/RenderCircuit.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/RenderCircuit.cpp new file mode 100644 index 000000000..89434a81a --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/RenderCircuit.cpp @@ -0,0 +1,807 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + RenderCircuit.cpp + +Abstract: + + Render Circuit. This file contains routines to create and handle + render circuit with no offload. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include +#include +#include +#include "AudioFormats.h" +#include "streamengine.h" +#include "cpp_utils.h" +#include "circuithelper.h" + +#ifndef __INTELLISENSE__ +#include "renderCircuit.tmh" +#endif + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtAcxPinSetDataFormat( + _In_ ACXPIN Pin, + _In_ ACXDATAFORMAT DataFormat +) +/*++ + +Routine Description: + + This ACX pin callback sets the device/mixed format. + +Return Value: + + NTSTATUS + +--*/ +{ + UNREFERENCED_PARAMETER(Pin); + UNREFERENCED_PARAMETER(DataFormat); + + PAGED_CODE(); + + // NOTE: update device/mixed format here. + + return STATUS_NOT_SUPPORTED; +} + +/////////////////////////////////////////////////////////// +// +// For more information on mute element see: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/ksnodetype-mute +// +_Use_decl_annotations_ +NTSTATUS +NTAPI +CodecR_EvtMuteAssignState( + _In_ ACXMUTE Mute, + _In_ ULONG Channel, + _In_ ULONG State +) +{ + PMUTE_ELEMENT_CONTEXT muteCtx; + ULONG i; + + PAGED_CODE(); + + muteCtx = GetMuteElementContext(Mute); + ASSERT(muteCtx); + + // + // Use first channel for all channels setting. + // + if (Channel != ALL_CHANNELS_ID) + { + muteCtx->MuteState[Channel] = State; + } + else + { + for (i = 0; i < MAX_CHANNELS; ++i) + { + muteCtx->MuteState[i] = State; + } + } + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +NTAPI +CodecR_EvtMuteRetrieveState( + _In_ ACXMUTE Mute, + _In_ ULONG Channel, + _Out_ ULONG * State +) +{ + PMUTE_ELEMENT_CONTEXT muteCtx; + + PAGED_CODE(); + + muteCtx = GetMuteElementContext(Mute); + ASSERT(muteCtx); + + // + // Use first channel for all channels setting. + // + if (Channel != ALL_CHANNELS_ID) + { + *State = muteCtx->MuteState[Channel]; + } + else + { + *State = muteCtx->MuteState[0]; + } + + return STATUS_SUCCESS; +} + +/////////////////////////////////////////////////////////// +// +// For more information on volume element see: https://docs.microsoft.com/en-us/windows-hardware/drivers/audio/ksnodetype-volume +// +_Use_decl_annotations_ +NTSTATUS +NTAPI +CodecR_EvtRampedVolumeAssignLevel( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _In_ LONG VolumeLevel, + _In_ ACX_VOLUME_CURVE_TYPE CurveType, + _In_ ULONGLONG CurveDuration +) +{ + PVOLUME_ELEMENT_CONTEXT volumeCtx; + ULONG i; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(CurveType); + UNREFERENCED_PARAMETER(CurveDuration); + + volumeCtx = GetVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel != ALL_CHANNELS_ID) + { + volumeCtx->VolumeLevel[Channel] = VolumeLevel; + } + else + { + for (i = 0; i < MAX_CHANNELS; ++i) + { + volumeCtx->VolumeLevel[i] = VolumeLevel; + } + } + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +NTAPI +CodecR_EvtVolumeRetrieveLevel( + _In_ ACXVOLUME Volume, + _In_ ULONG Channel, + _Out_ LONG * VolumeLevel +) +{ + PVOLUME_ELEMENT_CONTEXT volumeCtx; + + PAGED_CODE(); + + volumeCtx = GetVolumeElementContext(Volume); + ASSERT(volumeCtx); + + if (Channel != ALL_CHANNELS_ID) + { + *VolumeLevel = volumeCtx->VolumeLevel[Channel]; + } + else + { + *VolumeLevel = volumeCtx->VolumeLevel[0]; + } + + return STATUS_SUCCESS; +} + +VOID +CodecR_EvtPinContextCleanup( + _In_ WDFOBJECT WdfPin +) +/*++ + +Routine Description: + + In this callback, it cleans up pin context. + +Arguments: + + WdfDevice - WDF device object + +Return Value: + + nullptr + +--*/ +{ + + UNREFERENCED_PARAMETER(WdfPin); +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName +) +/*++ + +Routine Description: + + Creates the static render circuit (pictured below) and + adds it to the device context. This is called when a + new device is detected and the AddDevice call is made + by the pnp manager. + + *************************************************************************** + * Render Circuit * + * * + * +--------------------------------------------+ * + * | | * + * | +-------------+ +-------------+ | * + * Host ------>| | Volume Node | | Mute Node | |---> Bridge * + * Pin | +-------------+ +-------------+ | Pin * + * | | * + * +--------------------------------------------+ * + * * + *************************************************************************** + +Return Value: + + NTSTATUS + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + PCODEC_DEVICE_CONTEXT devCtx; + PRENDER_DEVICE_CONTEXT renderDevCtx; + ACXCIRCUIT renderCircuit = nullptr; + WDF_OBJECT_ATTRIBUTES attributes; + + PAGED_CODE(); + + devCtx = GetCodecDeviceContext(Device); + ASSERT(devCtx != nullptr); + + // + // Alloc audio context to current device. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, RENDER_DEVICE_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(WdfObjectAllocateContext(Device, &attributes, (PVOID*)&renderDevCtx)); + ASSERT(renderDevCtx); + + // + // Create a render circuit associated with this child device. + // + RETURN_NTSTATUS_IF_FAILED(CodecR_CreateRenderCircuit(Device, ComponentGuid, CircuitName, &renderCircuit)); + + devCtx->Render = renderCircuit; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +Render_AllocateSupportedFormats( + _In_ WDFDEVICE Device, + _In_reads_bytes_(CodecRenderPinCount) ACXPIN Pin[], + _In_ ACXCIRCUIT Circuit, + _In_ size_t CodecRenderPinCount +) +{ + UNREFERENCED_PARAMETER(CodecRenderPinCount); + + NTSTATUS status = STATUS_SUCCESS; + ACXDATAFORMAT formatPcm44100c2; + ACXDATAFORMAT formatPcm48000c2; + ACXDATAFORMATLIST formatList; + + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + + /////////////////////////////////////////////////////////// + // + // Allocate the formats this circuit supports. + // + + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm44100c2, Circuit, Device, &formatPcm44100c2)); + RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm48000c2, Circuit, Device, &formatPcm48000c2)); + + /////////////////////////////////////////////////////////// + // + // Define supported formats for the host pin. + // + + // + // The raw processing mode list is associated with each single circuit + // by ACX. The driver uses this DDI to retrieve the built-in raw + // data-format list. + // + RETURN_NTSTATUS_IF_TRUE(CodecRenderHostPin >= CodecRenderPinCount, STATUS_INVALID_PARAMETER); + formatList = AcxPinGetRawDataFormatList(Pin[CodecRenderHostPin]); + RETURN_NTSTATUS_IF_TRUE(formatList == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + // + // The driver uses this DDI to add data formats to the raw + // processing mode list associated with the current circuit. + // + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c2)); + RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm48000c2)); + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_CreateRenderCircuit( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName, + _Out_ ACXCIRCUIT* Circuit +) +/*++ + +Routine Description: + + This routine builds the CODEC render circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDF_OBJECT_ATTRIBUTES attributes; + ACXCIRCUIT circuit; + CODEC_RENDER_CIRCUIT_CONTEXT* circuitCtx; + ACXPIN pin[CodecRenderPinCount]; + + PAGED_CODE(); + + // + // Init output value. + // + *Circuit = nullptr; + + /////////////////////////////////////////////////////////// + // + // Create a circuit. + // + { + PACXCIRCUIT_INIT circuitInit = nullptr; + ACX_CIRCUIT_PNPPOWER_CALLBACKS powerCallbacks; + + // + // The driver uses this DDI to allocate an ACXCIRCUIT_INIT + // structure. This opaque structure is used when creating + // a standalone audio circuit representing an audio device. + // + circuitInit = AcxCircuitInitAllocate(Device); + + // + // The driver uses this DDI to free the allocated + // ACXCIRCUIT_INIT structure when an error is detected. + // Normally the structures is deleted/cleared by ACX when + // an ACX circuit is created successfully. + // + auto circuitInitScope = scope_exit([&circuitInit]() { + if (circuitInit) { + AcxCircuitInitFree(circuitInit); + } + }); + + // + // The driver uses this DDI to specify the Component ID + // of the ACX circuit. This ID is a guid that uniquely + // identifies the circuit instance (vendor specific). + // + AcxCircuitInitSetComponentId(circuitInit, ComponentGuid); + + // + // The driver uses this DDI to specify the circuit name. + // For standalone circuits, this is the audio device name + // which is used by clients to open handles to the audio devices. + // + (VOID)AcxCircuitInitAssignName(circuitInit, CircuitName); + + // + // The driver uses this DDI to specify the circuit type. The + // circuit type can be AcxCircuitTypeRender, AcxCircuitTypeCapture, + // AcxCircuitTypeOther, or AcxCircuitTypeMaximum (for validation). + // + AcxCircuitInitSetCircuitType(circuitInit, AcxCircuitTypeRender); + + // + // The driver uses this DDI to assign its (if any) power callbacks. + // + ACX_CIRCUIT_PNPPOWER_CALLBACKS_INIT(&powerCallbacks); + powerCallbacks.EvtAcxCircuitPowerUp = CodecR_EvtCircuitPowerUp; + powerCallbacks.EvtAcxCircuitPowerDown = CodecR_EvtCircuitPowerDown; + AcxCircuitInitSetAcxCircuitPnpPowerCallbacks(circuitInit, &powerCallbacks); + + // + // The driver uses this DDI to register for a stream-create callback. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitInitAssignAcxCreateStreamCallback(circuitInit, CodecR_EvtCircuitCreateStream)); + + // + // The driver uses this DDI to create a new ACX circuit. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_RENDER_CIRCUIT_CONTEXT); + RETURN_NTSTATUS_IF_FAILED(AcxCircuitCreate(Device, &attributes, &circuitInit, &circuit)); + + circuitInitScope.release(); + + circuitCtx = GetRenderCircuitContext(circuit); + ASSERT(circuitCtx); + } + + // + // Post circuit creation initialization. + // + + /////////////////////////////////////////////////////////// + // + // Create mute and volume elements. + // + { + ACXELEMENT elements[RenderElementCount] = { 0 }; + + // + // The driver uses this DDI to assign its volume element callbacks. + // + ACX_VOLUME_CALLBACKS volumeCallbacks; + ACX_VOLUME_CALLBACKS_INIT(&volumeCallbacks); + volumeCallbacks.EvtAcxRampedVolumeAssignLevel = CodecR_EvtRampedVolumeAssignLevel; + volumeCallbacks.EvtAcxVolumeRetrieveLevel = CodecR_EvtVolumeRetrieveLevel; + + // + // Create Volume element + // + ACX_VOLUME_CONFIG volumeCfg; + ACX_VOLUME_CONFIG_INIT(&volumeCfg); + volumeCfg.ChannelsCount = MAX_CHANNELS; + volumeCfg.Minimum = VOLUME_LEVEL_MINIMUM; + volumeCfg.Maximum = VOLUME_LEVEL_MAXIMUM; + volumeCfg.SteppingDelta = VOLUME_STEPPING; + volumeCfg.Name = &KSAUDFNAME_VOLUME_CONTROL; + volumeCfg.Callbacks = &volumeCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, VOLUME_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxVolumeCreate(circuit, &attributes, &volumeCfg, (ACXVOLUME*)&elements[RenderVolumeIndex])); + + // + // The driver uses this DDI to assign its mute element callbacks. + // + ACX_MUTE_CALLBACKS muteCallbacks; + ACX_MUTE_CALLBACKS_INIT(&muteCallbacks); + muteCallbacks.EvtAcxMuteAssignState = CodecR_EvtMuteAssignState; + muteCallbacks.EvtAcxMuteRetrieveState = CodecR_EvtMuteRetrieveState; + + // + // Create Mute element + // + ACX_MUTE_CONFIG muteCfg; + ACX_MUTE_CONFIG_INIT(&muteCfg); + muteCfg.ChannelsCount = MAX_CHANNELS; + muteCfg.Name = &KSAUDFNAME_WAVE_MUTE; + muteCfg.Callbacks = &muteCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, MUTE_ELEMENT_CONTEXT); + attributes.ParentObject = circuit; + + RETURN_NTSTATUS_IF_FAILED(AcxMuteCreate(circuit, &attributes, &muteCfg, (ACXMUTE*)&elements[RenderMuteIndex])); + + // + // Saving the volume and mute elements in the circuit context. + // + circuitCtx->VolumeElement = (ACXVOLUME)elements[RenderVolumeIndex]; + circuitCtx->MuteElement = (ACXMUTE)elements[RenderMuteIndex]; + + // + // The driver uses this DDI post circuit creation to add ACXELEMENTs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddElements(circuit, elements, SIZEOF_ARRAY(elements))); + } + + /////////////////////////////////////////////////////////// + // + // Create the pins for the circuit. + // + { + ACX_PIN_CONFIG pinCfg; + CODEC_PIN_CONTEXT* pinCtx; + ACX_PIN_CALLBACKS pinCallbacks; + + /////////////////////////////////////////////////////////// + // + // Create Render Pin. + // + + ACX_PIN_CALLBACKS_INIT(&pinCallbacks); + pinCallbacks.EvtAcxPinSetDataFormat = CodecR_EvtAcxPinSetDataFormat; + + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSink; + pinCfg.Communication = AcxPinCommunicationSink; + pinCfg.Category = &KSCATEGORY_AUDIO; + pinCfg.PinCallbacks = &pinCallbacks; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecR_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin[CodecRenderHostPin])); + + ASSERT(pin[CodecRenderHostPin] != nullptr); + pinCtx = GetCodecPinContext(pin[CodecRenderHostPin]); + ASSERT(pinCtx); + pinCtx->CodecPinType = CodecPinTypeHost; + + /////////////////////////////////////////////////////////// + // + // Create Device Bridge Pin. + // + + ACX_PIN_CONFIG_INIT(&pinCfg); + pinCfg.Type = AcxPinTypeSource; + pinCfg.Communication = AcxPinCommunicationNone; + pinCfg.Category = &KSNODETYPE_SPEAKER; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CODEC_PIN_CONTEXT); + attributes.EvtCleanupCallback = CodecR_EvtPinContextCleanup; + attributes.ParentObject = circuit; + + // + // The driver uses this DDI to create one or more pins on the circuits. + // + RETURN_NTSTATUS_IF_FAILED(AcxPinCreate(circuit, &attributes, &pinCfg, &pin[CodecRenderBridgePin])); + + ASSERT(pin[CodecRenderBridgePin] != nullptr); + pinCtx = GetCodecPinContext(pin[CodecRenderBridgePin]); + ASSERT(pinCtx); + pinCtx->CodecPinType = CodecPinTypeDevice; + } + + /////////////////////////////////////////////////////////// + // + // Add audio jack to bridge pin. + // For more information on audio jack see: https://docs.microsoft.com/en-us/windows/win32/api/devicetopology/ns-devicetopology-ksjack_description + // + { + ACX_JACK_CONFIG jackCfg; + ACXJACK jack; + PJACK_CONTEXT jackCtx; + + ACX_JACK_CONFIG_INIT(&jackCfg); + jackCfg.Description.ChannelMapping = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT; + jackCfg.Description.Color = RGB(0, 0, 0); + jackCfg.Description.ConnectionType = AcxConnTypeAtapiInternal; + jackCfg.Description.GeoLocation = AcxGeoLocFront; + jackCfg.Description.GenLocation = AcxGenLocPrimaryBox; + jackCfg.Description.PortConnection = AcxPortConnIntegratedDevice; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, JACK_CONTEXT); + attributes.ParentObject = pin[CodecRenderBridgePin]; + + RETURN_NTSTATUS_IF_FAILED(AcxJackCreate(pin[CodecRenderBridgePin], &attributes, &jackCfg, &jack)); + + ASSERT(jack != nullptr); + + jackCtx = GetJackContext(jack); + ASSERT(jackCtx); + jackCtx->Dummy = 0; + + RETURN_NTSTATUS_IF_FAILED(AcxPinAddJacks(pin[CodecRenderBridgePin], &jack, 1)); + } + + RETURN_NTSTATUS_IF_FAILED(Render_AllocateSupportedFormats(Device, pin, circuit, CodecRenderPinCount)); + + /////////////////////////////////////////////////////////// + // + // The driver uses this DDI post circuit creation to add ACXPINs. + // + RETURN_NTSTATUS_IF_FAILED(AcxCircuitAddPins(circuit, pin, CodecRenderPinCount)); + + // + // Set output value. + // + *Circuit = circuit; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +_Use_decl_annotations_ +NTSTATUS +CodecR_EvtCircuitPowerUp( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE PreviousState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(PreviousState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +NTSTATUS +CodecR_EvtCircuitPowerDown( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ WDF_POWER_DEVICE_STATE TargetState +) +{ + UNREFERENCED_PARAMETER(Device); + UNREFERENCED_PARAMETER(Circuit); + UNREFERENCED_PARAMETER(TargetState); + + PAGED_CODE(); + + return STATUS_SUCCESS; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtCircuitCreateStream( + _In_ WDFDEVICE Device, + _In_ ACXCIRCUIT Circuit, + _In_ ACXPIN Pin, + _In_ PACXSTREAM_INIT StreamInit, + _In_ ACXDATAFORMAT StreamFormat, + _In_ const GUID* SignalProcessingMode, + _In_ ACXOBJECTBAG VarArguments +) +/*++ + +Routine Description: + + This routine creates a stream for the specified circuit. + +Return Value: + + NT status value + +--*/ +{ + NTSTATUS status; + PRENDER_DEVICE_CONTEXT devCtx; + WDF_OBJECT_ATTRIBUTES attributes; + ACXSTREAM stream; + STREAMENGINE_CONTEXT * streamCtx; + ACX_STREAM_CALLBACKS streamCallbacks; + ACX_RT_STREAM_CALLBACKS rtCallbacks; + CRenderStreamEngine* renderStreamEngine = nullptr; + CODEC_PIN_TYPE codecPinType; + PCODEC_PIN_CONTEXT pinCtx; + ACX_PIN_TYPE pinType; + CODEC_RENDER_CIRCUIT_CONTEXT* circuitCtx; + + auto streamEngineScope = scope_exit([&renderStreamEngine]() { + + delete renderStreamEngine; + + }); + + PAGED_CODE(); + UNREFERENCED_PARAMETER(SignalProcessingMode); + UNREFERENCED_PARAMETER(VarArguments); + + ASSERT(IsEqualGUID(*SignalProcessingMode, AUDIO_SIGNALPROCESSINGMODE_RAW)); + + ASSERT(Circuit != nullptr); + circuitCtx = GetRenderCircuitContext(Circuit); + ASSERT(circuitCtx); + + devCtx = GetRenderDeviceContext(Device); + ASSERT(devCtx != nullptr); + UNREFERENCED_PARAMETER(devCtx); + + pinCtx = GetCodecPinContext(Pin); + codecPinType = pinCtx->CodecPinType; + + pinType = AcxPinGetType(Pin); + + // + // Init streaming callbacks. + // + ACX_STREAM_CALLBACKS_INIT(&streamCallbacks); + streamCallbacks.EvtAcxStreamPrepareHardware = EvtStreamPrepareHardware; + streamCallbacks.EvtAcxStreamReleaseHardware = EvtStreamReleaseHardware; + streamCallbacks.EvtAcxStreamRun = EvtStreamRun; + streamCallbacks.EvtAcxStreamPause = EvtStreamPause; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxStreamCallbacks(StreamInit, &streamCallbacks)); + + // + // Init RT streaming callbacks. + // + ACX_RT_STREAM_CALLBACKS_INIT(&rtCallbacks); + rtCallbacks.EvtAcxStreamGetHwLatency = EvtStreamGetHwLatency; + rtCallbacks.EvtAcxStreamAllocateRtPackets = EvtStreamAllocateRtPackets; + rtCallbacks.EvtAcxStreamFreeRtPackets = EvtStreamFreeRtPackets; + rtCallbacks.EvtAcxStreamSetRenderPacket = CodecR_EvtStreamSetRenderPacket; + rtCallbacks.EvtAcxStreamGetCurrentPacket = EvtStreamGetCurrentPacket; + rtCallbacks.EvtAcxStreamGetPresentationPosition = EvtStreamGetPresentationPosition; + + RETURN_NTSTATUS_IF_FAILED(AcxStreamInitAssignAcxRtStreamCallbacks(StreamInit, &rtCallbacks)); + + // + // Buffer notifications are supported. + // + AcxStreamInitSetAcxRtStreamSupportsNotifications(StreamInit); + + // + // Create the stream. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, STREAMENGINE_CONTEXT); + attributes.EvtDestroyCallback = EvtStreamDestroy; + RETURN_NTSTATUS_IF_FAILED(AcxRtStreamCreate(Device, Circuit, &attributes, &StreamInit, &stream)); + + // + // Create the virtual streaming engine which will control + // streaming logic for the render circuit. + // + renderStreamEngine = new (POOL_FLAG_NON_PAGED, DeviceDriverTag) CRenderStreamEngine(stream, StreamFormat, FALSE, NULL); + RETURN_NTSTATUS_IF_TRUE(renderStreamEngine == nullptr, STATUS_INSUFFICIENT_RESOURCES); + + streamCtx = GetStreamEngineContext(stream); + ASSERT(streamCtx); + streamCtx->StreamEngine = (PVOID)renderStreamEngine; + + renderStreamEngine = nullptr; + + // + // Done. + // + status = STATUS_SUCCESS; + + return status; +} + +PAGED_CODE_SEG +NTSTATUS +CodecR_EvtStreamSetRenderPacket( + _In_ ACXSTREAM Stream, + _In_ ULONG Packet, + _In_ ULONG Flags, + _In_ ULONG EosPacketLength +) +{ + PSTREAMENGINE_CONTEXT ctx; + CRenderStreamEngine* streamEngine = nullptr; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = static_cast(ctx->StreamEngine); + + return streamEngine->SetRenderPacket(Packet, Flags, EosPacketLength); +} + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj b/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj new file mode 100644 index 000000000..ce54f8ead --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj @@ -0,0 +1,179 @@ + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + {6A946D59-6690-4ED0-A77D-7D4C3D4B3241} + {497e31cb-056b-4f31-abb8-447fd55ee5a5} + v4.5 + 12.0 + Debug + SamplesCommon + $(LatestTargetPlatformVersion) + + + + Windows10 + true + WindowsKernelModeDriver10.0 + StaticLibrary + KMDF + Windows Driver + 1 + 31 + + + Windows10 + false + WindowsKernelModeDriver10.0 + StaticLibrary + KMDF + Windows Driver + 1 + 31 + + + Windows10 + true + WindowsKernelModeDriver10.0 + StaticLibrary + KMDF + Windows Driver + 1 + 31 + + + Windows10 + false + WindowsKernelModeDriver10.0 + StaticLibrary + KMDF + Windows Driver + 1 + 31 + + + + + + + + + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + DbgengKernelDebugger + $(IntDir) + + + + true + true + trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\1.1;..\inc;..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + + + true + true + trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\1.1;..\inc;..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + + + true + true + trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\1.1;..\inc;..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + + + true + true + trace_macros.h + true + $(SDK_INC_PATH);$(DDK_INC_PATH)\acx\km\1.1;..\inc;..\shared;%(AdditionalIncludeDirectories) + ACX_VERSION_MAJOR=1;ACX_VERSION_MINOR=1;KMDF_VERSION_MAJOR=1;KMDF_VERSION_MINOR=31;%(PreprocessorDefinitions) + + + sha256 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.cpp new file mode 100644 index 000000000..96b9493b8 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.cpp @@ -0,0 +1,1103 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + SaveData.cpp + +Abstract: + + Implementation of data saving class for ACX driver samples. + + To save the playback data to disk, this class maintains a circular data + buffer, associated frame structures and worker items to save frames to + disk. + Each frame structure represents a portion of buffer. When that portion + of frame is full, a workitem is scheduled to save it to disk. + + + +--*/ +#pragma warning (disable : 4127) +#pragma warning (disable : 26165) + + +#include "private.h" +#include +#include +#include +#include +#include "savedata.h" +#include // This is for using RtlStringCbPrintf + +#define SAVEDATA_POOLTAG 'TDVS' +#define SAVEDATA_POOLTAG1 '1DVS' +#define SAVEDATA_POOLTAG2 '2DVS' +#define SAVEDATA_POOLTAG3 '3DVS' +#define SAVEDATA_POOLTAG4 '4DVS' +#define SAVEDATA_POOLTAG5 '5DVS' +#define SAVEDATA_POOLTAG6 '6DVS' +#define SAVEDATA_POOLTAG7 '7DVS' + +//============================================================================= +// Defines +//============================================================================= +#define RIFF_TAG 0x46464952; +#define WAVE_TAG 0x45564157; +#define FMT__TAG 0x20746D66; +#define DATA_TAG 0x61746164; + +#define DEFAULT_FRAME_COUNT 4 +#define DEFAULT_FRAME_SIZE PAGE_SIZE * 4 +#define DEFAULT_BUFFER_SIZE DEFAULT_FRAME_SIZE * DEFAULT_FRAME_COUNT + +#define DEFAULT_FILE_FOLDER1 L"\\DriverData\\Audio_Samples" +#define DEFAULT_FILE_FOLDER2 L"\\DriverData\\Audio_Samples\\AudioCodec" +#define DEFAULT_FILE_NAME L"\\DriverData\\Audio_Samples\\AudioCodec\\STREAM" +#define OFFLOAD_FILE_NAME L"OFFLOAD" +#define HOST_FILE_NAME L"HOST" + +#define MAX_WORKER_ITEM_COUNT 15 + + +PSAVEWORKER_PARAM CSaveData::m_pWorkItems = NULL; +PDEVICE_OBJECT CSaveData::m_pDeviceObject = NULL; + +//============================================================================= +// Statics +//============================================================================= +ULONG CSaveData::m_ulStreamId = 0; +ULONG CSaveData::m_ulOffloadStreamId = 0; + +//============================================================================= +// CSaveData +//============================================================================= + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +CSaveData::CSaveData() +: m_pDataBuffer(NULL), + m_FileHandle(NULL), + m_ulFrameCount(DEFAULT_FRAME_COUNT), + m_ulBufferSize(DEFAULT_BUFFER_SIZE), + m_ulFrameSize(DEFAULT_FRAME_SIZE), + m_ulBufferOffset(0), + m_ulFrameIndex(0), + m_fFrameUsed(NULL), + m_waveFormat(NULL), + m_pFilePtr(NULL), + m_fWriteDisabled(FALSE), + m_bInitialized(FALSE) +{ + PAGED_CODE(); + + m_FileHeader.dwRiff = RIFF_TAG; + m_FileHeader.dwFileSize = 0; + m_FileHeader.dwWave = WAVE_TAG; + m_FileHeader.dwFormat = FMT__TAG; + m_FileHeader.dwFormatLength = sizeof(WAVEFORMATEX); + + m_DataHeader.dwData = DATA_TAG; + m_DataHeader.dwDataLength = 0; + + RtlZeroMemory(&m_objectAttributes, sizeof(m_objectAttributes)); +} // CSaveData + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +CSaveData::~CSaveData() +{ + PAGED_CODE(); + Cleanup(); +} // CSaveData + +void +_Use_decl_annotations_ +PAGED_CODE_SEG +CSaveData::Cleanup +( + void +) +{ + PAGED_CODE(); + + // Update the wave header in data file with real file size. + // + if(m_pFilePtr) + { + // RIFF header, whose size is the whole file size minus RIFF header. + m_FileHeader.dwFileSize = + (DWORD)m_pFilePtr->QuadPart - 2 * sizeof(DWORD); + // The data length is the size of all the audio that was written. + // It gets calculated by taking: + m_DataHeader.dwDataLength = (DWORD)m_pFilePtr->QuadPart - // the whole file size, + sizeof(m_FileHeader) - // minus the file header, + m_FileHeader.dwFormatLength - // minus the format, + sizeof(m_DataHeader); // minus the data header itself. + + if (STATUS_SUCCESS == KeWaitForSingleObject + ( + &m_FileSync, + Executive, + KernelMode, + FALSE, + NULL + )) + { + if (NT_SUCCESS(FileOpen(FALSE))) + { + FileWriteHeader(); + + FileClose(); + } + + KeReleaseMutex(&m_FileSync, FALSE); + } + + m_FileHeader.dwRiff = RIFF_TAG; + m_FileHeader.dwFileSize = 0; + m_FileHeader.dwWave = WAVE_TAG; + m_FileHeader.dwFormat = FMT__TAG; + m_FileHeader.dwFormatLength = sizeof(WAVEFORMATEX); + + m_DataHeader.dwData = DATA_TAG; + m_DataHeader.dwDataLength = 0; + m_pFilePtr = NULL; + } + + if (m_waveFormat) + { + ExFreePoolWithTag(m_waveFormat, SAVEDATA_POOLTAG1); + m_waveFormat = NULL; + } + + if (m_fFrameUsed) + { + ExFreePoolWithTag(m_fFrameUsed, SAVEDATA_POOLTAG2); + m_fFrameUsed = NULL; + } + + if (m_FileName.Buffer) + { + ExFreePoolWithTag(m_FileName.Buffer, SAVEDATA_POOLTAG3); + m_FileName.Buffer = NULL; + } + + if (m_pDataBuffer) + { + ExFreePoolWithTag(m_pDataBuffer, SAVEDATA_POOLTAG4); + m_pDataBuffer = NULL; + } +} + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +void +CSaveData::DestroyWorkItems +( + void +) +{ + PAGED_CODE(); + + if (m_pWorkItems) + { + for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++) + { + if (m_pWorkItems[i].WorkItem!=NULL) + { + IoFreeWorkItem(m_pWorkItems[i].WorkItem); + m_pWorkItems[i].WorkItem = NULL; + } + } + ExFreePoolWithTag(m_pWorkItems, SAVEDATA_POOLTAG); + m_pWorkItems = NULL; + } + +} // DestroyWorkItems + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +void +CSaveData::Disable +( + _In_ BOOL fDisable +) +{ + PAGED_CODE(); + + m_fWriteDisabled = fDisable; +} // Disable + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::FileClose(void) +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (m_FileHandle) + { + ntStatus = ZwClose(m_FileHandle); + m_FileHandle = NULL; + } + + return ntStatus; +} // FileClose + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::FileOpen +( + _In_ BOOL fOverWrite +) +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STATUS_BLOCK ioStatusBlock; + + if( FALSE == m_bInitialized ) + { + return STATUS_UNSUCCESSFUL; + } + + if(!m_FileHandle) + { + ntStatus = + ZwCreateFile + ( + &m_FileHandle, + GENERIC_WRITE | SYNCHRONIZE, + &m_objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + fOverWrite ? FILE_OVERWRITE_IF : FILE_OPEN_IF, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + } + + return ntStatus; +} // FileOpen + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::FileWrite +( + _In_reads_bytes_(ulDataSize) PBYTE pData, + _In_ ULONG ulDataSize +) +{ + PAGED_CODE(); + + ASSERT(pData); + ASSERT(m_pFilePtr); + + NTSTATUS ntStatus; + + if (m_FileHandle) + { + IO_STATUS_BLOCK ioStatusBlock; + + ntStatus = ZwWriteFile( m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + pData, + ulDataSize, + m_pFilePtr, + NULL); + + if (NT_SUCCESS(ntStatus)) + { + ASSERT(ioStatusBlock.Information == ulDataSize); + + m_pFilePtr->QuadPart += ulDataSize; + } + } + else + { + ntStatus = STATUS_INVALID_HANDLE; + } + + return ntStatus; +} // FileWrite + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::FileWriteHeader(void) +{ + PAGED_CODE(); + + NTSTATUS ntStatus; + + if (m_FileHandle && m_waveFormat) + { + IO_STATUS_BLOCK ioStatusBlock; + + m_pFilePtr->QuadPart = 0; + + m_FileHeader.dwFormatLength = (m_waveFormat->wFormatTag == WAVE_FORMAT_PCM) ? + sizeof( PCMWAVEFORMAT ) : + sizeof( WAVEFORMATEX ) + m_waveFormat->cbSize; + + ntStatus = ZwWriteFile( m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + &m_FileHeader, + sizeof(m_FileHeader), + m_pFilePtr, + NULL); + + if (NT_SUCCESS(ntStatus)) + { + m_pFilePtr->QuadPart += sizeof(m_FileHeader); + + ntStatus = ZwWriteFile( m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + m_waveFormat, + m_FileHeader.dwFormatLength, + m_pFilePtr, + NULL); + } + + if (NT_SUCCESS(ntStatus)) + { + m_pFilePtr->QuadPart += m_FileHeader.dwFormatLength; + + ntStatus = ZwWriteFile( m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + &m_DataHeader, + sizeof(m_DataHeader), + m_pFilePtr, + NULL); + } + + if (NT_SUCCESS(ntStatus)) + { + m_pFilePtr->QuadPart += sizeof(m_DataHeader); + } + } + else + { + ntStatus = STATUS_INVALID_HANDLE; + } + + + return ntStatus; +} // FileWriteHeader + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::SetDeviceObject +( + _In_ PDEVICE_OBJECT DeviceObject +) +{ + PAGED_CODE(); + + ASSERT(DeviceObject); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + m_pDeviceObject = DeviceObject; + return ntStatus; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +PDEVICE_OBJECT +CSaveData::GetDeviceObject +( + void +) +{ + PAGED_CODE(); + + return m_pDeviceObject; +} + +//============================================================================= +_Use_decl_annotations_ +PSAVEWORKER_PARAM +CSaveData::GetNewWorkItem +( + void +) +{ + LARGE_INTEGER timeOut = { 0 }; + NTSTATUS ntStatus; + + for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++) + { + ntStatus = + KeWaitForSingleObject + ( + &m_pWorkItems[i].EventDone, + Executive, + KernelMode, + FALSE, + &timeOut + ); + if (STATUS_SUCCESS == ntStatus) + { + if (m_pWorkItems[i].WorkItem) + return &(m_pWorkItems[i]); + else + return NULL; + } + } + + return NULL; +} // GetNewWorkItem + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::Initialize +( + _In_ BOOL _bOffloaded +) +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + WCHAR szTemp[MAX_PATH]; + size_t cLen = 0; + IO_STATUS_BLOCK ioStatusBlock = {0}; + HANDLE fileHandle; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING fileName; + + if (_bOffloaded) + { + m_ulOffloadStreamId++; + } + else + { + m_ulStreamId++; + } + + RtlInitUnicodeString(&fileName, DEFAULT_FILE_FOLDER1); + InitializeObjectAttributes( + &objectAttributes, + &fileName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + // Create the folder. + ntStatus = ZwCreateFile( + &fileHandle, + 0, + &objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN_IF, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + if (NT_SUCCESS(ntStatus)) + { + ZwClose(fileHandle); + fileHandle = NULL; + + RtlInitUnicodeString(&fileName, DEFAULT_FILE_FOLDER2); + InitializeObjectAttributes( + &objectAttributes, + &fileName, + OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + // Create the folder. + ntStatus = ZwCreateFile( + &fileHandle, + 0, + &objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + 0, + FILE_OPEN_IF, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0); + + if (NT_SUCCESS(ntStatus)) + { + ZwClose(fileHandle); + fileHandle = NULL; + } + } + + if (NT_SUCCESS(ntStatus)) + { + // Allocate data file name. + // + RtlStringCchPrintfW(szTemp, MAX_PATH, L"%s_%s_%d.wav", DEFAULT_FILE_NAME, _bOffloaded ? OFFLOAD_FILE_NAME : HOST_FILE_NAME, _bOffloaded ? m_ulOffloadStreamId : m_ulStreamId); + m_FileName.Length = 0; + ntStatus = RtlStringCchLengthW (szTemp, sizeof(szTemp)/sizeof(szTemp[0]), &cLen); + } + + if (NT_SUCCESS(ntStatus)) + { + m_FileName.MaximumLength = (USHORT)((cLen * sizeof(WCHAR)) + sizeof(WCHAR));//convert to wchar and add room for NULL + m_FileName.Buffer = (PWSTR) + ExAllocatePool2 + ( + POOL_FLAG_PAGED, + m_FileName.MaximumLength, + SAVEDATA_POOLTAG3 + ); + if (!m_FileName.Buffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + + // Allocate memory for data buffer. + // + if (NT_SUCCESS(ntStatus)) + { + RtlStringCbCopyW(m_FileName.Buffer, m_FileName.MaximumLength, szTemp); + m_FileName.Length = (USHORT)wcslen(m_FileName.Buffer) * sizeof(WCHAR); + + m_pDataBuffer = (PBYTE) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + m_ulBufferSize, + SAVEDATA_POOLTAG4 + ); + if (!m_pDataBuffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + + // Allocate memory for frame usage flags and m_pFilePtr. + // + if (NT_SUCCESS(ntStatus)) + { + m_fFrameUsed = (PBOOL) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + m_ulFrameCount * sizeof(BOOL) + + sizeof(LARGE_INTEGER), + SAVEDATA_POOLTAG2 + ); + if (!m_fFrameUsed) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + + // Initialize the spinlock to synchronize access to the frames + // + KeInitializeSpinLock ( &m_FrameInUseSpinLock ) ; + + // Initialize the file mutex + // + KeInitializeMutex( &m_FileSync, 1 ) ; + + // Open the data file. + // + if (NT_SUCCESS(ntStatus)) + { + // m_fFrameUsed has additional memory to hold m_pFilePtr + // + m_pFilePtr = (PLARGE_INTEGER) + (((PBYTE) m_fFrameUsed) + m_ulFrameCount * sizeof(BOOL)); + + // Create data file. + InitializeObjectAttributes + ( + &m_objectAttributes, + &m_FileName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + + m_bInitialized = TRUE; + + // Write wave header information to data file. + ntStatus = KeWaitForSingleObject + ( + &m_FileSync, + Executive, + KernelMode, + FALSE, + NULL + ); + + if (STATUS_SUCCESS == ntStatus) + { + ntStatus = FileOpen(TRUE); + if (NT_SUCCESS(ntStatus)) + { + ntStatus = FileWriteHeader(); + + FileClose(); + } + + KeReleaseMutex( &m_FileSync, FALSE ); + } + } + + return ntStatus; +} // Initialize + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::InitializeWorkItems +( + _In_ PDEVICE_OBJECT DeviceObject +) +{ + PAGED_CODE(); + + ASSERT(DeviceObject); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (m_pWorkItems != NULL) + { + return ntStatus; + } + + m_pWorkItems = (PSAVEWORKER_PARAM) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + sizeof(SAVEWORKER_PARAM) * MAX_WORKER_ITEM_COUNT, + SAVEDATA_POOLTAG + ); + if (m_pWorkItems) + { + for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++) + { + + m_pWorkItems[i].WorkItem = IoAllocateWorkItem(DeviceObject); + if(m_pWorkItems[i].WorkItem == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + KeInitializeEvent + ( + &m_pWorkItems[i].EventDone, + NotificationEvent, + TRUE + ); + } + } + else + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + + return ntStatus; +} // InitializeWorkItems + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +SaveFrameWorkerCallback +( + _In_ PDEVICE_OBJECT pDeviceObject, + _In_opt_ PVOID Context +) +{ + UNREFERENCED_PARAMETER(pDeviceObject); + + PAGED_CODE(); + + ASSERT(Context); + + PSAVEWORKER_PARAM pParam = (PSAVEWORKER_PARAM) Context; + PCSaveData pSaveData; + + if (NULL == pParam) + { + // This is completely unexpected, assert here. + // + ASSERT(pParam); + return; + } + + ASSERT(pParam->pSaveData); + ASSERT(pParam->pSaveData->m_fFrameUsed); + + if (pParam->WorkItem) + { + pSaveData = pParam->pSaveData; + + if (STATUS_SUCCESS == KeWaitForSingleObject + ( + &pSaveData->m_FileSync, + Executive, + KernelMode, + FALSE, + NULL + )) + { + if (NT_SUCCESS(pSaveData->FileOpen(FALSE))) + { + pSaveData->FileWrite(pParam->pData, pParam->ulDataSize); + pSaveData->FileClose(); + } + InterlockedExchange( (LONG *)&(pSaveData->m_fFrameUsed[pParam->ulFrameNo]), FALSE ); + + KeReleaseMutex( &pSaveData->m_FileSync, FALSE ); + } + } + + KeSetEvent(&pParam->EventDone, 0, FALSE); +} // SaveFrameWorkerCallback + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::SetDataFormat +( + _In_ PKSDATAFORMAT pDataFormat +) +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + + ASSERT(pDataFormat); + + PWAVEFORMATEX pwfx = NULL; + + if (IsEqualGUIDAligned(pDataFormat->Specifier, + KSDATAFORMAT_SPECIFIER_DSOUND)) + { + pwfx = + &(((PKSDATAFORMAT_DSOUND) pDataFormat)->BufferDesc.WaveFormatEx); + } + else if (IsEqualGUIDAligned(pDataFormat->Specifier, + KSDATAFORMAT_SPECIFIER_WAVEFORMATEX)) + { + pwfx = &((PKSDATAFORMAT_WAVEFORMATEX) pDataFormat)->WaveFormatEx; + } + + if (pwfx) + { + // Free the previously allocated waveformat + if (m_waveFormat) + { + ExFreePoolWithTag(m_waveFormat, SAVEDATA_POOLTAG1); + } + + m_waveFormat = (PWAVEFORMATEX) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + (pwfx->wFormatTag == WAVE_FORMAT_PCM) ? + sizeof( PCMWAVEFORMAT ) : + sizeof( WAVEFORMATEX ) + pwfx->cbSize, + SAVEDATA_POOLTAG1 + ); + + if(m_waveFormat) + { + RtlCopyMemory( m_waveFormat, + pwfx, + (pwfx->wFormatTag == WAVE_FORMAT_PCM) ? + sizeof( PCMWAVEFORMAT ) : + sizeof( WAVEFORMATEX ) + pwfx->cbSize); + } + else + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + } + return ntStatus; +} // SetDataFormat + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CSaveData::SetMaxWriteSize +( + _In_ ULONG ulMaxWriteSize +) +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + ULONG bufferSize = 0; + PBYTE buffer = NULL; + + // + // Compute new buffer size. + // + ntStatus = RtlULongMult(ulMaxWriteSize, DEFAULT_FRAME_COUNT, &bufferSize); + if (!NT_SUCCESS(ntStatus)) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // + // Alloc memory for buffer. + // + buffer = (PBYTE) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + bufferSize, + SAVEDATA_POOLTAG4 + ); + if (!buffer) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // + // Free old one. + // + if (m_pDataBuffer) + { + ExFreePoolWithTag(m_pDataBuffer, SAVEDATA_POOLTAG4); + m_pDataBuffer = NULL; + } + + // + // Init new buffer settings. + // + m_pDataBuffer = buffer; + m_ulBufferSize = bufferSize; + m_ulFrameSize = ulMaxWriteSize; + + ntStatus = STATUS_SUCCESS; + +Done: + return ntStatus; +} // SetDataFormat + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +void +CSaveData::ReadData +( + _Inout_updates_bytes_all_(ulByteCount) PBYTE pBuffer, + _In_ ULONG ulByteCount +) +{ + UNREFERENCED_PARAMETER(pBuffer); + UNREFERENCED_PARAMETER(ulByteCount); + + PAGED_CODE(); + + // Not implemented yet. +} // ReadData + +//============================================================================= +_Use_decl_annotations_ +void +CSaveData::SaveFrame +( + _In_ ULONG ulFrameNo, + _In_ ULONG ulDataSize +) +{ + PSAVEWORKER_PARAM pParam = NULL; + + pParam = GetNewWorkItem(); + if (pParam) + { + pParam->pSaveData = this; + pParam->ulFrameNo = ulFrameNo; + pParam->ulDataSize = ulDataSize; + pParam->pData = m_pDataBuffer + ulFrameNo * m_ulFrameSize; + KeResetEvent(&pParam->EventDone); + IoQueueWorkItem(pParam->WorkItem, SaveFrameWorkerCallback, + CriticalWorkQueue, (PVOID)pParam); + } +} // SaveFrame + +//============================================================================= +void +_Use_decl_annotations_ +PAGED_CODE_SEG +CSaveData::WaitAllWorkItems +( + void +) +{ + PAGED_CODE(); + + // Save the last partially-filled frame + if (m_ulBufferOffset > m_ulFrameIndex * m_ulFrameSize) + { + ULONG size; + + size = m_ulBufferOffset - m_ulFrameIndex * m_ulFrameSize; + SaveFrame(m_ulFrameIndex, size); + } + + for (int i = 0; i < MAX_WORKER_ITEM_COUNT; i++) + { + KeWaitForSingleObject + ( + &(m_pWorkItems[i].EventDone), + Executive, + KernelMode, + FALSE, + NULL + ); + } +} // WaitAllWorkItems + +//============================================================================= +_Use_decl_annotations_ +void +CSaveData::WriteData +( + _In_reads_bytes_(ulByteCount) PBYTE pBuffer, + _In_ ULONG ulByteCount +) +{ + ASSERT(pBuffer); + + BOOL fSaveFrame = FALSE; + ULONG ulSaveFrameIndex = 0; + KIRQL oldIrql; + + // If stream writing is disabled, then exit. + // + if (m_fWriteDisabled) + { + return; + } + + if( 0 == ulByteCount ) + { + return; + } + + // The logic below assumes that write size is <= than frame size. + if (ulByteCount > m_ulFrameSize) + { + ulByteCount = m_ulFrameSize; + } + + // Check to see if this frame is available. + KeAcquireSpinLock(&m_FrameInUseSpinLock, &oldIrql); + if (!m_fFrameUsed[m_ulFrameIndex]) + { + KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql ); + + ULONG ulWriteBytes = ulByteCount; + + if( (m_ulBufferSize - m_ulBufferOffset) < ulWriteBytes ) + { + ulWriteBytes = m_ulBufferSize - m_ulBufferOffset; + } + + RtlCopyMemory(m_pDataBuffer + m_ulBufferOffset, pBuffer, ulWriteBytes); + m_ulBufferOffset += ulWriteBytes; + + // Check to see if we need to save this frame + if (m_ulBufferOffset >= ((m_ulFrameIndex + 1) * m_ulFrameSize)) + { + fSaveFrame = TRUE; + } + + // Loop the buffer, if we reached the end. + if (m_ulBufferOffset == m_ulBufferSize) + { + fSaveFrame = TRUE; + m_ulBufferOffset = 0; + } + + if (fSaveFrame) + { + InterlockedExchange( (LONG *)&(m_fFrameUsed[m_ulFrameIndex]), TRUE ); + ulSaveFrameIndex = m_ulFrameIndex; + m_ulFrameIndex = (m_ulFrameIndex + 1) % m_ulFrameCount; + } + + // Write the left over if the next frame is available. + if (ulWriteBytes != ulByteCount) + { + KeAcquireSpinLock(&m_FrameInUseSpinLock, &oldIrql ); + if (!m_fFrameUsed[m_ulFrameIndex]) + { + KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql ); + RtlCopyMemory + ( + m_pDataBuffer + m_ulBufferOffset, + pBuffer + ulWriteBytes, + ulByteCount - ulWriteBytes + ); + + m_ulBufferOffset += ulByteCount - ulWriteBytes; + } + else + { + KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql); + } + } + + if (fSaveFrame) + { + SaveFrame(ulSaveFrameIndex, m_ulFrameSize); + } + } + else + { + KeReleaseSpinLock(&m_FrameInUseSpinLock, oldIrql ); + } + +} // WriteData + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.h b/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.h new file mode 100644 index 000000000..21beab4ad --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SaveData.h @@ -0,0 +1,259 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + SaveData.h + +Abstract: + + Declaration of data saving class for ACX driver samples. This class supplies services +to save data to disk. + + +--*/ + +#pragma once + +//----------------------------------------------------------------------------- +// Forward declaration +//----------------------------------------------------------------------------- +class CSaveData; +typedef CSaveData *PCSaveData; + + +//----------------------------------------------------------------------------- +// Structs +//----------------------------------------------------------------------------- + +// Parameter to workitem. +#include +typedef struct _SAVEWORKER_PARAM { + PIO_WORKITEM WorkItem; + ULONG ulFrameNo; + ULONG ulDataSize; + PBYTE pData; + PCSaveData pSaveData; + KEVENT EventDone; +} SAVEWORKER_PARAM; +typedef SAVEWORKER_PARAM *PSAVEWORKER_PARAM; +#include + +// wave file header. +#include +typedef struct _OUTPUT_FILE_HEADER +{ + DWORD dwRiff; + DWORD dwFileSize; + DWORD dwWave; + DWORD dwFormat; + DWORD dwFormatLength; +} OUTPUT_FILE_HEADER; +typedef OUTPUT_FILE_HEADER *POUTPUT_FILE_HEADER; + +typedef struct _OUTPUT_DATA_HEADER +{ + DWORD dwData; + DWORD dwDataLength; +} OUTPUT_DATA_HEADER; +typedef OUTPUT_DATA_HEADER *POUTPUT_DATA_HEADER; + +#include + +//----------------------------------------------------------------------------- +// Classes +//----------------------------------------------------------------------------- + +/////////////////////////////////////////////////////////////////////////////// +// CSaveData +// Saves the wave data to disk. +// +__drv_maxIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +IO_WORKITEM_ROUTINE SaveFrameWorkerCallback; + +class CSaveData +{ +protected: + UNICODE_STRING m_FileName; // DataFile name. + HANDLE m_FileHandle; // DataFile handle. + PBYTE m_pDataBuffer; // Data buffer. + ULONG m_ulBufferSize; // Total buffer size. + + ULONG m_ulFrameIndex; // Current Frame. + ULONG m_ulFrameCount; // Frame count. + ULONG m_ulFrameSize; + ULONG m_ulBufferOffset; // index in buffer. + PBOOL m_fFrameUsed; // Frame usage table. + KSPIN_LOCK m_FrameInUseSpinLock; // Spinlock for synch. + KMUTEX m_FileSync; // Synchronizes file access + + OBJECT_ATTRIBUTES m_objectAttributes; // Used for opening file. + + OUTPUT_FILE_HEADER m_FileHeader; + PWAVEFORMATEX m_waveFormat; + OUTPUT_DATA_HEADER m_DataHeader; + PLARGE_INTEGER m_pFilePtr; + + static PDEVICE_OBJECT m_pDeviceObject; + static ULONG m_ulStreamId; + static ULONG m_ulOffloadStreamId; + static PSAVEWORKER_PARAM m_pWorkItems; + + BOOL m_fWriteDisabled; + + BOOL m_bInitialized; + +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CSaveData(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CSaveData(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void + Cleanup( + void + ); + + static + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + InitializeWorkItems( + _In_ PDEVICE_OBJECT DeviceObject + ); + + static + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void + DestroyWorkItems( + void + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void + Disable( + _In_ BOOL fDisable + ); + + static + __drv_maxIRQL(DISPATCH_LEVEL) + PSAVEWORKER_PARAM + GetNewWorkItem( + void + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Initialize( + _In_ BOOL _bOffloaded + ); + + static + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetDeviceObject( + _In_ PDEVICE_OBJECT DeviceObject + ); + + static + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + PDEVICE_OBJECT + GetDeviceObject( + void + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void + ReadData( + _Inout_updates_bytes_all_(ulByteCount) PBYTE pBuffer, + _In_ ULONG ulByteCount + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetDataFormat( + _In_ PKSDATAFORMAT pDataFormat + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetMaxWriteSize( + _In_ ULONG ulMaxWriteSize + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void + WaitAllWorkItems( + void + ); + + __drv_maxIRQL(DISPATCH_LEVEL) + void + WriteData( + _In_reads_bytes_(ulByteCount) PBYTE pBuffer, + _In_ ULONG ulByteCount + ); + +private: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + FileClose( + void + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + FileOpen( + _In_ BOOL fOverWrite + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + FileWrite( + _In_reads_bytes_(ulDataSize) PBYTE pData, + _In_ ULONG ulDataSize + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + FileWriteHeader( + void + ); + + __drv_maxIRQL(DISPATCH_LEVEL) + void + SaveFrame( + _In_ ULONG ulFrameNo, + _In_ ULONG ulDataSize + ); + + friend + IO_WORKITEM_ROUTINE SaveFrameWorkerCallback; +}; +typedef CSaveData *PCSaveData; + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.cpp new file mode 100644 index 000000000..05f7fe05e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.cpp @@ -0,0 +1,106 @@ +/*++ + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + SimPeakMeter.cpp + +Abstract: + + Virtual Peakmeter - aggregates all streams + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "SimPeakMeter.h" + +#ifndef __INTELLISENSE__ +#include "SimPeakMeter.tmh" +#endif + +_Use_decl_annotations_ +PAGED_CODE_SEG +CSimPeakMeter::CSimPeakMeter() +{ + PAGED_CODE(); + m_NumStreams = 0; + m_PeakMeterIndex = 0; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CSimPeakMeter::~CSimPeakMeter() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +LONG CSimPeakMeter::GetValue(ULONG Channel) +{ + PAGED_CODE(); + + // Ignore channel + UNREFERENCED_PARAMETER(Channel); + +#define PEAKMETER_VALUE_FULL (PEAKMETER_MAXIMUM / PEAKMETER_STEPPING_DELTA * PEAKMETER_STEPPING_DELTA) +#define PEAKMETER_VALUE_HALF (PEAKMETER_MAXIMUM / 2 / PEAKMETER_STEPPING_DELTA * PEAKMETER_STEPPING_DELTA) +#define PEAKMETER_VALUE_QUARTER (PEAKMETER_MAXIMUM / 4 / PEAKMETER_STEPPING_DELTA * PEAKMETER_STEPPING_DELTA) +#define PEAKMETER_VALUE_ONE_EIGTH (PEAKMETER_MAXIMUM / 8 / PEAKMETER_STEPPING_DELTA * PEAKMETER_STEPPING_DELTA) + + LONG PeakMeterValues[] = { + PEAKMETER_VALUE_ONE_EIGTH, + PEAKMETER_VALUE_QUARTER, + PEAKMETER_VALUE_HALF, + PEAKMETER_VALUE_FULL, + PEAKMETER_VALUE_HALF, + PEAKMETER_VALUE_QUARTER + }; + + if (m_NumStreams) + { + LONG pmi = InterlockedIncrement(&m_PeakMeterIndex); + if (pmi == ARRAYSIZE(PeakMeterValues)) + { + pmi = 0; + InterlockedExchange(&m_PeakMeterIndex, 0); + } + + return PeakMeterValues[pmi]; + } + + // + // No active streams. Peak meter = 0 + // + return 0; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CSimPeakMeter::StartStream() +{ + PAGED_CODE(); + InterlockedIncrement(&m_NumStreams); + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CSimPeakMeter::StopStream() +{ + PAGED_CODE(); + + ASSERT(m_NumStreams); + InterlockedDecrement(&m_NumStreams); + + return STATUS_SUCCESS; +} diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.h b/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.h new file mode 100644 index 000000000..3f0828572 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SimPeakMeter.h @@ -0,0 +1,51 @@ +/*++ + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + SimPeakMeter.h + +Abstract: + + Virtual Peakmeter - aggregates all streams + +Environment: + + Kernel mode + +--*/ + +#pragma once + +class CSimPeakMeter +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CSimPeakMeter(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CSimPeakMeter(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + LONG GetValue(_In_ ULONG Channel); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS StartStream(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS StopStream(); + +private: + LONG m_NumStreams; + LONG m_PeakMeterIndex; +}; + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp new file mode 100644 index 000000000..441b53c04 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp @@ -0,0 +1,1345 @@ +/*++ + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + StreamEngine.cpp + +Abstract: + + Virtual Streaming Engine - this module controls streaming logic for + the device. + +Environment: + + Kernel mode + +--*/ + +#include "private.h" +#include "public.h" +#include +#include +#include +#include +#include "streamengine.h" + +#ifndef __INTELLISENSE__ +#include "streamengine.tmh" +#endif + +_Use_decl_annotations_ +PAGED_CODE_SEG +CStreamEngine::CStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ BOOL Offload, + _In_opt_ CSimPeakMeter *CircuitPeakmeter +) + : m_PacketsCount(0), + m_PacketSize(0), + m_FirstPacketOffset(0), + m_NotificationTimer(NULL), + m_CurrentState(AcxStreamStateStop), + m_CurrentPacket(0), + m_Position(0), + m_Stream(Stream), + m_StreamFormat(StreamFormat), + m_StartTime(0), + m_StartPosition(0), + m_GlitchAdjust(0), + m_ToneFrequency(DEFAULT_FREQUENCY), + m_Offload(Offload), + m_pCircuitPeakmeter(CircuitPeakmeter) +{ + PAGED_CODE(); + + KeQueryPerformanceCounter(&m_PerformanceCounterFrequency); + RtlZeroMemory(m_Packets, sizeof(m_Packets)); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CStreamEngine::~CStreamEngine() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::AllocateRtPackets( + _In_ ULONG PacketCount, + _In_ ULONG PacketSize, + _Out_ PACX_RTPACKET* Packets +) +{ + NTSTATUS status = STATUS_SUCCESS; + PACX_RTPACKET packets = NULL; + PVOID packetBuffer = NULL; + ULONG i; + ULONG packetAllocSizeInPages = 0; + ULONG packetAllocSizeInBytes = 0; + ULONG firstPacketOffset = 0; + size_t packetsSize = 0; + + PAGED_CODE(); + + if (PacketCount > MAX_PACKET_COUNT) + { + ASSERT(FALSE); + status = STATUS_INVALID_PARAMETER; + goto exit; + } + + status = RtlSizeTMult(PacketCount, sizeof(ACX_RTPACKET), &packetsSize); + if (!NT_SUCCESS(status)) + { + ASSERT(FALSE); + goto exit; + } + + packets = (PACX_RTPACKET)ExAllocatePool2(POOL_FLAG_NON_PAGED, packetsSize, DeviceDriverTag); + if (!packets) + { + status = STATUS_NO_MEMORY; + ASSERT(FALSE); + goto exit; + } + + // + // We need to allocate page-aligned buffers, to ensure no kernel memory leaks + // to user space. Round up the packet size to page aligned, then calculate + // the first packet's buffer offset so packet 0 ends on a page boundary and + // packet 1 begins on a page boundary. + // + status = RtlULongAdd(PacketSize, PAGE_SIZE - 1, &packetAllocSizeInPages); + if (!NT_SUCCESS(status)) + { + ASSERT(FALSE); + goto exit; + } + packetAllocSizeInPages = packetAllocSizeInPages / PAGE_SIZE; + packetAllocSizeInBytes = PAGE_SIZE * packetAllocSizeInPages; + firstPacketOffset = packetAllocSizeInBytes - PacketSize; + + for (i = 0; i < PacketCount; ++i) + { + PMDL pMdl = NULL; + + ACX_RTPACKET_INIT(&packets[i]); + + packetBuffer = ExAllocatePool2(POOL_FLAG_NON_PAGED, packetAllocSizeInBytes, DeviceDriverTag); + if (packetBuffer == NULL) + { + status = STATUS_NO_MEMORY; + goto exit; + } + + pMdl = IoAllocateMdl(packetBuffer, packetAllocSizeInBytes, FALSE, TRUE, NULL); + if (pMdl == NULL) + { + status = STATUS_NO_MEMORY; + goto exit; + } + + MmBuildMdlForNonPagedPool(pMdl); + + WDF_MEMORY_DESCRIPTOR_INIT_MDL(&((packets)[i].RtPacketBuffer), pMdl, packetAllocSizeInBytes); + + packets[i].RtPacketSize = PacketSize; + if (i == 0) + { + packets[i].RtPacketOffset = firstPacketOffset; + } + else + { + packets[i].RtPacketOffset = 0; + } + m_Packets[i] = packetBuffer; + + packetBuffer = NULL; + } + + *Packets = packets; + packets = NULL; + m_PacketsCount = PacketCount; + m_PacketSize = PacketSize; + m_FirstPacketOffset = firstPacketOffset; + +exit: + if (packetBuffer) + { + ExFreePoolWithTag(packetBuffer, DeviceDriverTag); + } + if (packets) + { + FreeRtPackets(packets, PacketCount); + } + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID +CStreamEngine::FreeRtPackets( + _Frees_ptr_ PACX_RTPACKET Packets, + _In_ ULONG PacketCount +) +{ + ULONG i; + PVOID buffer; + + PAGED_CODE(); + + for (i = 0; i < PacketCount; ++i) + { + if (Packets[i].RtPacketBuffer.u.MdlType.Mdl) + { + buffer = MmGetMdlVirtualAddress(Packets[i].RtPacketBuffer.u.MdlType.Mdl); + IoFreeMdl(Packets[i].RtPacketBuffer.u.MdlType.Mdl); + ExFreePool(buffer); + } + } + + ExFreePool(Packets); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::PrepareHardware() +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + WDF_TIMER_CONFIG timerConfig; + WDF_OBJECT_ATTRIBUTES timerAttributes; + PSTREAM_TIMER_CONTEXT timerCtx; + + PAGED_CODE(); + + // + // If already in this state, do nothing. + // + if (m_CurrentState == AcxStreamStatePause) + { + // Nothing to do. + status = STATUS_SUCCESS; + goto exit; + } + + if (m_CurrentState != AcxStreamStateStop) + { + // Error out. + status = STATUS_INVALID_STATE_TRANSITION; + goto exit; + } + + // + // Stop to Pause. + // + WDF_TIMER_CONFIG_INIT(&timerConfig, CStreamEngine::s_EvtStreamPassCallback); + timerConfig.AutomaticSerialization = TRUE; + timerConfig.UseHighResolutionTimer = WdfTrue; + timerConfig.Period = 0; + + WDF_OBJECT_ATTRIBUTES_INIT(&timerAttributes); + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&timerAttributes, STREAM_TIMER_CONTEXT); + timerAttributes.ParentObject = m_Stream; + + status = WdfTimerCreate(&timerConfig, &timerAttributes, &m_NotificationTimer); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + timerCtx = GetStreamTimerContext(m_NotificationTimer); + timerCtx->StreamEngine = this; + + m_CurrentState = AcxStreamStatePause; + status = STATUS_SUCCESS; + +exit: + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + // + // If already in this state, do nothing. + // + if (m_CurrentState == AcxStreamStateStop) + { + // Nothing to do. + goto exit; + } + + // + // Just assert we are in the correct state. + // On the way down we always want to succeed. + // + ASSERT(m_CurrentState == AcxStreamStatePause); + + // + // Pause to Stop. + // + if (m_NotificationTimer) + { + WdfTimerStop(m_NotificationTimer, TRUE); + WdfObjectDelete(m_NotificationTimer); + m_NotificationTimer = NULL; + } + + KeFlushQueuedDpcs(); + + m_Position = 0; + m_GlitchAdjust = 0; + m_CurrentPacket = 0; + + m_CurrentState = AcxStreamStateStop; + +exit: + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::Pause() +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + + PAGED_CODE(); + + if (m_CurrentState == AcxStreamStatePause) + { + // Nothing to do. + status = STATUS_SUCCESS; + goto exit; + } + + if (m_CurrentState != AcxStreamStateRun) + { + // Error out. + status = STATUS_INVALID_STATE_TRANSITION; + goto exit; + } + + m_PeakMeter.StopStream(); + if (m_pCircuitPeakmeter) + { + m_pCircuitPeakmeter->StopStream(); + } + + // + // Run to Pause. + // + WdfTimerStop(m_NotificationTimer, TRUE); + + // Save the position we paused at. + UpdatePosition(); + + m_CurrentState = AcxStreamStatePause; + status = STATUS_SUCCESS; + +exit: + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::Run() +{ + NTSTATUS status = STATUS_UNSUCCESSFUL; + + PAGED_CODE(); + + if (m_CurrentState == AcxStreamStateRun) + { + // Nothing to do. + status = STATUS_SUCCESS; + goto exit; + } + + if (m_CurrentState != AcxStreamStatePause) + { + status = STATUS_INVALID_STATE_TRANSITION; + goto exit; + } + + m_PeakMeter.StartStream(); + if (m_pCircuitPeakmeter) + { + m_pCircuitPeakmeter->StartStream(); + } + + // + // Pause to Run. + // + // Save the time and position - if we ran and paused previously, the StartTime and StartPosition will allow + // us to continue scheduling packet completions correctly, while still reporting absolute position from the + // start of the stream. + // + m_StartTime = KSCONVERT_PERFORMANCE_TIME(m_PerformanceCounterFrequency.QuadPart, KeQueryPerformanceCounter(NULL)); + m_StartPosition = m_Position; + + // Reset time we've lost to glitches + m_GlitchAdjust = 0; + + ScheduleNextPass(); + + m_CurrentState = AcxStreamStateRun; + status = STATUS_SUCCESS; + +exit: + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::GetPresentationPosition( + _Out_ PULONGLONG PositionInBlocks, + _Out_ PULONGLONG QPCPosition +) +{ + ULONG blockAlign; + LARGE_INTEGER qpc; + + PAGED_CODE(); + + blockAlign = AcxDataFormatGetBlockAlign(m_StreamFormat); + + // Update the position based on the current time + UpdatePosition(); + qpc = KeQueryPerformanceCounter(NULL); + + *PositionInBlocks = m_Position / blockAlign; + *QPCPosition = (ULONGLONG)qpc.QuadPart; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::GetLinearBufferPosition( + _Out_ PULONGLONG Position +) +{ + UNREFERENCED_PARAMETER(Position); + PAGED_CODE(); + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::SetCurrentWritePosition( + _In_ ULONG Position +) +{ + UNREFERENCED_PARAMETER(Position); + PAGED_CODE(); + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::SetLastBufferPosition( + _In_ ULONG Position +) +{ + UNREFERENCED_PARAMETER(Position); + PAGED_CODE(); + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::AssignDrmContentId( + ULONG DrmContentId, + PACXDRMRIGHTS DrmRights +) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DrmContentId); + UNREFERENCED_PARAMETER(DrmRights); + + // + // At this point the driver should enforce the new DrmRights. + // + // HDMI render: if DigitalOutputDisable or CopyProtect is true, enable HDCP. + // + // From MSDN: + // + // This sample doesn't forward protected content, but if your driver uses + // lower layer drivers or a different stack to properly work, please see the + // following info from MSDN: + // + // "Before allowing protected content to flow through a data path, the system + // verifies that the data path is secure. To do so, the system authenticates + // each module in the data path beginning at the upstream end of the data path + // and moving downstream. As each module is authenticated, that module gives + // the system information about the next module in the data path so that it + // can also be authenticated. To be successfully authenticated, a module's + // binary file must be signed as DRM-compliant. + // + // Two adjacent modules in the data path can communicate with each other in + // one of several ways. If the upstream module calls the downstream module + // through IoCallDriver, the downstream module is part of a WDM driver. In + // this case, the upstream module calls the AcxDrmForwardContentToDeviceObject + // function to provide the system with the device object representing the + // downstream module. (If the two modules communicate through the downstream + // module's content handlers, the upstream module calls AcxDrmAddContentHandlers + // instead.) + // + // For more information, see MSDN's DRM Functions and Interfaces. + // + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::GetHWLatency( + _Out_ ULONG* FifoSize, + _Out_ ULONG* Delay +) +{ + PAGED_CODE(); + + *FifoSize = 128; + *Delay = 0; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CSimPeakMeter * +CStreamEngine::GetPeakMeter() +{ + PAGED_CODE(); + + return &m_PeakMeter; +} + +_Use_decl_annotations_ +VOID +CStreamEngine::s_EvtStreamPassCallback( + _In_ WDFTIMER Timer +) +{ + CStreamEngine* This; + PSTREAM_TIMER_CONTEXT timerCtx; + + // Get our stream engine pointer from the timer context + timerCtx = GetStreamTimerContext(Timer); + This = timerCtx->StreamEngine; + + // Call the StreamPassCallback for the engine + This->StreamPassCallback(); +} + +// This is run every time the stream timer fires +_Use_decl_annotations_ +VOID +CStreamEngine::StreamPassCallback() +{ + ULONGLONG completedPacket; + ULONGLONG qpcCompleted; + + // Process the packet (e.g. save render to file/generate capture data) + ProcessPacket(); + + // We've completed a packet! Increment our currently active packet + completedPacket = (ULONG)InterlockedIncrement((LONG*)&m_CurrentPacket) - 1; + // Save the time at which we moved to the next packet + qpcCompleted = (ULONGLONG)KeQueryPerformanceCounter(NULL).QuadPart; + + InterlockedExchange64(&m_LastPacketStart.QuadPart, m_CurrentPacketStart.QuadPart); + InterlockedExchange64(&m_CurrentPacketStart.QuadPart, qpcCompleted); + + // Tell ACX we've completed the packet. + (void)AcxRtStreamNotifyPacketComplete(m_Stream, completedPacket, qpcCompleted); + + // Schedule when our new current packet will finish + ScheduleNextPass(); +} + +_Use_decl_annotations_ +VOID +CStreamEngine::ScheduleNextPass() +{ + LONGLONG delay = 0; + ULONG bytesPerSecond; + ULONGLONG nextPacket = 0; + ULONGLONG nextPacketStartPosition = 0; + ULONGLONG nextPacketPositionFromLastPause = 0; + ULONGLONG nextPacketTimeFromLastPauseHns = 0; + ULONGLONG nextPacketTime = 0; + ULONGLONG currentTime; + BOOLEAN inTimerQueue = FALSE; + + // Get the number of bytes per second from our stored stream format + bytesPerSecond = GetBytesPerSecond(); + + // Calculate the absolute position of the beginning of the next packet from the beginning of the stream + nextPacket = m_CurrentPacket + 1; + nextPacketStartPosition = nextPacket * m_PacketSize; + + // Adjust next packet position to account for the last time we resumed from Pause + nextPacketPositionFromLastPause = nextPacketStartPosition - m_StartPosition; + + // Convert from bytes to HNS (to prevent truncation, multiply first then divide) + nextPacketTimeFromLastPauseHns = nextPacketPositionFromLastPause * HNS_PER_SEC / bytesPerSecond; + + // Next packet time is Time @ resume from Pause, offset for lost time due to glitch, with next packet time added + nextPacketTime = m_StartTime + m_GlitchAdjust + nextPacketTimeFromLastPauseHns; + + currentTime = KSCONVERT_PERFORMANCE_TIME(m_PerformanceCounterFrequency.QuadPart, KeQueryPerformanceCounter(NULL)); + + // Determine how long we want to wait, in HNS. Negative since it's a relative wait + delay = -(LONGLONG)(nextPacketTime - currentTime); + + // If the delay isn't negative, this means we lost some time (e.g. broken into kernel debugger). Update + // our glitch adjust to account for that lost time, and attempt to schedule again + if (delay >= 0) + { + // Glitch!!! + // Update the glitch adjustment and set the new delay. + m_GlitchAdjust += delay; + + StreamPassCallback(); + + return; + } + + // Start the timer for our next pass! Note the timer isn't periodic. + inTimerQueue = WdfTimerStart(m_NotificationTimer, delay); + + // We shouldn't be scheduling our next pass if the timer was previously still pending + ASSERT(inTimerQueue == FALSE); +} + +_Use_decl_annotations_ +VOID +CStreamEngine::UpdatePosition() +{ + ULONGLONG currentTime; + ULONG bytesPerSecond; + + if (m_CurrentState != AcxStreamStateRun) + { + return; + } + bytesPerSecond = GetBytesPerSecond(); + currentTime = KSCONVERT_PERFORMANCE_TIME(m_PerformanceCounterFrequency.QuadPart, KeQueryPerformanceCounter(NULL)); + + // Update position + m_Position = m_StartPosition - m_GlitchAdjust + (currentTime - m_StartTime) * bytesPerSecond / HNS_PER_SEC; +} + +_Use_decl_annotations_ +ULONG +CStreamEngine::GetBytesPerSecond() +{ + ULONG bytesPerSecond; + + bytesPerSecond = AcxDataFormatGetAverageBytesPerSec(m_StreamFormat); + + return bytesPerSecond; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CStreamEngine::GetCurrentPacket( + _Out_ PULONG CurrentPacket +) +{ + ULONG currentPacket; + PAGED_CODE(); + + currentPacket = (ULONG)InterlockedCompareExchange((LONG*)&m_CurrentPacket, -1, -1); + + *CurrentPacket = currentPacket; + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CRenderStreamEngine::CRenderStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ BOOL Offload, + _In_ CSimPeakMeter * CircuitPeakmeter + +) + : CStreamEngine(Stream, StreamFormat, Offload, CircuitPeakmeter) +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CRenderStreamEngine::~CRenderStreamEngine() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::PrepareHardware() +{ + NTSTATUS status = STATUS_SUCCESS; + + PAGED_CODE(); + + status = CStreamEngine::PrepareHardware(); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + status = m_SaveData.SetDataFormat((PKSDATAFORMAT)AcxDataFormatGetKsDataFormat(m_StreamFormat)); + if (!NT_SUCCESS(status)) + { + status = STATUS_SUCCESS; + goto exit; + } + + status = m_SaveData.Initialize(m_Offload); + if (!NT_SUCCESS(status)) + { + status = STATUS_SUCCESS; + goto exit; + } + + status = m_SaveData.SetMaxWriteSize(m_PacketSize * m_PacketsCount * 16); + if (!NT_SUCCESS(status)) + { + status = STATUS_SUCCESS; + goto exit; + } + +exit: + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + m_SaveData.WaitAllWorkItems(); + m_SaveData.Cleanup(); + + return CStreamEngine::ReleaseHardware(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::AssignDrmContentId( + ULONG DrmContentId, + PACXDRMRIGHTS DrmRights + ) +{ + PAGED_CODE(); + + UNREFERENCED_PARAMETER(DrmContentId); + + // + // At this point the driver should enforce the new DrmRights. + // The sample driver handles DrmRights per stream basis, and + // stops writing the stream to disk, if CopyProtect = TRUE. + // + // HDMI render: if DigitalOutputDisable or CopyProtect is true, enable HDCP. + // Loopback: if CopyProtect is true, disable loopback stream. + // + + // + // Sample writes each stream seperately to disk. If the rights for this + // stream indicates that the stream is CopyProtected, stop writing to disk. + // + m_SaveData.Disable(DrmRights->CopyProtect); + + // + // From MSDN: + // + // This sample doesn't forward protected content, but if your driver uses + // lower layer drivers or a different stack to properly work, please see the + // following info from MSDN: + // + // "Before allowing protected content to flow through a data path, the system + // verifies that the data path is secure. To do so, the system authenticates + // each module in the data path beginning at the upstream end of the data path + // and moving downstream. As each module is authenticated, that module gives + // the system information about the next module in the data path so that it + // can also be authenticated. To be successfully authenticated, a module's + // binary file must be signed as DRM-compliant. + // + // Two adjacent modules in the data path can communicate with each other in + // one of several ways. If the upstream module calls the downstream module + // through IoCallDriver, the downstream module is part of a WDM driver. In + // this case, the upstream module calls the AcxDrmForwardContentToDeviceObject + // function to provide the system with the device object representing the + // downstream module. (If the two modules communicate through the downstream + // module's content handlers, the upstream module calls AcxDrmAddContentHandlers + // instead.) + // + // For more information, see MSDN's DRM Functions and Interfaces. + // + + return STATUS_SUCCESS; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CRenderStreamEngine::SetRenderPacket( + _In_ ULONG Packet, + _In_ ULONG Flags, + _In_ ULONG EosPacketLength +) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG currentPacket; + + UNREFERENCED_PARAMETER(Flags); + UNREFERENCED_PARAMETER(EosPacketLength); + + PAGED_CODE(); + + currentPacket = (ULONG)InterlockedCompareExchange((LONG*)&m_CurrentPacket, -1, -1); + + if (Packet <= currentPacket) + { + //ASSERT(FALSE); + status = STATUS_DATA_LATE_ERROR; + } + else if (Packet > currentPacket + 1) + { + //ASSERT(FALSE); + status = STATUS_DATA_OVERRUN; + } + + return status; +} + +_Use_decl_annotations_ +VOID +CRenderStreamEngine::ProcessPacket() +{ + ULONG currentPacket; + ULONG packetIndex; + PBYTE packetBuffer; + + currentPacket = (ULONG)InterlockedCompareExchange((LONG*)&m_CurrentPacket, -1, -1); + + packetIndex = currentPacket % m_PacketsCount; + packetBuffer = (PBYTE)m_Packets[packetIndex]; + // Packet 0 starts at an offset if the size isn't a multiple of page_size + if (packetIndex == 0) + { + packetBuffer += m_FirstPacketOffset; + } + + m_SaveData.WriteData(packetBuffer, m_PacketSize); +} + + +_Use_decl_annotations_ +PAGED_CODE_SEG +CCaptureStreamEngine::CCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat +) + : CStreamEngine(Stream, StreamFormat, FALSE, NULL), + m_EnableWaveCapture(0) +{ + PAGED_CODE(); + + m_CurrentPacketStart.QuadPart = 0; + m_LastPacketStart.QuadPart = 0; + + RtlInitUnicodeString(&m_HostCaptureFileName, NULL); + RtlInitUnicodeString(&m_LoopbackCaptureFileName, NULL); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CCaptureStreamEngine::~CCaptureStreamEngine() +{ + PAGED_CODE(); + + RtlFreeUnicodeString(&m_HostCaptureFileName); + RtlFreeUnicodeString(&m_LoopbackCaptureFileName); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::PrepareHardware() +{ + NTSTATUS status = STATUS_SUCCESS; + PWAVEFORMATEXTENSIBLE pwfext = NULL; + + PAGED_CODE(); + + status = CStreamEngine::PrepareHardware(); + if (!NT_SUCCESS(status)) + { + goto exit; + } + + (void)ReadRegistrySettings(); + + pwfext = (PWAVEFORMATEXTENSIBLE)AcxDataFormatGetWaveFormatExtensible(m_StreamFormat); + if (pwfext == NULL) + { + // Cannot initialize reader or generator with a format that's not understood + status = STATUS_NO_MATCH; + ASSERT(FALSE); + goto exit; + } + + if (m_EnableWaveCapture) + { + status = m_WaveReader.Init(pwfext, &m_HostCaptureFileName); + if (!NT_SUCCESS(status)) + { + m_EnableWaveCapture = FALSE; + } + } + + if (!m_EnableWaveCapture) + { + status = m_ToneGenerator.Init(m_ToneFrequency, pwfext); + } + +exit: + return status; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::ReleaseHardware() +{ + PAGED_CODE(); + + if (m_EnableWaveCapture) + { + m_WaveReader.WaitAllWorkItems(); + } + + return CStreamEngine::ReleaseHardware(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::GetCapturePacket( + _Out_ ULONG* LastCapturePacket, + _Out_ ULONGLONG* QPCPacketStart, + _Out_ BOOLEAN* MoreData +) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG currentPacket; + LONGLONG qpcPacketStart; + + PAGED_CODE(); + + currentPacket = (ULONG)InterlockedCompareExchange((LONG*)&m_CurrentPacket, -1, -1); + qpcPacketStart = InterlockedCompareExchange64(&m_LastPacketStart.QuadPart, -1, -1); + + *LastCapturePacket = currentPacket - 1; + *QPCPacketStart = (ULONGLONG)qpcPacketStart; + *MoreData = FALSE; + + return status; +} + +_Use_decl_annotations_ +VOID +CCaptureStreamEngine::ProcessPacket() +{ + ULONG currentPacket; + ULONG packetIndex; + PBYTE packetBuffer; + + currentPacket = (ULONG)InterlockedCompareExchange((LONG*)&m_CurrentPacket, -1, -1); + + packetIndex = currentPacket % m_PacketsCount; + packetBuffer = (PBYTE)m_Packets[packetIndex]; + + // Packet 0 starts at an offset if the size isn't a multiple of page_size + if (packetIndex == 0) + { + packetBuffer += m_FirstPacketOffset; + } + + if (m_EnableWaveCapture) + { + m_WaveReader.ReadWaveData(packetBuffer, m_PacketSize); + } + else + { + m_ToneGenerator.GenerateSine(packetBuffer, m_PacketSize); + } +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CCaptureStreamEngine::ReadRegistrySettings() +{ + NTSTATUS status; + PDRIVER_OBJECT DriverObject; + HANDLE DriverKey; + + RTL_QUERY_REGISTRY_TABLE paramTable[] = { + // QueryRoutine Flags Name EntryContext DefaultType DefaultData DefaultLength + { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"EnableWaveCapture", &m_EnableWaveCapture, (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_DWORD, &m_EnableWaveCapture, sizeof(DWORD) }, + { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"HostCaptureFileName", &m_HostCaptureFileName, (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_SZ, &m_HostCaptureFileName, sizeof(UNICODE_STRING) }, + { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK, L"LoopbackCaptureFileName", &m_LoopbackCaptureFileName, (REG_SZ << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_SZ, &m_LoopbackCaptureFileName, sizeof(UNICODE_STRING) }, + { NULL, 0, NULL, NULL, 0, NULL, 0 } + }; + + PAGED_CODE(); + + DriverObject = WdfDriverWdmGetDriverObject(WdfGetDriver()); + DriverKey = NULL; + status = IoOpenDriverRegistryKey(DriverObject, + DriverRegKeyParameters, + KEY_READ, + 0, + &DriverKey); + + if (!NT_SUCCESS(status)) + { + ASSERT(FALSE); + goto exit; + } + + status = RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, + (PCWSTR) DriverKey, + ¶mTable[0], + NULL, + NULL); + + if (DriverKey) + { + ZwClose(DriverKey); + } + +exit: + if (!NT_SUCCESS(status)) + { + m_EnableWaveCapture = FALSE; + } + + return status; +} +_Use_decl_annotations_ +PAGED_CODE_SEG +CBufferedCaptureStreamEngine::CBufferedCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ CKeywordDetector* KeywordDetector + +) + : CCaptureStreamEngine(Stream, StreamFormat), + m_KeywordDetector(KeywordDetector) +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +CBufferedCaptureStreamEngine::~CBufferedCaptureStreamEngine() +{ + PAGED_CODE(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CBufferedCaptureStreamEngine::Pause() +{ + PAGED_CODE(); + + m_KeywordDetector->Stop(); + return CCaptureStreamEngine::Pause(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CBufferedCaptureStreamEngine::Run() +{ + PAGED_CODE(); + + m_KeywordDetector->Run(); + return CCaptureStreamEngine::Run(); +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS +CBufferedCaptureStreamEngine::GetCapturePacket( + _Out_ ULONG* LastCapturePacket, + _Out_ ULONGLONG* QPCPacketStart, + _Out_ BOOLEAN* MoreData +) +{ + PAGED_CODE(); + + // retrieve the packet from the fifo queue + return m_KeywordDetector->GetReadPacket(m_PacketsCount, m_PacketSize, m_Packets, LastCapturePacket, QPCPacketStart, MoreData); +} + +_Use_decl_annotations_ +VOID +CBufferedCaptureStreamEngine::ProcessPacket() +{ + LARGE_INTEGER qpc; + LARGE_INTEGER qpcFrequency; + + qpc = KeQueryPerformanceCounter(&qpcFrequency); + + // Add the next packet to the fifo queue + m_KeywordDetector->DpcRoutine(qpc.QuadPart, qpcFrequency.QuadPart); +} + +//Streamengine callbacks + +VOID +EvtStreamDestroy( + _In_ WDFOBJECT Object +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + ctx = GetStreamEngineContext((ACXSTREAM)Object); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + ctx->StreamEngine = NULL; + delete streamEngine; +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetHwLatency( + _In_ ACXSTREAM Stream, + _Out_ ULONG* FifoSize, + _Out_ ULONG* Delay +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->GetHWLatency(FifoSize, Delay); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamAllocateRtPackets( + _In_ ACXSTREAM Stream, + _In_ ULONG PacketCount, + _In_ ULONG PacketSize, + _Out_ PACX_RTPACKET* Packets +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->AllocateRtPackets(PacketCount, PacketSize, Packets); +} + +PAGED_CODE_SEG +VOID +EvtStreamFreeRtPackets( + _In_ ACXSTREAM Stream, + _In_ PACX_RTPACKET Packets, + _In_ ULONG PacketCount +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->FreeRtPackets(Packets, PacketCount); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamPrepareHardware( + _In_ ACXSTREAM Stream +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->PrepareHardware(); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamReleaseHardware( + _In_ ACXSTREAM Stream +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->ReleaseHardware(); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamRun( + _In_ ACXSTREAM Stream +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->Run(); +} + + +PAGED_CODE_SEG +NTSTATUS +EvtStreamPause( + _In_ ACXSTREAM Stream +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->Pause(); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamAssignDrmContentId( + _In_ ACXSTREAM Stream, + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine * streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = (CStreamEngine*)ctx->StreamEngine; + + return streamEngine->AssignDrmContentId(DrmContentId, DrmRights); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetCurrentPacket( + _In_ ACXSTREAM Stream, + _Out_ PULONG CurrentPacket +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = static_cast(ctx->StreamEngine); + + return streamEngine->GetCurrentPacket(CurrentPacket); +} + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetPresentationPosition( + _In_ ACXSTREAM Stream, + _Out_ PULONGLONG PositionInBlocks, + _Out_ PULONGLONG QPCPosition +) +{ + PSTREAMENGINE_CONTEXT ctx; + CStreamEngine* streamEngine = NULL; + + PAGED_CODE(); + + ctx = GetStreamEngineContext(Stream); + + streamEngine = static_cast(ctx->StreamEngine); + + return streamEngine->GetPresentationPosition(PositionInBlocks, QPCPosition); +} + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.h b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.h new file mode 100644 index 000000000..62f6c8d18 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.h @@ -0,0 +1,449 @@ +#pragma once + +#include "savedata.h" +#include "tonegenerator.h" +#include "WaveReader.h" +#include "SimPeakMeter.h" +#include "keyworddetector.h" + +#define HNSTIME_PER_MILLISECOND 10000 + +#define MAX_PACKET_COUNT 2 + +#define DEFAULT_FREQUENCY 220 +#define LOOPBACK_FREQUENCY 500 + +// Stream callbacks shared between Capture and Render + +VOID +EvtStreamDestroy( + _In_ WDFOBJECT Object +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetHwLatency( + _In_ ACXSTREAM Stream, + _Out_ ULONG* FifoSize, + _Out_ ULONG* Delay +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamAllocateRtPackets( + _In_ ACXSTREAM Stream, + _In_ ULONG PacketCount, + _In_ ULONG PacketSize, + _Out_ PACX_RTPACKET* Packets +); + +PAGED_CODE_SEG +VOID +EvtStreamFreeRtPackets( + _In_ ACXSTREAM Stream, + _In_ PACX_RTPACKET Packets, + _In_ ULONG PacketCount +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamPrepareHardware( + _In_ ACXSTREAM Stream +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamReleaseHardware( + _In_ ACXSTREAM Stream +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamRun( + _In_ ACXSTREAM Stream +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamPause( + _In_ ACXSTREAM Stream +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamAssignDrmContentId( + _In_ ACXSTREAM Stream, + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetCurrentPacket( + _In_ ACXSTREAM Stream, + _Out_ PULONG CurrentPacket +); + +PAGED_CODE_SEG +NTSTATUS +EvtStreamGetPresentationPosition( + _In_ ACXSTREAM Stream, + _Out_ PULONGLONG PositionInBlocks, + _Out_ PULONGLONG QPCPosition +); + + +class CStreamEngine +{ +public: + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + AllocateRtPackets( + _In_ ULONG PacketCount, + _In_ ULONG PacketSize, + _Out_ PACX_RTPACKET * Packets + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + FreeRtPackets( + _Frees_ptr_ PACX_RTPACKET Packets, + _In_ ULONG PacketCount + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Run(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Pause(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetPresentationPosition( + _Out_ PULONGLONG PositionInBlocks, + _Out_ PULONGLONG QPCPosition + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetLinearBufferPosition( + _Out_ PULONGLONG Position + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetCurrentWritePosition( + _In_ ULONG Position + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetLastBufferPosition( + _In_ ULONG Position + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetCurrentPacket( + _Out_ PULONG CurrentPacket + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetHWLatency( + _Out_ ULONG * FifoSize, + _Out_ ULONG * Delay + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + AssignDrmContentId( + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CSimPeakMeter * + GetPeakMeter(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ BOOL Offload, + _In_opt_ CSimPeakMeter *CircuitPeakmeter + ); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CStreamEngine(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + SetFrequency( + _In_ DWORD ToneFrequency + ) + { + PAGED_CODE(); + + m_ToneFrequency = ToneFrequency; + } + +protected: + PVOID m_Packets[MAX_PACKET_COUNT]; + ULONG m_PacketsCount; + ULONG m_PacketSize; + ULONG m_FirstPacketOffset; + WDFTIMER m_NotificationTimer; + ACX_STREAM_STATE m_CurrentState; + ULONG m_CurrentPacket; + ULONGLONG m_Position; + ACXSTREAM m_Stream; + ACXDATAFORMAT m_StreamFormat; + ULONGLONG m_StartTime; + ULONGLONG m_StartPosition; + ULONGLONG m_GlitchAdjust; + LARGE_INTEGER m_PerformanceCounterFrequency; + LARGE_INTEGER m_CurrentPacketStart; + LARGE_INTEGER m_LastPacketStart; + DWORD m_ToneFrequency; + BOOL m_Offload; + CSimPeakMeter m_PeakMeter; + CSimPeakMeter* m_pCircuitPeakmeter; + + static + __drv_maxIRQL(DISPATCH_LEVEL) + _Function_class_(EVT_WDF_TIMER) + VOID s_EvtStreamPassCallback( + _In_ WDFTIMER Timer + ); + + // This is run every time the stream timer fires + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + StreamPassCallback(); + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + ScheduleNextPass(); + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + UpdatePosition(); + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + ULONG + GetBytesPerSecond(); + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + ProcessPacket() = 0; +}; + +class CRenderStreamEngine : public CStreamEngine +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CRenderStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ BOOL Offload, + _In_ CSimPeakMeter *CircuitPeakmeter + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CRenderStreamEngine(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + AssignDrmContentId( + _In_ ULONG DrmContentId, + _In_ PACXDRMRIGHTS DrmRights + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + SetRenderPacket( + _In_ ULONG Packet, + _In_ ULONG Flags, + _In_ ULONG EosPacketLength + ); + +protected: + CSaveData m_SaveData; + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + ProcessPacket(); + +}; + +class CCaptureStreamEngine : public CStreamEngine +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CCaptureStreamEngine(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + PrepareHardware(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReleaseHardware(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetCapturePacket( + _Out_ ULONG * LastCapturePacket, + _Out_ ULONGLONG * QPCPacketStart, + _Out_ BOOLEAN * MoreData + ); + +protected: + ToneGenerator m_ToneGenerator; + CWaveReader m_WaveReader; + DWORD m_EnableWaveCapture; + UNICODE_STRING m_HostCaptureFileName; + UNICODE_STRING m_LoopbackCaptureFileName; + + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + ProcessPacket(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + ReadRegistrySettings(); +}; + +class CBufferedCaptureStreamEngine : public CCaptureStreamEngine +{ +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CBufferedCaptureStreamEngine( + _In_ ACXSTREAM Stream, + _In_ ACXDATAFORMAT StreamFormat, + _In_ CKeywordDetector * KeywordDetector + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CBufferedCaptureStreamEngine(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Run(); + + virtual + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Pause(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + GetCapturePacket( + _Out_ ULONG * LastCapturePacket, + _Out_ ULONGLONG * QPCPacketStart, + _Out_ BOOLEAN * MoreData + ); + +protected: + virtual + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + ProcessPacket(); + + CKeywordDetector * m_KeywordDetector; +}; + +// Define circuit/stream pin context. +// +typedef struct _STREAM_TIMER_CONTEXT { + CStreamEngine * StreamEngine; +} STREAM_TIMER_CONTEXT, *PSTREAM_TIMER_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(STREAM_TIMER_CONTEXT, GetStreamTimerContext) diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.cpp new file mode 100644 index 000000000..876d2bbd9 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.cpp @@ -0,0 +1,297 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + ToneGenerator.cpp + +Abstract: + + Implementation of sine wave generator for ACX driver samples + + +--*/ +#include "private.h" +#include "public.h" +#include +#include +#include +#include +#include "ToneGenerator.h" + +#define TONEGENERATOR_POOLTAG 'rGnT' + +const double TONE_AMPLITUDE = 0.5; // Scalar value, should be between 0.0 - 1.0 +const double TWO_PI = M_PI * 2; + +DWORD g_DisableToneGenerator = 0; // default is to generate tones. + +#define IF_FAILED_JUMP(result, tag) do {if (!NT_SUCCESS(result)) {goto tag;}} while(false) +#define IF_TRUE_JUMP(result, tag) do {if (result) {goto tag;}} while(false) +#define IF_TRUE_ACTION_JUMP(result, action, tag) do {if (result) {action; goto tag;}} while(false) + +// +// Double to short conversion. +// +__drv_maxIRQL(DISPATCH_LEVEL) +short ConvertToShort(double Value) +{ + return (short)(Value * _I16_MAX); +}; + +// +// Double to char conversion. +// +__drv_maxIRQL(DISPATCH_LEVEL) +unsigned char ConvertToUChar(double Value) +{ + const double F_127_5 = 127.5; + return (unsigned char)(Value * F_127_5 + F_127_5); +}; + +// +// Ctor: basic init. +// +_Use_decl_annotations_ +PAGED_CODE_SEG +ToneGenerator::ToneGenerator() +: m_Frequency(0), + m_ChannelCount(0), + m_BitsPerSample(0), + m_SamplesPerSecond(0), + m_Mute(false), + m_PartialFrame(NULL), + m_PartialFrameBytes(0), + m_FrameSize(0) +{ + PAGED_CODE(); + + // Theta (double) and SampleIncrement (double) are init in the Init() method + // after saving the floating point state. +} + +// +// Dtor: free resources. +// +_Use_decl_annotations_ +PAGED_CODE_SEG +ToneGenerator::~ToneGenerator() +{ + PAGED_CODE(); + + if (m_PartialFrame) + { + ExFreePoolWithTag(m_PartialFrame, TONEGENERATOR_POOLTAG); + m_PartialFrame = NULL; + m_PartialFrameBytes = 0; + } +} + +// +// Init a new frame. +// Note: caller will save and restore the floatingpoint state. +// +#pragma warning(push) +// Caller wraps this routine between KeSaveFloatingPointState/KeRestoreFloatingPointState calls. +#pragma warning(disable: 28110) + +_Use_decl_annotations_ +VOID ToneGenerator::InitNewFrame +( + _Out_writes_bytes_(FrameSize) BYTE* Frame, + _In_ DWORD FrameSize +) +{ + double sinValue = TONE_AMPLITUDE * sin( m_Theta ); + + if (FrameSize != (DWORD)m_ChannelCount * m_BitsPerSample/8) + { + ASSERT(FALSE); + RtlZeroMemory(Frame, FrameSize); + return; + } + + for(ULONG i = 0; i < m_ChannelCount; ++i) + { + if (m_BitsPerSample == 8) + { + unsigned char *dataBuffer = reinterpret_cast(Frame); + dataBuffer[i] = ConvertToUChar(sinValue); + } + else // 16 bits per sample + { + short *dataBuffer = reinterpret_cast(Frame); + dataBuffer[i] = ConvertToShort(sinValue); + } + } + + m_Theta += m_SampleIncrement; + if (m_Theta >= TWO_PI) + { + m_Theta -= TWO_PI; + } +} +#pragma warning(pop) + +// +// GenerateSamples() +// +// Generate a sine wave that fits into the specified buffer. +// +// Buffer - Buffer to hold the samples +// BufferLength - Length of the buffer. +// +// Note: this function supports 16bit and 8bit samples only. +// +_Use_decl_annotations_ +void ToneGenerator::GenerateSine +( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ size_t BufferLength +) +{ + NTSTATUS status; + KFLOATING_SAVE saveData; + BYTE * buffer; + size_t length; + size_t copyBytes; + + // if muted, or tone generator disabled via registry, + // we deliver silence. + if (m_Mute || g_DisableToneGenerator) + { + goto ZeroBuffer; + } + + status = KeSaveFloatingPointState(&saveData); + if (!NT_SUCCESS(status)) + { + goto ZeroBuffer; + } + + buffer = Buffer; + length = BufferLength; + + // + // Check if we have any residual frame bytes from the last time. + // + if (m_PartialFrameBytes) + { + ASSERT(m_FrameSize > m_PartialFrameBytes); + DWORD offset = m_FrameSize - m_PartialFrameBytes; + copyBytes = MIN(m_PartialFrameBytes, length); + RtlCopyMemory(buffer, m_PartialFrame + offset, copyBytes); + RtlZeroMemory(m_PartialFrame + offset, copyBytes); + length -= copyBytes; + buffer += copyBytes; + m_PartialFrameBytes = 0; + } + + IF_TRUE_JUMP(length == 0, Done); + + // + // Copy all the aligned frames. + // + + size_t frames = length/m_FrameSize; + + for (size_t i = 0; i < frames; ++i) + { + InitNewFrame(buffer, m_FrameSize); + buffer += m_FrameSize; + length -= m_FrameSize; + } + + IF_TRUE_JUMP(length == 0, Done); + + // + // Copy any partial frame at the end. + // + ASSERT(m_FrameSize > length); + InitNewFrame(m_PartialFrame, m_FrameSize); + RtlCopyMemory(buffer, m_PartialFrame, length); + RtlZeroMemory(m_PartialFrame, length); + m_PartialFrameBytes = m_FrameSize - (DWORD)length; + +Done: + KeRestoreFloatingPointState(&saveData); + return; + +ZeroBuffer: + RtlZeroMemory(Buffer, BufferLength); + return; +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS ToneGenerator::Init +( + _In_ DWORD ToneFrequency, + _In_ PWAVEFORMATEXTENSIBLE WfExt +) +{ + NTSTATUS status = STATUS_SUCCESS; + KFLOATING_SAVE saveData; + + PAGED_CODE(); + + // + // This sample supports PCM 16bit formats only. + // + if ((WfExt->Format.wFormatTag != WAVE_FORMAT_PCM && + !(WfExt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && + IsEqualGUIDAligned(WfExt->SubFormat, KSDATAFORMAT_SUBTYPE_PCM))) || + (WfExt->Format.wBitsPerSample != 16 && + WfExt->Format.wBitsPerSample != 8)) + { + status = STATUS_NOT_SUPPORTED; + } + IF_FAILED_JUMP(status, Done); + + // + // Save floating state (just in case). + // + status = KeSaveFloatingPointState(&saveData); + IF_FAILED_JUMP(status, Done); + + // + // Basic init. + // + RtlZeroMemory(&m_Theta, sizeof(m_Theta)); + m_Frequency = ToneFrequency; + m_ChannelCount = WfExt->Format.nChannels; // # channels. + m_BitsPerSample = WfExt->Format.wBitsPerSample; // bits per sample. + m_SamplesPerSecond = WfExt->Format.nSamplesPerSec; // samples per sec. + m_Mute = false; + m_SampleIncrement = (m_Frequency * TWO_PI) / (double)m_SamplesPerSecond; + m_FrameSize = (DWORD)m_ChannelCount * m_BitsPerSample/8; + ASSERT(m_FrameSize == WfExt->Format.nBlockAlign); + + // + // Restore floating state. + // + KeRestoreFloatingPointState(&saveData); + + // + // Allocate a buffer to hold a partial frame. + // + m_PartialFrame = (BYTE*)ExAllocatePool2( + POOL_FLAG_NON_PAGED, + m_FrameSize, + TONEGENERATOR_POOLTAG); + + IF_TRUE_ACTION_JUMP(m_PartialFrame == NULL, status = STATUS_INSUFFICIENT_RESOURCES, Done); + + status = STATUS_SUCCESS; + +Done: + return status; +} + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.h b/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.h new file mode 100644 index 000000000..a9d030b5f --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/ToneGenerator.h @@ -0,0 +1,88 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + ToneGenerator.h + +Abstract: + + Declaration of sine wave generator for ACX driver samples. + + +--*/ +#pragma once + +#define _USE_MATH_DEFINES +#include +#include + +class ToneGenerator +{ +public: + DWORD m_Frequency; + WORD m_ChannelCount; + WORD m_BitsPerSample; + DWORD m_SamplesPerSecond; + double m_Theta; + double m_SampleIncrement; + bool m_Mute; + BYTE* m_PartialFrame; + DWORD m_PartialFrameBytes; + DWORD m_FrameSize; + +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ToneGenerator(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~ToneGenerator(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS + Init + ( + _In_ DWORD ToneFrequency, + _In_ PWAVEFORMATEXTENSIBLE WfExt + ); + + __drv_maxIRQL(DISPATCH_LEVEL) + VOID + GenerateSine + ( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ size_t BufferLength + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID + SetMute + ( + _In_ bool Value + ) + { + PAGED_CODE(); + + m_Mute = Value; + } + +private: + __drv_maxIRQL(DISPATCH_LEVEL) + VOID InitNewFrame + ( + _Out_writes_bytes_(FrameSize) BYTE* Frame, + _In_ DWORD FrameSize + ); +}; + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/Trace_macros.h b/crossplatform/windows-driver/LibrePodsMic/Common/Trace_macros.h new file mode 100644 index 000000000..c2fc3efff --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/Trace_macros.h @@ -0,0 +1,470 @@ +#pragma once + +#include // for va_start, etc. + +#pragma region Tracing level definitions + +#if !defined(FAILED_NTSTATUS) +#define FAILED_NTSTATUS(status) (((NTSTATUS)(status)) < 0) +#endif + +#if !defined(SUCCEEDED_NTSTATUS) +#define SUCCEEDED_NTSTATUS(status) (((NTSTATUS)(status)) >= 0) +#endif + +//! Define shorter versions of the ETW trace levels +#define LEVEL_CRITICAL TRACE_LEVEL_CRITICAL +#define LEVEL_ERROR TRACE_LEVEL_ERROR +#define LEVEL_WARNING TRACE_LEVEL_WARNING +#define LEVEL_INFO TRACE_LEVEL_INFORMATION +#define LEVEL_VERBOSE TRACE_LEVEL_VERBOSE + +//! This is a special LEVEL that changes the trace macro level from ERROR to VERBOSE +//! depending on whether the return value passed to the macro was non-zero or zero, +//! respectively. +#define LEVEL_COND 0xFF +#pragma endregion + +//! Logger and Enabled that supports both level and flag. +//! \link https://msdn.microsoft.com/en-us/library/windows/hardware/ff542492(v=vs.85).aspx +#define WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) WPP_LEVEL_LOGGER(FLAGS) +#define WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) (WPP_LEVEL_ENABLED(FLAGS) && (WPP_CONTROL(WPP_BIT_ ## FLAGS).Level >= LEVEL)) + +//! This macro is to be used by the WPP custom macros below that want to do conditional +//! logging based on return value. If LEVEL_VERBOSE is specified when calling a macro that +//! uses this, the level will be set to LEVEL_INFO if return code is 0 or +//! LEVEL_ERROR if the return code is not 0. This can be called in any PRE macro. +//! +//! The "LEVEL == LEVEL_COND" check generates a compiler warning that the "conditional +//! expression is constant" so we explicitly disable that. +#define WPP_CONDITIONAL_LEVEL_FLAGS_OVERRIDE(LEVEL, FLAGS, HR) \ + BOOL bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS); \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4127)) \ + if (LEVEL == LEVEL_COND) \ + { \ + if (SUCCEEDED(HR)) \ + { \ + bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL_VERBOSE, FLAGS); \ + } \ + else \ + { \ + bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL_ERROR, FLAGS); \ + } \ + } \ + __pragma(warning(pop)) + +#define WPP_CONDITIONAL_LEVEL_FLAGS_OVERRIDE_NTSTATUS(LEVEL, FLAGS, STATUS) \ + BOOLEAN bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS); \ + __pragma(warning(push)) \ + __pragma(warning(disable: 4127)) \ + if (LEVEL == LEVEL_COND) \ + { \ + if (SUCCEEDED_NTSTATUS(STATUS)) \ + { \ + bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL_VERBOSE, FLAGS); \ + } \ + else \ + { \ + bEnabled = WPP_LEVEL_FLAGS_ENABLED(LEVEL_ERROR, FLAGS); \ + } \ + } \ + __pragma(warning(pop)) + + +#define WPP_LEVEL_FLAGS_IFRLOG_ENABLED(LEVEL, FLAGS, IFRLOG) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_IFRLOG_LOGGER(LEVEL, FLAGS, IFRLOG) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) +#define WPP_LEVEL_IFRLOG_FLAGS_ENABLED(LEVEL, IFRLOG, FLAGS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_IFRLOG_FLAGS_LOGGER(LEVEL, IFRLOG, FLAGS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_HR_PRE(LEVEL, FLAGS, HR) { WPP_CONDITIONAL_LEVEL_FLAGS_OVERRIDE(LEVEL, FLAGS, HR) +#define WPP_LEVEL_FLAGS_HR_POST(LEVEL, FLAGS, HR) ;} +#define WPP_LEVEL_FLAGS_HR_ENABLED(LEVEL, FLAGS, HR) bEnabled +#define WPP_LEVEL_FLAGS_HR_LOGGER(LEVEL, FLAGS, HR) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETVAL_ENABLED(LEVEL, FLAGS, RETVAL) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETVAL_LOGGER(LEVEL, FLAGS, RETVAL) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_FI_ENABLED(LEVEL, FLAGS, FI) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_FI_LOGGER(LEVEL, FLAGS, FI) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_STATUS_PRE(LEVEL, FLAGS, STATUS) { WPP_CONDITIONAL_LEVEL_FLAGS_OVERRIDE_NTSTATUS(LEVEL, FLAGS, STATUS) +#define WPP_LEVEL_FLAGS_STATUS_POST(LEVEL, FLAGS, STATUS) ;} +#define WPP_LEVEL_FLAGS_STATUS_ENABLED(LEVEL, FLAGS, STATUS) bEnabled +#define WPP_LEVEL_FLAGS_STATUS_LOGGER(LEVEL, FLAGS, STATUS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETSTATUS_PRE(LEVEL, FLAGS, RETSTATUS) do { NTSTATUS __statusRet = (RETSTATUS); if (FAILED_NTSTATUS(__statusRet)) { +#define WPP_LEVEL_FLAGS_RETSTATUS_POST(LEVEL, FLAGS, RETSTATUS) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_RETSTATUS_ENABLED(LEVEL, FLAGS, RETSTATUS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETSTATUS_LOGGER(LEVEL, FLAGS, RETSTATUS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_PRE(LEVEL, FLAGS, IFRLOG, RETSTATUS) do { NTSTATUS __statusRet = (RETSTATUS); if (FAILED_NTSTATUS(__statusRet)) { +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_POST(LEVEL, FLAGS, IFRLOG, RETSTATUS) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_ENABLED(LEVEL, FLAGS, IFRLOG, RETSTATUS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_LOGGER(LEVEL, FLAGS, IFRLOG, RETSTATUS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_PRE(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) do {\ +NTSTATUS __statusRet = (RETSTATUS);\ +if(__statusRet == ALLOWEDSTATUS)\ +{\ + __statusRet = STATUS_SUCCESS;\ +}\ +if (FAILED_NTSTATUS(__statusRet)) { +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_POST(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_ENABLED(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_LOGGER(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETPTR_PRE(LEVEL, FLAGS, RETPTR) do { if ((RETPTR) == nullptr) { +#define WPP_LEVEL_FLAGS_RETPTR_POST(LEVEL, FLAGS, RETPTR) ; return STATUS_INSUFFICIENT_RESOURCES; } } while (0, 0) +#define WPP_LEVEL_FLAGS_RETPTR_ENABLED(LEVEL, FLAGS, RETPTR) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETPTR_LOGGER(LEVEL, FLAGS, RETPTR) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETSTATUS_RETPTR_PRE(LEVEL, FLAGS, RETSTATUS, RETPTR) do { NTSTATUS __statusRet = (RETSTATUS); if ((RETPTR) == nullptr) { +#define WPP_LEVEL_FLAGS_RETSTATUS_RETPTR_POST(LEVEL, FLAGS, RETSTATUS, RETPTR) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_RETSTATUS_RETPTR_ENABLED(LEVEL, FLAGS, RETSTATUS, RETPTR) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETSTATUS_RETPTR_LOGGER(LEVEL, FLAGS, RETSTATUS, RETPTR) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETSTATUS_POSCOND_PRE(LEVEL, FLAGS, RETSTATUS, POSCOND) do { NTSTATUS __statusRet = (RETSTATUS); if ((POSCOND)) { +#define WPP_LEVEL_FLAGS_RETSTATUS_POSCOND_POST(LEVEL, FLAGS, RETSTATUS, POSCOND) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_RETSTATUS_POSCOND_ENABLED(LEVEL, FLAGS, RETSTATUS, POSCOND) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETSTATUS_POSCOND_LOGGER(LEVEL, FLAGS, RETSTATUS, POSCOND) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_PRE(LEVEL, FLAGS, IFRLOG, POSCOND, RETSTATUS) do { NTSTATUS __statusRet = (RETSTATUS); if ((POSCOND)) { +#define WPP_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_POST(LEVEL, FLAGS, IFRLOG, POSCOND, RETSTATUS) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_ENABLED(LEVEL, FLAGS, IFRLOG, POSCOND, RETSTATUS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_LOGGER(LEVEL, FLAGS, IFRLOG, POSCOND, RETSTATUS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#define WPP_LEVEL_FLAGS_RETSTATUS_NEGCOND_PRE(LEVEL, FLAGS, RETSTATUS, NEGCOND) do { NTSTATUS __statusRet = (RETSTATUS); if (!(NEGCOND)) { +#define WPP_LEVEL_FLAGS_RETSTATUS_NEGCOND_POST(LEVEL, FLAGS, RETSTATUS, NEGCOND) ; return __statusRet; } } while (0, 0) +#define WPP_LEVEL_FLAGS_RETSTATUS_NEGCOND_ENABLED(LEVEL, FLAGS, RETSTATUS, NEGCOND) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) +#define WPP_LEVEL_FLAGS_RETSTATUS_NEGCOND_LOGGER(LEVEL, FLAGS, RETSTATUS, NEGCOND) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) + +#pragma region IFR Enablement Macros + +// Opt-in to a WPP recorder feature that enables independent evaluation of conditions to decide if a +// message needs to be sent to the recorder, an enabled session, or both. +#define ENABLE_WPP_TRACE_FILTERING_WITH_WPP_RECORDER 1 + +// Logger/Enabled macros used to decide if a message that is being sent to a custom recorder should +// also go to an enabled session. These do not depend on the custom recorder itself, so just +// delegate to the default. +#define WPP_IFRLOG_LEVEL_FLAGS_LOGGER(IFRLOG, LEVEL, FLAGS) WPP_LEVEL_FLAGS_LOGGER(LEVEL, FLAGS) +#define WPP_IFRLOG_LEVEL_FLAGS_ENABLED(IFRLOG, LEVEL, FLAGS) WPP_LEVEL_FLAGS_ENABLED(LEVEL, FLAGS) + +#define WPP_RECORDER_CONDITIONAL_LEVEL_FLAGS_OVERRIDE(LEVEL, FLAGS, HR) \ + ((LEVEL == LEVEL_COND) ? \ + (FAILED(HR) ? \ + WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL_ERROR, FLAGS) : WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL_VERBOSE, FLAGS)) : \ + WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)) + +#define WPP_RECORDER_CONDITIONAL_LEVEL_FLAGS_OVERRIDE_NTSTATUS(LEVEL, FLAGS, STATUS) \ + ((LEVEL == LEVEL_COND) ? \ + (FAILED_NTSTATUS(STATUS) ? \ + WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL_ERROR, FLAGS) : WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL_VERBOSE, FLAGS)) : \ + WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS)) + +#define WPP_RECORDER_LEVEL_FLAGS_HR_ARGS(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_HR_FILTER(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETVAL_ARGS(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETVAL_FILTER(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_FI_ARGS(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_FI_FILTER(LEVEL, FLAGS, RETVAL) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_STATUS_ARGS(LEVEL, FLAGS, STATUS) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_STATUS_FILTER(LEVEL, FLAGS, STATUS) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_ARGS(LEVEL, FLAGS, RETSTATUS) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_FILTER(LEVEL, FLAGS, RETSTATUS) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_RETSTATUS_ARGS(LEVEL, FLAGS, IFRLOG, RETSTATUS) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_RETSTATUS_FILTER(LEVEL, FLAGS, IFRLOG, RETSTATUS) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_ARGS(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_RETSTATUS_ALLOWEDSTATUS_FILTER(LEVEL, FLAGS, IFRLOG, RETSTATUS, ALLOWEDSTATUS) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETPTR_ARGS(LEVEL, FLAGS, RETPTR) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETPTR_FILTER(LEVEL, FLAGS, RETPTR) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_RETPTR_ARGS(LEVEL, FLAGS, RETSTATUS, RETPTR) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_RETPTR_FILTER(LEVEL, FLAGS, RETSTATUS, RETPTR) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_POSCOND_ARGS(LEVEL, FLAGS, RETSTATUS, POSCOND) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_POSCOND_FILTER(LEVEL, FLAGS, RETSTATUS, POSCOND) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_ARGS(LEVEL, FLAGS, IFRLOG, RETSTATUS, POSCOND) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_IFRLOG_POSCOND_RETSTATUS_FILTER(LEVEL, FLAGS, IFRLOG, RETSTATUS, POSCOND) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) + +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_NEGCOND_ARGS(LEVEL, FLAGS, RETSTATUS, NEGCOND) WPP_RECORDER_LEVEL_FLAGS_ARGS(LEVEL, FLAGS) +#define WPP_RECORDER_LEVEL_FLAGS_RETSTATUS_NEGCOND_FILTER(LEVEL, FLAGS, RETSTATUS, NEGCOND) WPP_RECORDER_LEVEL_FLAGS_FILTER(LEVEL, FLAGS) +#pragma endregion + +#pragma region Custom tracing macros + +// begin_wpp config +// USEPREFIX(DrvLogCritical, "%!STDPREFIX!CRIT: "); +// USEPREFIX(DrvLogError, "%!STDPREFIX!ERROR: "); +// USEPREFIX(DrvLogWarning, "%!STDPREFIX!WARN: "); +// USEPREFIX(DrvLogInfo, "%!STDPREFIX!INFO: "); +// USEPREFIX(DrvLogVerbose, "%!STDPREFIX!VERB: "); +// USEPREFIX(DrvLogEnter, "%!STDPREFIX!ENTER"); +// USEPREFIX(DrvLogExit, "%!STDPREFIX!EXIT"); +// end_wpp + +// begin_wpp config +// FUNC DrvLogCritical{LEVEL=TRACE_LEVEL_CRITICAL}(IFRLOG,FLAGS,MSG,...); +// FUNC DrvLogError{LEVEL=TRACE_LEVEL_ERROR}(IFRLOG,FLAGS,MSG,...); +// FUNC DrvLogWarning{LEVEL=TRACE_LEVEL_WARNING}(IFRLOG,FLAGS,MSG,...); +// FUNC DrvLogInfo{LEVEL=TRACE_LEVEL_INFORMATION}(IFRLOG,FLAGS,MSG,...); +// FUNC DrvLogEnter{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=FLAG_FUNCTION}(IFRLOG,...); +// FUNC DrvLogVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(IFRLOG,FLAGS,MSG,...); +// FUNC DrvLogExit{LEVEL=TRACE_LEVEL_VERBOSE,FLAGS=FLAG_FUNCTION}(IFRLOG,...); +// end_wpp + + +#ifdef __INTELLISENSE__ +#define FLAG_DEVICE_ALL 0x01 +#define FLAG_FUNCTION 0x02 +#define FLAG_INFO 0x04 +#define FLAG_PNP 0x08 +#define FLAG_POWER 0x10 +#define FLAG_STREAM 0x20 +#define FLAG_INIT 0x40 +#define FLAG_DDI 0x80 +#define FLAG_GENERIC 0x100 +void DrvLogCritical(void* log, int flags, const WCHAR* fmt, ...); +void DrvLogError(void* log, int flags, const WCHAR* fmt, ...); +void DrvLogWarning(void* log, int flags, const WCHAR* fmt, ...); +void DrvLogInfo(void* log, int flags, const WCHAR* fmt, ...); +void DrvLogEnter(void* log, ...); +void DrvLogVerbose(void* log, int flags, const WCHAR* fmt, ...); +void DrvLogExit(void* log, ...); + +void RETURN_IF_FAILED(NTSTATUS status); +void RETURN_NTSTATUS_IF_FAILED(NTSTATUS status); +void RETURN_NTSTATUS_IF_FAILED_MSG(NTSTATUS status, const WCHAR* fmt, ...); +void RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED(NTSTATUS returnStatus, NTSTATUS allowedStatus); +void RETURN_NTSTATUS_IF_NULL_ALLOC(PVOID ptr); +void RETURN_NTSTATUS_IF_NULL(PVOID ptr); +void RETURN_NTSTATUS_IF_TRUE(BOOL condition, NTSTATUS status); +void RETURN_NTSTATUS_IF_TRUE_MSG(BOOL condition, NTSTATUS status, const WCHAR* fmt, ...); +void RETURN_NTSTATUS_IF_FALSE(BOOL condition, NTSTATUS status); +void RETURN_NTSTATUS(NTSTATUS status); +void RETURN_NTSTATUS_MSG(NTSTATUS status, const WCHAR* fmt, ...); +#endif// __INTELLISENSE__ + +//********************************************************* +// MACRO: TRACE_METHOD_LINE +// +// begin_wpp config +// FUNC TRACE_METHOD_LINE(LEVEL, FLAGS, MSG, ...); +// USESUFFIX (TRACE_METHOD_LINE, ", this=0x%p", this); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_ENTRY +// +// begin_wpp config +// FUNC TRACE_METHOD_ENTRY(LEVEL, FLAGS); +// USESUFFIX (TRACE_METHOD_ENTRY, "Enter, this=0x%p", this); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_EXIT +// +// begin_wpp config +// FUNC TRACE_METHOD_EXIT(LEVEL, FLAGS); +// USESUFFIX (TRACE_METHOD_EXIT, "Exit, this=0x%p", this); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_EXIT_HR +// +// begin_wpp config +// FUNC TRACE_METHOD_EXIT_HR(LEVEL, FLAGS, HR); +// USESUFFIX (TRACE_METHOD_EXIT_HR, "Exit, this=0x%p, hr=%!HRESULT!", this, HR); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_EXIT_DWORD +// +// begin_wpp config +// FUNC TRACE_METHOD_EXIT_DWORD(LEVEL, FLAGS, RETVAL); +// USESUFFIX (TRACE_METHOD_EXIT_DWORD, "Exit, this=0x%p, ret=0x%08Ix ", this, RETVAL); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_EXIT_PTR +// +// begin_wpp config +// FUNC TRACE_METHOD_EXIT_PTR(LEVEL, FLAGS, RETVAL); +// USESUFFIX (TRACE_METHOD_EXIT_PTR,"Exit, this=0x%p, retptr=0x%p", this, RETVAL); +// end_wpp + +//********************************************************* +// MACRO: TRACE_METHOD_EXIT_STATUS +// +// begin_wpp config +// FUNC TRACE_METHOD_EXIT_STATUS(LEVEL, FLAGS, STATUS); +// USESUFFIX (TRACE_METHOD_EXIT_STATUS, "Exit, this=0x%p, status=%!STATUS!", this, STATUS); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_ENTRY +// +// begin_wpp config +// FUNC TRACE_FUNCTION_ENTRY(LEVEL, FLAGS); +// USESUFFIX (TRACE_FUNCTION_ENTRY, "Enter"); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_EXIT +// +// begin_wpp config +// FUNC TRACE_FUNCTION_EXIT(LEVEL, FLAGS); +// USESUFFIX (TRACE_FUNCTION_EXIT, "Exit"); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_EXIT_HR +// +// begin_wpp config +// FUNC TRACE_FUNCTION_EXIT_HR(LEVEL, FLAGS, HR); +// USESUFFIX (TRACE_FUNCTION_EXIT_HR, "Exit, hr=%!HRESULT!", HR); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_EXIT_DWORD +// +// begin_wpp config +// FUNC TRACE_FUNCTION_EXIT_DWORD(LEVEL, FLAGS, RETVAL); +// USESUFFIX (TRACE_FUNCTION_EXIT_DWORD, "Exit, ret=0x%08Ix", RETVAL); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_EXIT_PTR +// +// begin_wpp config +// FUNC TRACE_FUNCTION_EXIT_PTR(LEVEL, FLAGS, RETVAL); +// USESUFFIX (TRACE_FUNCTION_EXIT_PTR, "Exit, retptr=0x%p", RETVAL); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FUNCTION_EXIT_STATUS +// +// begin_wpp config +// FUNC TRACE_FUNCTION_EXIT_STATUS(LEVEL, FLAGS, STATUS); +// USESUFFIX (TRACE_FUNCTION_EXIT_STATUS, "Exit, status=%!STATUS!", STATUS); +// end_wpp + +//********************************************************* +// MACRO: TRACE_LINE +// +// begin_wpp config +// FUNC TRACE_LINE(LEVEL, FLAGS, MSG, ...); +// end_wpp + +//********************************************************* +// MACRO: TRACE_HRESULT +// +// begin_wpp config +// FUNC TRACE_HRESULT(LEVEL, FLAGS, HR, MSG, ...); +// USESUFFIX (TRACE_HRESULT, ", ret=%!HRESULT!", HR); +// end_wpp + +//********************************************************* +// MACRO: TRACE_FAILURE_INFO (WIL FailureInfo logging) +// see: https://github.com/microsoft/wil/blob/master/include/wil/result_macros.h +// +// begin_wpp config +// FUNC TRACE_FAILURE_INFO(LEVEL, FLAGS, FI); +// USESUFFIX(TRACE_FAILURE_INFO, " [%04X] '%ws', hr=%!HRESULT! ['%s' (%u)]", FI.threadId, FI.pszMessage, FI.hr, FI.pszFile, FI.uLineNumber); +// end_wpp + +// MACRO: RETURN_IF_FAILED +// +// begin_wpp config +// FUNC RETURN_IF_FAILED{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS); +// USEPREFIX(RETURN_IF_FAILED, "%!STDPREFIX!ERROR:"); +// USESUFFIX(RETURN_IF_FAILED, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + + +// MACRO: RETURN_NTSTATUS_IF_FAILED +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_FAILED{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS); +// USEPREFIX(RETURN_NTSTATUS_IF_FAILED, "%!STDPREFIX!ERROR:"); +// USESUFFIX(RETURN_NTSTATUS_IF_FAILED, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_FAILED_MSG +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_FAILED_MSG{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS, MSG, ...); +// USEPREFIX(RETURN_NTSTATUS_IF_FAILED_MSG, "%!STDPREFIX!ERROR:"); +// USESUFFIX(RETURN_NTSTATUS_IF_FAILED_MSG, " - status=%!STATUS!",__statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS, ALLOWEDSTATUS); +// USEPREFIX(RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED, "%!STDPREFIX!ERROR:"); +// USESUFFIX(RETURN_NTSTATUS_IF_FAILED_UNLESS_ALLOWED, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_NULL_ALLOC +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_NULL_ALLOC{LEVEL=LEVEL_ERROR,FLAGS=DUMMY}(RETPTR); +// USESUFFIX(RETURN_NTSTATUS_IF_NULL, "status=STATUS_INSUFFICIENT_RESOURCES"); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_NULL +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_NULL{LEVEL=LEVEL_ERROR,FLAGS=DUMMY}(RETSTATUS, RETPTR); +// USESUFFIX(RETURN_NTSTATUS_IF_NULL, "status=%!STATUS!", __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_TRUE +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_TRUE{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(POSCOND, RETSTATUS); +// USESUFFIX(RETURN_NTSTATUS_IF_TRUE, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_TRUE_MSG +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_TRUE_MSG{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(POSCOND, RETSTATUS, MSG, ...); +// USESUFFIX(RETURN_NTSTATUS_IF_TRUE_MSG, " - status=%!STATUS!", __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_IF_FALSE +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_IF_FALSE{LEVEL=LEVEL_ERROR,FLAGS=DUMMY}(RETSTATUS, NEGCOND); +// USESUFFIX(RETURN_NTSTATUS_IF_FALSE, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS +// +// begin_wpp config +// FUNC RETURN_NTSTATUS{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS); +// USESUFFIX(RETURN_NTSTATUS, " File:%s, Line:%d - status=%!STATUS!", __FILE__, __LINE__, __statusRet); +// end_wpp + +// MACRO: RETURN_NTSTATUS_MSG +// +// begin_wpp config +// FUNC RETURN_NTSTATUS_MSG{LEVEL=LEVEL_ERROR,FLAGS=FLAG_DEVICE_ALL,IFRLOG=g_AudioDspLog}(RETSTATUS, MSG, ...); +// USESUFFIX(RETURN_NTSTATUS_MSG, " - status=%!STATUS!", __statusRet); +// end_wpp + +#define W32 +#define WPP_CHECK_FOR_NULL_STRING //to prevent exceptions due to NULL strings + +#pragma endregion diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.cpp new file mode 100644 index 000000000..5deb5a91e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.cpp @@ -0,0 +1,769 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + WaveReader.cpp + +Abstract: + Implementation of wave file reader for ACX sample drivers. + + To read data from disk, this class maintains a circular data buffer. This buffer is segmented into multiple chunks of + big buffer (Though we only need two, so it is set to two now). Initially we fill first two chunks and once a chunk gets emptied + by OS, we schedule a workitem to fill the next available chunk. + + +--*/ + +#pragma warning (disable : 4127) +#pragma warning (disable : 26165) + +#include "private.h" +#include +#include +#include +#include +#include "WaveReader.h" + +#define FILE_NAME_BUFFER_TAG 'WRT1' +#define WAVE_DATA_BUFFER_TAG 'WRT2' +#define WORK_ITEM_BUFFER_TAG 'WRT3' + +#define MAX_READ_WORKER_ITEM_COUNT 15 + +#define IF_FAILED_JUMP(result, tag) do {if (!NT_SUCCESS(result)) {goto tag;}} while(false) +#define IF_TRUE_JUMP(result, tag) do {if (result) {goto tag;}} while(false) +#define IF_TRUE_ACTION_JUMP(result, action, tag) do {if (result) {action; goto tag;}} while(false) + +PREADWORKER_PARAM CWaveReader::m_pWorkItems = NULL; +PDEVICE_OBJECT CWaveReader::m_pDeviceObject = NULL; + + +/*++ + +Routine Description: + Ctor: basic init. + +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +CWaveReader::CWaveReader() +: m_ChannelCount(0), + m_BitsPerSample(0), + m_SamplesPerSecond(0), + m_Mute(false), + m_FileHandle(NULL) +{ + PAGED_CODE(); + m_WaveDataQueue.pWavData = NULL; + KeInitializeMutex(&m_FileSync, 0); +} + +/*++ + +Routine Description: + Dtor: free resources. + +--*/ +_Use_decl_annotations_ +PAGED_CODE_SEG +CWaveReader::~CWaveReader() +{ + PAGED_CODE(); + if (STATUS_SUCCESS == KeWaitForSingleObject + ( + &m_FileSync, + Executive, + KernelMode, + FALSE, + NULL + )) + { + if (m_WaveDataQueue.pWavData != NULL) + { + ExFreePoolWithTag(m_WaveDataQueue.pWavData, WAVE_DATA_BUFFER_TAG); + m_WaveDataQueue.pWavData = NULL; + } + + FileClose(); + KeReleaseMutex(&m_FileSync, FALSE); + } + +} + +/*++ + +Routine Description: + - Initializing the workitems. These workitems will be scheduled asynchronously by the OS. + - When these work items will be scheduled the wave file will be read and the data + - will be put inside the big chunks. + +Arguments: + Device object + +Return Value: + NT status code. + +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::InitializeWorkItems(_In_ PDEVICE_OBJECT DeviceObject) +{ + PAGED_CODE(); + + ASSERT(DeviceObject); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (m_pWorkItems != NULL) + { + return ntStatus; + } + + m_pWorkItems = (PREADWORKER_PARAM) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + sizeof(READWORKER_PARAM) * MAX_READ_WORKER_ITEM_COUNT, + 'RDPT' + ); + if (m_pWorkItems) + { + for (int i = 0; i < MAX_READ_WORKER_ITEM_COUNT; i++) + { + + m_pWorkItems[i].WorkItem = IoAllocateWorkItem(DeviceObject); + if (m_pWorkItems[i].WorkItem == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + KeInitializeEvent + ( + &m_pWorkItems[i].EventDone, + NotificationEvent, + TRUE + ); + } + } + else + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + + return ntStatus; +} + +/*++ + +Routine Description: +- Wait for all the scheduled workitems to finish. + +--*/ + + +//============================================================================= +_Use_decl_annotations_ +PAGED_CODE_SEG +void CWaveReader::WaitAllWorkItems() +{ + PAGED_CODE(); + + for (int i = 0; i < MAX_READ_WORKER_ITEM_COUNT; i++) + { + KeWaitForSingleObject + ( + &(m_pWorkItems[i].EventDone), + Executive, + KernelMode, + FALSE, + NULL + ); + } +} + +/*++ + +Routine Description: + - Deallocating the workitems. + +--*/ + + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID CWaveReader::DestroyWorkItems() +{ + PAGED_CODE(); + + if (m_pWorkItems) + { + for (int i = 0; i < MAX_READ_WORKER_ITEM_COUNT; i++) + { + if (m_pWorkItems[i].WorkItem != NULL) + { + IoFreeWorkItem(m_pWorkItems[i].WorkItem); + m_pWorkItems[i].WorkItem = NULL; + } + } + ExFreePoolWithTag(m_pWorkItems, WORK_ITEM_BUFFER_TAG); + m_pWorkItems = NULL; + } +} + +/*++ + +Routine Description: + - Get a free work item to schedule a file read operation. + +--*/ +_Use_decl_annotations_ +PREADWORKER_PARAM CWaveReader::GetNewWorkItem() +{ + LARGE_INTEGER timeOut = { 0 }; + NTSTATUS ntStatus; + + for (int i = 0; i < MAX_READ_WORKER_ITEM_COUNT; i++) + { + ntStatus = + KeWaitForSingleObject + ( + &m_pWorkItems[i].EventDone, + Executive, + KernelMode, + FALSE, + &timeOut + ); + if (STATUS_SUCCESS == ntStatus) + { + if (m_pWorkItems[i].WorkItem) + return &(m_pWorkItems[i]); + else + return NULL; + } + } + + return NULL; +} + +/*++ +Routine Description: +- This routine will enqueue a workitem for reading wave file and putting +- the data into the chunk buffer. + +Arguments: + Chunk descriptor for the chunk to be filled. +--*/ + +_Use_decl_annotations_ +VOID CWaveReader::ReadWavChunk(PCHUNKDESCRIPTOR pChunkDescriptor) +{ + PREADWORKER_PARAM pParam = NULL; + + pParam = GetNewWorkItem(); + if (pParam) + { + pParam->PtrWaveReader = this; + pParam->PtrChunkDescriptor = pChunkDescriptor; + KeResetEvent(&pParam->EventDone); + IoQueueWorkItem(pParam->WorkItem, ReadFrameWorkerCallback, + DelayedWorkQueue, (PVOID)pParam); + } +} + +_Use_decl_annotations_ +PAGED_CODE_SEG +IO_WORKITEM_ROUTINE ReadFrameWorkerCallback; +/* +Routine Description: +- This routine will be called by the OS. It will fill the chunk buffer, defined by the chunk descriptor +- If end of file is reached it will mark the end of file as true. + +Arguments: + pDeviceObject - Device object + Context - pointer to reader worker params +*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +VOID ReadFrameWorkerCallback +( + _In_ PDEVICE_OBJECT pDeviceObject, + _In_opt_ PVOID Context +) +{ + PAGED_CODE(); + UNREFERENCED_PARAMETER(pDeviceObject); + pWaveReader pWavRd; + PREADWORKER_PARAM pParam = (PREADWORKER_PARAM)Context; + + if (NULL == pParam) + { + // This is completely unexpected, assert here. + // + ASSERT(pParam); + goto exit; + } + + pWavRd = pParam->PtrWaveReader; + + if (pWavRd == NULL) + { + goto exit; + } + if (STATUS_SUCCESS == KeWaitForSingleObject + ( + &pWavRd->m_FileSync, + Executive, + KernelMode, + FALSE, + NULL + )) + { + + NTSTATUS ntStatus = STATUS_SUCCESS; + + ASSERT(Context); + + IO_STATUS_BLOCK ioStatusBlock; + + if (pParam->WorkItem) + { + if (pWavRd->m_WaveDataQueue.bEofReached || pWavRd->m_WaveDataQueue.pWavData == NULL) + { + KeReleaseMutex(&pWavRd->m_FileSync, FALSE); + goto exit; + } + + if (pParam->PtrChunkDescriptor->pStartAddress != NULL) + { + ntStatus = ZwReadFile(pWavRd->m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + pParam->PtrChunkDescriptor->pStartAddress, + pParam->PtrChunkDescriptor->ulChunkLength, + NULL, + NULL); + + pParam->PtrChunkDescriptor->bIsChunkEmpty = false; + + if (ioStatusBlock.Information != pParam->PtrChunkDescriptor->ulChunkLength) + { + pWavRd->m_WaveDataQueue.bEofReached = true; + } + } + } + + KeReleaseMutex(&pWavRd->m_FileSync, FALSE); + } + +exit: + KeSetEvent(&pParam->EventDone, 0, FALSE); +} + +/*++ + +Routine Description: +- If all the chunks are empty this resturn true. + +--*/ + +_Use_decl_annotations_ +bool CWaveReader::IsAllChunkEmpty() +{ + for (int i = 0; i < NUM_OF_CHUNK_FOR_FILE_READ; i++) + { + if (!m_WaveDataQueue.sChunkDescriptor[i].bIsChunkEmpty) + { + return false; + } + } + return true; +} + +/*++ +Routine Description: + - This routine does the actual copy of data from the chunk buffer to the buffer provided by OS. + - If it empties the current chunk buffer, then it sets it state to empty and then enqueue a workitem + - to read data from the wave file and put it to the next available chunk buffer. + +Arguments: + Buffer - Pointer to the OS buffer + BufferLength - Length of the data to be filled (in bytes) + +--*/ +_Use_decl_annotations_ +VOID CWaveReader::CopyDataFromRingBuffer +( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ ULONG BufferLength +) +{ + if (IsAllChunkEmpty()) + { + RtlZeroMemory(Buffer, BufferLength); + } + else + { + ULONG prevChunk = (m_WaveDataQueue.ulReadPtr*NUM_OF_CHUNK_FOR_FILE_READ )/ m_WaveDataQueue.ulLength; + + ///////////////// + BYTE *currentBuf = Buffer; + ULONG length = BufferLength; + while (length > 0) + { + ULONG runWrite = min(length, m_WaveDataQueue.ulLength - m_WaveDataQueue.ulReadPtr); + + // Copy the wave buffer data to OS buffer + RtlCopyMemory(currentBuf, m_WaveDataQueue.pWavData + m_WaveDataQueue.ulReadPtr, runWrite); + // Zero out the wave buffer, so that if wave end of file is reached we should copy only zeros + RtlZeroMemory(m_WaveDataQueue.pWavData + m_WaveDataQueue.ulReadPtr, runWrite); + // Update the read pointer + m_WaveDataQueue.ulReadPtr = (m_WaveDataQueue.ulReadPtr + runWrite) % m_WaveDataQueue.ulLength; + currentBuf += runWrite; + length = length - runWrite; + } + + ULONG curChunk = (m_WaveDataQueue.ulReadPtr*NUM_OF_CHUNK_FOR_FILE_READ) / m_WaveDataQueue.ulLength; + + if (curChunk != prevChunk) + { + m_WaveDataQueue.currentExecutedChunk++; + // Schedule a workitem to read data from the wave file + ULONG chunkNo = m_WaveDataQueue.currentExecutedChunk % NUM_OF_CHUNK_FOR_FILE_READ; + m_WaveDataQueue.sChunkDescriptor[chunkNo].bIsChunkEmpty = true; + if (!m_WaveDataQueue.bEofReached) + { + ReadWavChunk(&m_WaveDataQueue.sChunkDescriptor[chunkNo]); + } + } + } +} + +/*++ +Routine Description: + - Just a high level read buffer call. + + Arguments: + Buffer - Pointer to the OS buffer + BufferLength - Length of the data to be filled (in bytes) +--*/ + +_Use_decl_annotations_ +VOID CWaveReader::ReadWaveData +( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ ULONG BufferLength +) +{ + if (m_Mute) + { + RtlZeroMemory(Buffer, BufferLength); + } + else + { + CopyDataFromRingBuffer(Buffer, BufferLength); + } +} + +/*++ +Routine Description: +- initialization for the wavereader member variables, +- Allocating memory for the 1 second buffer +- Preread the one second buffer data, so that when OS comes to read the data we have it available in the memory. + +Arguments: + WfExt - Format which should be used for capture + fileNameString - name of the file to be read + +Return: + NTStatus +--*/ +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::Init +( + _In_ PWAVEFORMATEXTENSIBLE WfExt, + _In_ PUNICODE_STRING puiFileName +) +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + KFLOATING_SAVE saveData; + + // Save floating state (just in case). + ntStatus = KeSaveFloatingPointState(&saveData); + if (!NT_SUCCESS(ntStatus)) + { + return ntStatus; + } + + // + // This sample supports PCM 16bit formats only. + // + if ((WfExt->Format.wFormatTag != WAVE_FORMAT_PCM && + !(WfExt->Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE && + IsEqualGUIDAligned(WfExt->SubFormat, KSDATAFORMAT_SUBTYPE_PCM))) || + (WfExt->Format.wBitsPerSample != 16 && + WfExt->Format.wBitsPerSample != 8)) + { + ntStatus = STATUS_NOT_SUPPORTED; + } + IF_FAILED_JUMP(ntStatus, Done); + + // Basic init. + m_ChannelCount = WfExt->Format.nChannels; // # channels. + m_BitsPerSample = WfExt->Format.wBitsPerSample; // bits per sample. + m_SamplesPerSecond = WfExt->Format.nSamplesPerSec; // samples per sec. + m_Mute = false; + + // Wave data queue initialization + m_WaveDataQueue.ulLength = WfExt->Format.nAvgBytesPerSec; + m_WaveDataQueue.bEofReached = false; + m_WaveDataQueue.ulReadPtr = 0; + + // Mark all the chunk empty + for (int i = 0; i < NUM_OF_CHUNK_FOR_FILE_READ; i++) + { + m_WaveDataQueue.sChunkDescriptor[i].bIsChunkEmpty = true; + } + + ntStatus = OpenWaveFile(puiFileName); + IF_FAILED_JUMP(ntStatus, Done); + + ntStatus = AllocateBigBuffer(); + IF_FAILED_JUMP(ntStatus, Done); + + ntStatus = ReadHeaderAndFillBuffer(); + +Done: + (void)KeRestoreFloatingPointState(&saveData); + return ntStatus; +} + +/*++ +Routine Description: + This function read the wave header file and compare the header info with the + stream info. Currently we are using only number of channel, sampling frequency + and bits per sample as the primary parameters for the wave file to compare against + stream params. If the params don't match we return success but streams zeros. + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::ReadHeaderAndFillBuffer() +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + ntStatus = FileReadHeader(); + + if(NT_SUCCESS(ntStatus)) + { + if (m_WaveHeader.numChannels != m_ChannelCount || + m_WaveHeader.bitsPerSample != m_BitsPerSample || + m_WaveHeader.sampleRate != m_SamplesPerSecond) + { + // If the wave file format don't match we wont treat this as error + // and we will stream zeros. So we return from here and will not read the + // wave file and wont fill the buffers. + return STATUS_SUCCESS; + } + } + + if (NT_SUCCESS(ntStatus)) + { + // If the wave file format is same as the stream format we will stream the data + // else we will just stream zeros. + ReadWavChunk(&m_WaveDataQueue.sChunkDescriptor[0]); // Fill the first chunk + ReadWavChunk(&m_WaveDataQueue.sChunkDescriptor[1]); // Fill the second chunk + // Set the current executed chunk to 1. Once OS finishs the data for the first chunk + // use the currentExecutedChunk to find the next chunk and schedule a workitem to fill the + // data into the next chunk + m_WaveDataQueue.currentExecutedChunk = 1; + } + + return ntStatus; +} + +/*++ +Routine Description: + This function allocates 1 second buffer. + Segments the buffer into multiple (currently two) chunks. Assigns the start pointer and length + for each chunk. + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::AllocateBigBuffer() +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + + m_WaveDataQueue.pWavData = (PBYTE) + ExAllocatePool2 + ( + POOL_FLAG_NON_PAGED, + m_WaveDataQueue.ulLength, + WAVE_DATA_BUFFER_TAG + ); + if (!m_WaveDataQueue.pWavData) + { + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + } + else + { + ULONG chunklLength = m_WaveDataQueue.ulLength / NUM_OF_CHUNK_FOR_FILE_READ; + for (int i = 0; i < NUM_OF_CHUNK_FOR_FILE_READ; i++) + { + m_WaveDataQueue.sChunkDescriptor[i].pStartAddress = m_WaveDataQueue.pWavData + chunklLength*i; + m_WaveDataQueue.sChunkDescriptor[i].ulChunkLength = chunklLength; + } + } + return ntStatus; +} + +/*++ +Routine Description: + This function opens wave file. + +Arguments: + fileNameString - Name of the wave file + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::OpenWaveFile(PUNICODE_STRING puiFileName) +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (NT_SUCCESS(ntStatus) && puiFileName->Buffer != NULL) + { + // Create data file. + InitializeObjectAttributes + ( + &m_objectAttributes, + puiFileName, + OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, + NULL, + NULL + ); + + // Open Wave File + ntStatus = FileOpen(); + } + + return ntStatus; +} + +/*++ +Routine Description: + This function closes wave file handle. + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::FileClose() +{ + PAGED_CODE(); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + if (m_FileHandle) + { + ntStatus = ZwClose(m_FileHandle); + m_FileHandle = NULL; + } + + return ntStatus; +} + +/*++ +Routine Description: + Reads the wave file file header information + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::FileReadHeader() +{ + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STATUS_BLOCK ioStatusBlock; + + + ntStatus = ZwReadFile(m_FileHandle, + NULL, + NULL, + NULL, + &ioStatusBlock, + &m_WaveHeader, + sizeof(WAVEHEADER), + NULL, + NULL); + + return ntStatus; +} + +/*++ +Routine Description: + This function opens wave file. + +Return: + NTStatus +--*/ + +_Use_decl_annotations_ +PAGED_CODE_SEG +NTSTATUS CWaveReader::FileOpen() +{ + + PAGED_CODE(); + NTSTATUS ntStatus = STATUS_SUCCESS; + IO_STATUS_BLOCK ioStatusBlock; + + if (!m_FileHandle) + { + ntStatus = + ZwCreateFile + ( + &m_FileHandle, + GENERIC_READ, + &m_objectAttributes, + &ioStatusBlock, + NULL, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ, + FILE_OPEN, + FILE_SYNCHRONOUS_IO_NONALERT, + NULL, + 0 + ); + } + + return ntStatus; +} + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.h b/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.h new file mode 100644 index 000000000..3c8394e4f --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/WaveReader.h @@ -0,0 +1,196 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + WaveReader.h + +Abstract: + + Declaration of wave reader for ACX sample drivers. + + +--*/ +#pragma once + +#define _USE_MATH_DEFINES +#include +#include + +#define NUM_OF_CHUNK_FOR_FILE_READ 2 + +class CWaveReader; + +// Wave header structure decleration +typedef CWaveReader *pWaveReader; +typedef struct _WAVEHEADER +{ + BYTE chunkId[4]; + ULONG chunkSize; + BYTE format[4]; + BYTE subChunkId[4]; + ULONG subChunkSize; + WORD audioFormat; + WORD numChannels; + ULONG sampleRate; + ULONG bytesPerSecond; + WORD blockAlign; + WORD bitsPerSample; + BYTE dataChunkId[4]; + ULONG dataSize; +}WAVEHEADER; + +typedef struct _CHUNKDESCRIPTOR +{ + PBYTE pStartAddress; // Starting address of the chunk + ULONG ulChunkLength; // Length of the chunk + bool bIsChunkEmpty; // If the chunk is empty +}CHUNKDESCRIPTOR; +typedef CHUNKDESCRIPTOR *PCHUNKDESCRIPTOR; + +/* + The idea here is to allocate one second long worth of buffer and divide it into NUM_OF_CHUNK_FOR_FILE_READ chunks. + In one file read operation we read and fill one chunk data . The chunk will be emptied every 10 ms by OS. + Once the OS empties one chunk data we schedule a workitem to read and fill next available chunk. +*/ + +typedef struct _WAVEDATAQUEUE +{ + PBYTE pWavData; // Pointer to the temporary buffer for reading one second worth of data from wave file + ULONG ulLength; // length of pWavData in bytes + ULONG ulReadPtr; // current reading position in pWavData in bytes + bool bEofReached; // This will be set once the eof is reached. + WORD currentExecutedChunk; + CHUNKDESCRIPTOR sChunkDescriptor[NUM_OF_CHUNK_FOR_FILE_READ]; +}WAVEDATAQUEUE; +typedef WAVEDATAQUEUE *PWAVEDATAQUEUE; + +// Parameter to workitem. +#include +typedef struct _READWORKER_PARAM { + PIO_WORKITEM WorkItem; // Pointer to the workitem + KEVENT EventDone; // Used for synchronizing a workitem for scheduling. + pWaveReader PtrWaveReader; // pointer to the wavereader class. + PCHUNKDESCRIPTOR PtrChunkDescriptor; // chunk descriptor for the chunk, which needs to be filled after file read +} READWORKER_PARAM; +typedef READWORKER_PARAM *PREADWORKER_PARAM; +#include + +__drv_maxIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +IO_WORKITEM_ROUTINE ReadFrameWorkerCallback; + +// Wave Reader class + +class CWaveReader +{ + +public: + HANDLE m_FileHandle; // Wave File handle. + WORD m_ChannelCount; // Number of Channels for the stream during stream init + WORD m_BitsPerSample; // Number of Bits per sample for the stream during stream init + DWORD m_SamplesPerSecond; // Number of Sample per second for the stream during stream init + bool m_Mute; // Capture Zero buffer if mute + OBJECT_ATTRIBUTES m_objectAttributes; // Used for opening file. + WAVEDATAQUEUE m_WaveDataQueue; // Big buffer data object and its current state + KMUTEX m_FileSync; // Synchronizes file access + WAVEHEADER m_WaveHeader; + +public: + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + CWaveReader(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + ~CWaveReader(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS Init + ( + _In_ PWAVEFORMATEXTENSIBLE WfExt, + _In_ PUNICODE_STRING puiFileName + ); + + __drv_maxIRQL(DISPATCH_LEVEL) + VOID ReadWaveData + ( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ ULONG BufferLength + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + VOID SetMute(_In_ bool Value) + { + PAGED_CODE(); + + m_Mute = Value; + } + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + void WaitAllWorkItems(); + + // Static allocation totally related to the workitems for reading data from wavefile and putting it to chunk buffer + static PDEVICE_OBJECT m_pDeviceObject; + static PREADWORKER_PARAM m_pWorkItems; + PAGED_CODE_SEG + static NTSTATUS InitializeWorkItems(_In_ PDEVICE_OBJECT DeviceObject); + + __drv_maxIRQL(DISPATCH_LEVEL) + static PREADWORKER_PARAM GetNewWorkItem(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + static VOID DestroyWorkItems(); + +private: + __drv_maxIRQL(DISPATCH_LEVEL) + VOID ReadWavChunk(PCHUNKDESCRIPTOR PtrChunkDescriptor); + + __drv_maxIRQL(DISPATCH_LEVEL) + bool IsAllChunkEmpty(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS OpenWaveFile(PUNICODE_STRING puiFileName); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS FileClose(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS FileReadHeader(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS FileOpen(); + + __drv_maxIRQL(DISPATCH_LEVEL) + VOID CopyDataFromRingBuffer + ( + _Out_writes_bytes_(BufferLength) BYTE *Buffer, + _In_ ULONG BufferLength + ); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS AllocateBigBuffer(); + + __drv_maxIRQL(PASSIVE_LEVEL) + PAGED_CODE_SEG + NTSTATUS ReadHeaderAndFillBuffer(); + + friend IO_WORKITEM_ROUTINE ReadFrameWorkerCallback; +}; + + diff --git a/crossplatform/windows-driver/LibrePodsMic/Inc/AudioFormats.h b/crossplatform/windows-driver/LibrePodsMic/Inc/AudioFormats.h new file mode 100644 index 000000000..a518d4771 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Inc/AudioFormats.h @@ -0,0 +1,959 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + AudioFormats.h + +Abstract: + + Contains Audio formats supported for the ACX Sample Drivers + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#define NOBITMAP +#include + +// +// Basic-testing formats. +// +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm44100c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 44100, + 176400, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm44100c2_24in32 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 44100, + 352800, + 8, + 32, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 24, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm48000c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm48000c2_24in32 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 384000, + 8, + 32, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 24, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm192000c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 192000, + 768000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm44100c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 44100, + 88200, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm48000c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 48000, + 96000, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm16000c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 16000, + 32000, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm32000c2 = +{ // 14 + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 32000, + 128000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm88200c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 88200, + 352800, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm96000c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 96000, + 384000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm24000c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 24000, + 96000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm16000c2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 16000, + 64000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + 0, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm8000c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 8000, + 16000, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm11025c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 11025, + 22050, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm22050c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 22050, + 44100, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm24000c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 24000, + 48000, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm32000c1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 1, + 32000, + 64000, + 2, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_MONO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +// +// Definitions of HDMI specific audio formats. +// + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyDigital = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyDigitalPlus = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 192000, + 768000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyDigitalPlusAtmos = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS_ATMOS), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 192000, + 768000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_DIGITAL_PLUS_ATMOS) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyMlp = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyMlpSurround = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1_SURROUND, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MLP) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DtsSurround = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DtsHD = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DtsHDLowBitRate = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_STEREO, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTS_HD) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DtsXE1 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTSX_E1), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTSX_E1) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DtsXE2 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTSX_E2), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DTSX_E2) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyMAT20 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MAT20), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MAT20) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE DolbyMAT21 = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MAT21), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 8, + 192000, + 3072000, + 16, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + KSAUDIO_SPEAKER_7POINT1, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_IEC61937_DOLBY_MAT21) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm44100c2nomask = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 44100, + 176400, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) + }, + 16, + 0, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +// No Mask version is used for 2ch Capture, where the mask is not meaningful +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm48000c2nomask = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 2, + 48000, + 192000, + 4, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + 0, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; + +static +KSDATAFORMAT_WAVEFORMATEXTENSIBLE Pcm16000c4nomask = +{ + { + sizeof(KSDATAFORMAT_WAVEFORMATEXTENSIBLE), + 0, + 0, + 0, + STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO), + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM), + STATICGUIDOF(KSDATAFORMAT_SPECIFIER_WAVEFORMATEX) + }, + { + { + WAVE_FORMAT_EXTENSIBLE, + 4, + 16000, + 128000, + 8, + 16, + sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) + }, + 16, + 0, + STATICGUIDOF(KSDATAFORMAT_SUBTYPE_PCM) + } +}; diff --git a/crossplatform/windows-driver/LibrePodsMic/Inc/cpp_utils.h b/crossplatform/windows-driver/LibrePodsMic/Inc/cpp_utils.h new file mode 100644 index 000000000..e0e10ab48 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Inc/cpp_utils.h @@ -0,0 +1,71 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + cpp_utils.h + +Abstract: + + Contains CPP utilities + +Environment: + + Kernel mode + +--*/ + +#pragma once + +// Function scope_exit instantiates scope_exit object +// Constructor accepts lamda as parameter. +// Assign tasks in lamdba to be executed on scope exit. +template +auto scope_exit(F f) +{ + class scope_exit + { + public: + scope_exit(F f) : + _f{ f } + { + } + + ~scope_exit() + { + if (_call) + { + _f(); + } + } + + // Ensures the scope_exit lambda will not be called + void release() + { + _call = false; + } + + // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again + void reset() + { + if (_call) + { + _f(); + _call = false; + } + } + + private: + F _f; + bool _call = true; + }; + + return scope_exit{ f }; +}; + diff --git a/crossplatform/windows-driver/LibrePodsMic/README.md b/crossplatform/windows-driver/LibrePodsMic/README.md new file mode 100644 index 000000000..13b5d3116 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/README.md @@ -0,0 +1,32 @@ +# LibrePodsMic — virtual audio (microphone) driver + +The virtual-microphone driver for the [hi-res mic feature](../../hires-mic/PLAN.md): +Windows sees a "LibrePods Microphone" that the app feeds with the AirPods' +decoded AAC-ELD audio, so any app (Teams, Zoom, Discord, OBS…) can use it. + +## Origin / license + +This is based on the **Microsoft ACX `AudioCodec` sample** from +[microsoft/Windows-driver-samples](https://github.com/microsoft/Windows-driver-samples/tree/main/audio/Acx/Samples) +(**MIT licensed**), chosen because: + +- it's a **ROOT-enumerated** (software, no-hardware) audio device — i.e. virtual; +- it already has a **capture circuit** (`Common/CaptureCircuit.cpp`) — a mic; +- it uses **ACX** on top of **KMDF** — the same framework family as our + `LibrePodsAAP` driver (unlike SYSVAD's older PortCls). + +We will trim it to capture-only and swap the audio source (`Common/WaveReader.cpp`) +for a PCM feed pushed from the app over an IOCTL/ring buffer. + +## Status + +- [x] **Builds** with VS2026 + WDK 28000 (ACX headers present) — `AudioCodec.sys`. +- [ ] Install (ROOT device) + verify a virtual mic appears in Sound settings. +- [ ] Rename AudioCodec → LibrePodsMic (INF device description). +- [ ] Trim to capture-only; add the IOCTL PCM bridge (Phase 2). + +## Build + +`build-wsl.cmd` on the Windows host (VS + WDK) → +`AudioCodec/Driver/x64/Release/AudioCodec.sys`. See +[`../../hires-mic/PLAN.md`](../../hires-mic/PLAN.md) for the roadmap. diff --git a/crossplatform/windows-driver/LibrePodsMic/Shared/Public.h b/crossplatform/windows-driver/LibrePodsMic/Shared/Public.h new file mode 100644 index 000000000..727ada9bc --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Shared/Public.h @@ -0,0 +1,342 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + Public.h + +Abstract: + + Contains structure definitions and function prototypes for the driver + that are public. + +Environment: + + Kernel mode + +--*/ + +/* make prototypes usable from C++ */ +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include +#include "Trace.h" + +#include +#include + +#define PAGED_CODE_SEG __declspec(code_seg("PAGE")) +#define INIT_CODE_SEG __declspec(code_seg("INIT")) + +// Number of msec for idle timeout. +#define IDLE_POWER_TIMEOUT 5000 + +extern RECORDER_LOG g_AudioDspLog; +extern RECORDER_LOG g_AudioDspMcLog; + +// +// Define CODEC device context. +// +typedef struct _CODEC_DEVICE_CONTEXT { + ACXCIRCUIT Render; + ACXCIRCUIT Capture; + WDF_TRI_STATE ExcludeD3Cold; +} CODEC_DEVICE_CONTEXT, * PCODEC_DEVICE_CONTEXT; + +// +// Codec driver prototypes. +// +EVT_WDF_DRIVER_DEVICE_ADD Codec_EvtBusDeviceAdd; +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD AudioCodecDriverUnload; + +// +// Codec device callbacks. +// +EVT_WDF_DEVICE_PREPARE_HARDWARE Codec_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE Codec_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY Codec_EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT Codec_EvtDeviceD0Exit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP Codec_EvtDeviceContextCleanup; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODEC_DEVICE_CONTEXT, GetCodecDeviceContext) + +// +// Define DSP device context. +// +typedef struct _DSP_DEVICE_CONTEXT { + ACXCIRCUIT Speaker; + ACXCIRCUIT MicArray; + ACXCIRCUIT SpeakerHp; + ACXCIRCUIT MicrophoneHp; + ACXCIRCUIT HDMI; + WDF_TRI_STATE ExcludeD3Cold; +} DSP_DEVICE_CONTEXT, * PDSP_DEVICE_CONTEXT; + +// +// Dsp driver prototypes. +// +EVT_WDF_DRIVER_DEVICE_ADD Dsp_EvtBusDeviceAdd; +EVT_WDF_DRIVER_UNLOAD AudioDspDriverUnload; + +// +// Dsp device callbacks. +// +EVT_WDF_DEVICE_PREPARE_HARDWARE Dsp_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE Dsp_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY Dsp_EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT Dsp_EvtDeviceD0Exit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP Dsp_EvtDeviceContextCleanup; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSP_DEVICE_CONTEXT, GetDspDeviceContext) + +// +// Define CODECMC (multicircuit codec) device context. +// +typedef struct _CODECMC_DEVICE_CONTEXT +{ + ACXCIRCUIT Render; + ACXCIRCUIT Capture; + ACXCOMPOSITETEMPLATE Composite[2]; + ULONG refComposite[2]; + WDF_TRI_STATE ExcludeD3Cold; +} CODECMC_DEVICE_CONTEXT, *PCODECMC_DEVICE_CONTEXT; + +// +// Multicircuit codec driver prototypes. +// +EVT_WDF_DRIVER_DEVICE_ADD CodecMc_EvtBusDeviceAdd; +DRIVER_INITIALIZE DriverEntry; +EVT_WDF_DRIVER_UNLOAD AudioCodecMcDriverUnload; + +// +// Multicircuit codec device callbacks. +// +EVT_WDF_DEVICE_PREPARE_HARDWARE CodecMc_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE CodecMc_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY CodecMc_EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT CodecMc_EvtDeviceD0Exit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP CodecMc_EvtDeviceContextCleanup; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CODECMC_DEVICE_CONTEXT, GetCodecMcDeviceContext) + +// +// Composite type definition used in multicircuit codec. +// +typedef enum +{ + CompositeType_RENDER, + CompositeType_CAPTURE +} CompositeType; + +// +// Define DSPMC (multicircuit dsp) device context. +// +typedef struct _DSPMC_DEVICE_CONTEXT +{ + ACXCIRCUIT Render; + ACXCIRCUIT Capture; + WDF_TRI_STATE ExcludeD3Cold; +} DSPMC_DEVICE_CONTEXT, *PDSPMC_DEVICE_CONTEXT; + +// +// Multicircuit dsp driver prototypes. +// +EVT_WDF_DRIVER_DEVICE_ADD DspMc_EvtBusDeviceAdd; +EVT_WDF_DRIVER_UNLOAD AudioDspMcDriverUnload; + +// +// Multicircuit dsp device callbacks. +// +EVT_WDF_DEVICE_PREPARE_HARDWARE DspMc_EvtDevicePrepareHardware; +EVT_WDF_DEVICE_RELEASE_HARDWARE DspMc_EvtDeviceReleaseHardware; +EVT_WDF_DEVICE_D0_ENTRY DspMc_EvtDeviceD0Entry; +EVT_WDF_DEVICE_D0_EXIT DspMc_EvtDeviceD0Exit; +EVT_WDF_DEVICE_CONTEXT_CLEANUP DspMc_EvtDeviceContextCleanup; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DSPMC_DEVICE_CONTEXT, GetDspMcDeviceContext) + +// Factory circuit callbacks for multicircuit dsp. +EVT_ACX_FACTORY_CIRCUIT_CREATE_CIRCUITDEVICE RenderMCDsp_EvtAcxFactoryCircuitCreateCircuitDevice; +EVT_ACX_FACTORY_CIRCUIT_CREATE_CIRCUIT RenderMCDsp_EvtAcxFactoryCircuitCreateCircuit; + +EVT_ACX_FACTORY_CIRCUIT_CREATE_CIRCUITDEVICE CaptureMCDsp_EvtAcxFactoryCircuitCreateCircuitDevice; +EVT_ACX_FACTORY_CIRCUIT_CREATE_CIRCUIT CaptureMCDsp_EvtAcxFactoryCircuitCreateCircuit; + + +/* make internal prototypes usable from C++ */ +#ifdef __cplusplus +} +#endif + +// Used to store the registry settings path for the driver: +extern UNICODE_STRING g_RegistryPath; + +// Driver tag name: +extern ULONG DeviceDriverTag; + +// The idle timeout in msec for power policy structure: +extern ULONG IdleTimeoutMsec; + +#define DECLARE_CONST_ACXOBJECTBAG_MULTICIRCUIT_SAMPLE_PROPERTY_NAME(name) \ + DECLARE_CONST_UNICODE_STRING(name, L"mc_" #name) + +__drv_requiresIRQL(PASSIVE_LEVEL) +PAGED_CODE_SEG +NTSTATUS +CopyRegistrySettingsPath( + _In_ PUNICODE_STRING RegistryPath +); + +PAGED_CODE_SEG +NTSTATUS +Codec_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +Dsp_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +CodecMc_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +DspMc_SetPowerPolicy( + _In_ WDFDEVICE Device +); + +PAGED_CODE_SEG +NTSTATUS +CodecR_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +CodecC_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +Speaker_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ UNICODE_STRING CircuitName, + _In_ BOOLEAN IsHeadphones +); + +PAGED_CODE_SEG +NTSTATUS +MicArray_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ GUID MicCustomName, + _In_ UNICODE_STRING CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +MicrophoneHp_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ GUID MicCustomName, + _In_ UNICODE_STRING CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +SpeakerHp_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ UNICODE_STRING CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +HDMI_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ GUID ComponentGuid, + _In_ UNICODE_STRING CircuitName +); + +PAGED_CODE_SEG +NTSTATUS +RenderMC_AddStaticRender( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const UNICODE_STRING * CircuitName, + _In_ const UNICODE_STRING * Uri +); + +PAGED_CODE_SEG +NTSTATUS +CaptureMC_AddStaticCapture( + _In_ WDFDEVICE Device, + _In_ const GUID * ComponentGuid, + _In_ const GUID * MicCustomName, + _In_ const UNICODE_STRING * CircuitName, + _In_ const UNICODE_STRING * Uri +); + +PAGED_CODE_SEG +NTSTATUS +CodecC_CircuitCleanup( + _In_ ACXCIRCUIT Device +); + +PAGED_CODE_SEG +NTSTATUS +MicArray_CircuitCleanup( + _In_ ACXCIRCUIT Device +); + +PAGED_CODE_SEG +NTSTATUS +CaptureMCDsp_CircuitCleanup( + _In_ ACXCIRCUIT Device +); + +PAGED_CODE_SEG +NTSTATUS +DspMc_AddFactoryCircuit( + _In_ WDFDRIVER Driver, + _In_ WDFDEVICE Device +); + +NTSTATUS +CodecMc_AddRenderComposites(_In_ WDFDEVICE Device); + +PAGED_CODE_SEG +NTSTATUS +CodecMc_AddCaptureComposites(_In_ WDFDEVICE Device); + +PAGED_CODE_SEG +NTSTATUS +CodecMc_AddComposites(_In_ WDFDEVICE Device, _In_ CompositeType compositeType); + +NTSTATUS +CodecMc_RemoveComposites(_In_ WDFDEVICE Device); diff --git a/crossplatform/windows-driver/LibrePodsMic/Shared/Trace.h b/crossplatform/windows-driver/LibrePodsMic/Shared/Trace.h new file mode 100644 index 000000000..552021297 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Shared/Trace.h @@ -0,0 +1,33 @@ +/*++ + +Copyright (c) Microsoft Corporation + +Module Name: + +Trace.h + +--*/ + +#pragma once + +#include +#include // For TRACE_LEVEL definitions + +#define WPP_TOTAL_BUFFER_SIZE (PAGE_SIZE) +#define WPP_ERROR_PARTITION_SIZE (WPP_TOTAL_BUFFER_SIZE/4) + +// {1945C417-844C-48C6-9BCE-3AA2113A2B69} +#define WPP_CONTROL_GUIDS \ +WPP_DEFINE_CONTROL_GUID(DrvLogger,(1945C417,844C,48C6,9BCE,3AA2113A2B69), \ + WPP_DEFINE_BIT(FLAG_DEVICE_ALL) /* bit 0 = 0x00000001 */ \ + WPP_DEFINE_BIT(FLAG_FUNCTION) /* bit 1 = 0x00000002 */ \ + WPP_DEFINE_BIT(FLAG_INFO) /* bit 2 = 0x00000004 */ \ + WPP_DEFINE_BIT(FLAG_PNP) /* bit 3 = 0x00000008 */ \ + WPP_DEFINE_BIT(FLAG_POWER) /* bit 4 = 0x00000010 */ \ + WPP_DEFINE_BIT(FLAG_STREAM) /* bit 5 = 0x00000020 */ \ + WPP_DEFINE_BIT(FLAG_INIT) /* bit 6 = 0x00000040 */ \ + WPP_DEFINE_BIT(FLAG_DDI) /* bit 7 = 0x00000080 */ \ + WPP_DEFINE_BIT(FLAG_GENERIC) /* bit 8 = 0x00000100 */ \ + ) + +#include "trace_macros.h" From 2627fd41ea8f2a59c6535e57ba06727997ed7d11 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:33:59 +0100 Subject: [PATCH 03/48] hires-mic(Phase 1): install.ps1 for the LibrePodsMic virtual audio driver Test-signs the built AudioCodec.sys, generates+signs a catalog (inf2cat), trusts a test cert, and creates the ROOT\AudioCodec device via devcon so a virtual microphone endpoint appears. Elevated + Test Mode, like the AAP driver. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/LibrePodsMic/install.ps1 | 60 +++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 crossplatform/windows-driver/LibrePodsMic/install.ps1 diff --git a/crossplatform/windows-driver/LibrePodsMic/install.ps1 b/crossplatform/windows-driver/LibrePodsMic/install.ps1 new file mode 100644 index 000000000..22e65588e --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/install.ps1 @@ -0,0 +1,60 @@ +<# + install.ps1 — test-sign + install the LibrePodsMic virtual audio driver, and + create its ROOT-enumerated device so a virtual microphone appears. + + RUN AS ADMINISTRATOR, in Test Mode (bcdedit /set testsigning on + reboot, + Secure Boot off). Consider a system restore point first — this adds a virtual + audio device. + + Pass the build output dir that holds AudioCodec.sys + AudioCodec.inf. + Default: the Release build under this driver tree. +#> +param( + [string]$Dir = (Join-Path $PSScriptRoot 'AudioCodec\Driver\x64\Release') +) +$ErrorActionPreference = 'Stop' + +$sys = Join-Path $Dir 'AudioCodec.sys' +$inf = Join-Path $Dir 'AudioCodec.inf' +foreach ($f in @($sys, $inf)) { if (-not (Test-Path $f)) { throw "Missing $f — build first." } } + +$kit = 'C:\Program Files (x86)\Windows Kits\10' +$inf2cat = Join-Path $kit 'bin\10.0.28000.0\x86\Inf2Cat.exe' +$devcon = Join-Path $kit 'Tools\10.0.28000.0\x64\devcon.exe' +$signtool = (Get-ChildItem "$kit\bin" -Recurse -Filter signtool.exe | + Where-Object { $_.FullName -match 'x64' } | Select-Object -First 1).FullName + +# 1. A package folder with the .sys + .inf together, then a catalog. +$pkg = Join-Path $env:TEMP 'LibrePodsMicPkg' +Remove-Item $pkg -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $pkg | Out-Null +Copy-Item $sys, $inf $pkg -Force +Write-Host '==> Generating catalog...' +& $inf2cat /driver:$pkg /os:10_X64 +$cat = Join-Path $pkg 'audiocodec.cat' + +# 2. Test code-signing cert, trusted for driver loading. +Write-Host '==> Creating + trusting a test certificate...' +$cert = New-SelfSignedCertificate -Type CodeSigningCert ` + -Subject 'CN=LibrePods Test Cert' ` + -CertStoreLocation Cert:\LocalMachine\My ` + -KeyUsage DigitalSignature -KeyExportPolicy Exportable +$store = Get-Item "Cert:\LocalMachine\My\$($cert.Thumbprint)" +foreach ($name in 'Root', 'TrustedPublisher') { + $s = New-Object System.Security.Cryptography.X509Certificates.X509Store($name, 'LocalMachine') + $s.Open('ReadWrite'); $s.Add($store); $s.Close() +} + +Write-Host '==> Signing driver + catalog...' +$pkgSys = Join-Path $pkg 'AudioCodec.sys' +& $signtool sign /v /fd SHA256 /sm /s My /sha1 $cert.Thumbprint $pkgSys +& $signtool sign /v /fd SHA256 /sm /s My /sha1 $cert.Thumbprint $cat + +# 3. Install the driver + create the ROOT device (devcon install does both). +$pkgInf = Join-Path $pkg 'AudioCodec.inf' +Write-Host '==> Installing + creating the ROOT\AudioCodec device...' +& $devcon install $pkgInf 'ROOT\AudioCodec' + +Write-Host '' +Write-Host '==> Done. Check Settings -> System -> Sound -> Input for a new mic,' +Write-Host ' and Device Manager -> Sound, video and game controllers.' From 329bdd95e9190e9f32ba45a5b2444e477bc4523f Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:38:24 +0100 Subject: [PATCH 04/48] hires-mic: fix install.ps1 encoding (ASCII only, no em dashes) PowerShell read the UTF-8 em dash as garbage and broke string parsing. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-driver/LibrePodsMic/install.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crossplatform/windows-driver/LibrePodsMic/install.ps1 b/crossplatform/windows-driver/LibrePodsMic/install.ps1 index 22e65588e..2337ac34a 100644 --- a/crossplatform/windows-driver/LibrePodsMic/install.ps1 +++ b/crossplatform/windows-driver/LibrePodsMic/install.ps1 @@ -1,9 +1,9 @@ <# - install.ps1 — test-sign + install the LibrePodsMic virtual audio driver, and + install.ps1 - test-sign + install the LibrePodsMic virtual audio driver, and create its ROOT-enumerated device so a virtual microphone appears. RUN AS ADMINISTRATOR, in Test Mode (bcdedit /set testsigning on + reboot, - Secure Boot off). Consider a system restore point first — this adds a virtual + Secure Boot off). Consider a system restore point first - this adds a virtual audio device. Pass the build output dir that holds AudioCodec.sys + AudioCodec.inf. @@ -16,7 +16,7 @@ $ErrorActionPreference = 'Stop' $sys = Join-Path $Dir 'AudioCodec.sys' $inf = Join-Path $Dir 'AudioCodec.inf' -foreach ($f in @($sys, $inf)) { if (-not (Test-Path $f)) { throw "Missing $f — build first." } } +foreach ($f in @($sys, $inf)) { if (-not (Test-Path $f)) { throw "Missing $f - build first." } } $kit = 'C:\Program Files (x86)\Windows Kits\10' $inf2cat = Join-Path $kit 'bin\10.0.28000.0\x86\Inf2Cat.exe' From f49cb9e20e1d61f110b6caf115c444c5bb65df7a Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:40:19 +0100 Subject: [PATCH 05/48] =?UTF-8?q?hires-mic(Phase=201):=20DONE=20=E2=80=94?= =?UTF-8?q?=20virtual=20microphone=20installs=20+=20shows=20in=20Windows?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Confirmed on hardware: install.ps1 signs+catalogs the ACX driver and creates the ROOT\AudioCodec device via devcon; Windows shows 'Microphone (AudioCodec Device)' in Sound -> Input. The virtual-mic foundation is proven. Next: Phase 2 (IOCTL PCM bridge to feed the AirPods' decoded audio into the capture circuit). Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 11 +++++++++-- crossplatform/windows-driver/LibrePodsMic/README.md | 10 +++++++--- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index 2ef9d8f2a..ed1bd6ad1 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -68,5 +68,12 @@ the sink. ## Status -Phase 1 not started. This branch holds the plan + (to come) the `LibrePodsMic` -driver and the shared-crate mic path. +- **Phase 1 — DONE** ✅ (`windows-driver/LibrePodsMic/`, based on the MS ACX + AudioCodec sample). Builds with WDK 28000, installs via `install.ps1`, and + Windows shows a virtual **"Microphone (AudioCodec Device)"** (confirmed on + hardware). The audio source is still the sample's dummy; feeding real audio is + next. +- **Phase 2 — next**: IOCTL/ring bridge so user mode can push PCM into the + capture circuit (`Common/CaptureCircuit.cpp` / `WaveReader.cpp`); test with a + tone/WAV heard on the virtual mic. +- Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. diff --git a/crossplatform/windows-driver/LibrePodsMic/README.md b/crossplatform/windows-driver/LibrePodsMic/README.md index 13b5d3116..fece7573e 100644 --- a/crossplatform/windows-driver/LibrePodsMic/README.md +++ b/crossplatform/windows-driver/LibrePodsMic/README.md @@ -21,9 +21,13 @@ for a PCM feed pushed from the app over an IOCTL/ring buffer. ## Status - [x] **Builds** with VS2026 + WDK 28000 (ACX headers present) — `AudioCodec.sys`. -- [ ] Install (ROOT device) + verify a virtual mic appears in Sound settings. -- [ ] Rename AudioCodec → LibrePodsMic (INF device description). -- [ ] Trim to capture-only; add the IOCTL PCM bridge (Phase 2). +- [x] **Installs + a virtual mic appears** — `install.ps1` (elevated, Test Mode) + signs + catalogs the driver and creates the `ROOT\AudioCodec` device via + devcon. Confirmed on hardware: Windows shows **"Microphone (AudioCodec Device)"** + in Sound -> Input (and a matching output). **Phase 1 done.** +- [ ] Rename AudioCodec -> LibrePodsMic (INF device description). +- [ ] Trim to capture-only; add the IOCTL PCM bridge (Phase 2) so the app can + push the AirPods' decoded audio into the mic. ## Build From 522f9e8eefa0c4360a0be27ade33b190d8ef9366 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 17:44:20 +0100 Subject: [PATCH 06/48] hires-mic(Phase 1b): capture-only driver (drop the phantom speaker) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Device.cpp: don't create/add/remove the render (speaker) circuit — LibrePodsMic is a virtual *microphone*, so exposing a render endpoint only risked Windows grabbing the default output (the brief static on install) and cluttered the device list. Capture circuit only. Builds clean. install.ps1: `devcon remove ROOT\AudioCodec` before install so re-running updates in place instead of stacking a second virtual device. Co-Authored-By: Claude Opus 4.8 --- .../LibrePodsMic/AudioCodec/Driver/Device.cpp | 9 +++------ crossplatform/windows-driver/LibrePodsMic/install.ps1 | 5 +++++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp index 6a94a66a5..3c32145c5 100644 --- a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp @@ -178,8 +178,9 @@ Return Value: // device context. These circuits will be added to the device when the // prepare hardware callback is called. // - RETURN_NTSTATUS_IF_FAILED(CodecR_AddStaticRender(device, &CODEC_RENDER_COMPONENT_GUID, &renderCircuitName)); - + // LibrePodsMic is capture-only (a virtual microphone). No render/speaker + // circuit — so Windows never exposes a phantom output device that could grab + // the default output. RETURN_NTSTATUS_IF_FAILED(CodecC_AddStaticCapture(device, &CODEC_CAPTURE_COMPONENT_GUID, &MIC_CUSTOM_NAME, &captureCircuitName)); return status; @@ -248,9 +249,6 @@ Return Value: // called once). // - ASSERT(devCtx->Render); - RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Render)); - ASSERT(devCtx->Capture); RETURN_NTSTATUS_IF_FAILED(AcxDeviceAddCircuit(Device, devCtx->Capture)); @@ -294,7 +292,6 @@ Return Value: // // The driver uses this DDI to delete a circuit from the current device. // - RETURN_NTSTATUS_IF_FAILED(AcxDeviceRemoveCircuit(Device, devCtx->Render)); RETURN_NTSTATUS_IF_FAILED(AcxDeviceRemoveCircuit(Device, devCtx->Capture)); // NOTE: Release streaming h/w resources here. diff --git a/crossplatform/windows-driver/LibrePodsMic/install.ps1 b/crossplatform/windows-driver/LibrePodsMic/install.ps1 index 2337ac34a..3143eb6e7 100644 --- a/crossplatform/windows-driver/LibrePodsMic/install.ps1 +++ b/crossplatform/windows-driver/LibrePodsMic/install.ps1 @@ -51,7 +51,12 @@ $pkgSys = Join-Path $pkg 'AudioCodec.sys' & $signtool sign /v /fd SHA256 /sm /s My /sha1 $cert.Thumbprint $cat # 3. Install the driver + create the ROOT device (devcon install does both). +# Remove any existing instance first so re-running updates cleanly instead of +# stacking a second virtual device. $pkgInf = Join-Path $pkg 'AudioCodec.inf' +Write-Host '==> Removing any existing ROOT\AudioCodec device...' +& $devcon remove 'ROOT\AudioCodec' 2>&1 | Out-Null +Start-Sleep -Seconds 1 Write-Host '==> Installing + creating the ROOT\AudioCodec device...' & $devcon install $pkgInf 'ROOT\AudioCodec' From 6c6fdffff5d7a39daaed1d480114a94b05006022 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:09:28 +0100 Subject: [PATCH 07/48] windows-tray: throttle the AAP receive loop (fix 7.5% CPU spin) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver's ACL read (IOCTL_LP_RECEIVE) completes immediately with 0 bytes when the channel is idle (ACL_SHORT_TRANSFER_OK), so the background receive loop was spinning a core (~7.5% CPU, measured) and, worse, flooding the Bluetooth stack with thousands of back-to-back ACL reads per second — which contends with the A2DP audio stream and is the likely source of the crackle/static. Yield the CPU (150 ms) whenever a read returns no data, so the loop can't spin. Pushed events (battery / ANC / ear-detection) still arrive within ~150 ms since we only sleep on an empty read. Measured after: 0.1% CPU. A fully event-driven (async, kernel-pended) read would take idle reads to zero, but that's a driver change (reinstall + reboot); this gets ~99% of the benefit without touching the signed driver. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 7485e65c0..9f5d1cf95 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -165,8 +165,10 @@ fn run_receiver( let mut we_paused = false; let mut ticks = 0u32; loop { + let mut got_data = false; if let Ok(n) = driver.recv(2000, &mut buf) { if n > 0 { + got_data = true; let data = &buf[..n]; if let Some(b) = aap::parse_battery(data) { let mut s = state.lock().unwrap(); @@ -226,6 +228,14 @@ fn run_receiver( } } } + // No data this cycle: yield the CPU. The driver's ACL read completes + // immediately with 0 bytes when idle (ACL_SHORT_TRANSFER_OK), so + // without this the loop spins a core AND floods the Bluetooth stack + // with back-to-back ACL reads that contend with the A2DP audio + // (the crackle). Pushed events still arrive within ~150 ms. + if !got_data { + thread::sleep(Duration::from_millis(150)); + } // Passive session: no periodic L2CAP sends — those make Windows // re-negotiate the audio profile and cut/switch the output. Detect a // real disconnect via GET_STATUS, which reads a driver variable only From 87ed69f11febf55a72faaacd6b402496b6cb2d80 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:21:42 +0100 Subject: [PATCH 08/48] hires-mic(Phase 2): IOCTL PCM bridge into the capture stream Add MicPipe: a global byte ring buffer (spin-locked, single-instance mic) that user mode fills with decoded PCM and the ACX capture stream engine drains one packet per notification tick. - Common/MicPipe.{h,cpp}: the ring + a driver-scoped control device (\\.\LibrePodsMic) exposing IOCTL_LIBREPODS_MIC_WRITE_PCM (0x0022A000, METHOD_BUFFERED). Write appends (drops oldest on overflow); Read fills a packet, zero-filling underrun. Read is DISPATCH_LEVEL-safe (non-paged, spin lock). World RW SDDL so a non-elevated app can push audio. - StreamEngine.cpp ProcessPacket: fill the capture packet from MicPipeRead instead of the sample's WAV-file / tone dummy sources. - Device.cpp: MicPipeInit + MicPipeCreateControlDevice at device add (best-effort; never fails enumeration). - SamplesCommon.vcxproj: compile MicPipe.cpp. Builds clean (EXIT 0). Format is mono 16-bit PCM at 44100/48000 Hz (whatever the client opens the capture endpoint with). Next: user-mode feeder to validate the pipe end-to-end. Co-Authored-By: Claude Opus 4.8 --- .../LibrePodsMic/AudioCodec/Driver/Device.cpp | 10 + .../LibrePodsMic/Common/MicPipe.cpp | 206 ++++++++++++++++++ .../LibrePodsMic/Common/MicPipe.h | 80 +++++++ .../LibrePodsMic/Common/SamplesCommon.vcxproj | 2 + .../LibrePodsMic/Common/StreamEngine.cpp | 14 +- 5 files changed, 304 insertions(+), 8 deletions(-) create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp create mode 100644 crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp index 3c32145c5..2bb68346a 100644 --- a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/Device.cpp @@ -24,6 +24,7 @@ Module Name: #include #include #include "streamengine.h" +#include "MicPipe.h" #include "DriverSettings.h" #ifndef __INTELLISENSE__ @@ -183,6 +184,15 @@ Return Value: // the default output. RETURN_NTSTATUS_IF_FAILED(CodecC_AddStaticCapture(device, &CODEC_CAPTURE_COMPONENT_GUID, &MIC_CUSTOM_NAME, &captureCircuitName)); + // + // LibrePods mic bridge (Phase 2): init the PCM ring and expose the control + // device (\\.\LibrePodsMic) so user mode can push the decoded AirPods audio + // into the capture stream. Best-effort — a failure here must not fail device + // add (the mic still enumerates, just without a user-mode feed). + // + MicPipeInit(); + (VOID)MicPipeCreateControlDevice(device); + return status; } diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp new file mode 100644 index 000000000..362357edc --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp @@ -0,0 +1,206 @@ +/*++ + +Module Name: + + MicPipe.cpp + +Abstract: + + Implementation of the LibrePods hi-res microphone bridge. See MicPipe.h. + + Design: a single global byte ring buffer guarded by a spin lock (the virtual + mic is single-instance). User mode writes decoded PCM via the control device + IOCTL; the ACX capture stream engine reads a packet per tick. No WPP tracing + here (keeps the file self-contained). + +Environment: + + Kernel mode + +--*/ + +#include "MicPipe.h" + +// +// ~1.36 s of headroom @ 48 kHz mono 16-bit (96000 B/s). Lives in the driver's +// non-paged image data, so it's safe to touch at DISPATCH_LEVEL. +// +#define MIC_RING_BYTES 0x20000u + +static UCHAR g_Ring[MIC_RING_BYTES]; +static ULONG g_Head; // next write index +static ULONG g_Tail; // next read index +static ULONG g_Count; // bytes currently buffered +static KSPIN_LOCK g_Lock; +static BOOLEAN g_Inited = FALSE; + +static WDFDEVICE g_ControlDevice = NULL; + +EXTERN_C_START + +VOID +MicPipeInit( + VOID +) +{ + if (g_Inited) { + return; + } + KeInitializeSpinLock(&g_Lock); + g_Head = g_Tail = g_Count = 0; + g_Inited = TRUE; +} + +VOID +MicPipeWrite( + _In_reads_bytes_(Len) PVOID Data, + _In_ ULONG Len +) +{ + KIRQL irql; + PUCHAR src = (PUCHAR)Data; + ULONG i; + + if (!g_Inited || Data == NULL || Len == 0) { + return; + } + + KeAcquireSpinLock(&g_Lock, &irql); + for (i = 0; i < Len; i++) { + if (g_Count == MIC_RING_BYTES) { + // Full: drop the oldest byte so the newest audio always wins. + g_Tail = (g_Tail + 1u) % MIC_RING_BYTES; + g_Count--; + } + g_Ring[g_Head] = src[i]; + g_Head = (g_Head + 1u) % MIC_RING_BYTES; + g_Count++; + } + KeReleaseSpinLock(&g_Lock, irql); +} + +VOID +MicPipeRead( + _Out_writes_bytes_(Len) PVOID Out, + _In_ ULONG Len +) +{ + KIRQL irql; + PUCHAR dst = (PUCHAR)Out; + ULONG i; + + if (Out == NULL || Len == 0) { + return; + } + if (!g_Inited) { + RtlZeroMemory(Out, Len); + return; + } + + KeAcquireSpinLock(&g_Lock, &irql); + for (i = 0; i < Len; i++) { + if (g_Count == 0) { + dst[i] = 0; // underrun -> silence + } else { + dst[i] = g_Ring[g_Tail]; + g_Tail = (g_Tail + 1u) % MIC_RING_BYTES; + g_Count--; + } + } + KeReleaseSpinLock(&g_Lock, irql); +} + +// +// IOCTL handler: copy the pushed PCM into the ring. +// +static VOID +MicPipe_EvtIoDeviceControl( + _In_ WDFQUEUE Queue, + _In_ WDFREQUEST Request, + _In_ size_t OutputBufferLength, + _In_ size_t InputBufferLength, + _In_ ULONG IoControlCode +) +{ + NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; + ULONG_PTR info = 0; + + UNREFERENCED_PARAMETER(Queue); + UNREFERENCED_PARAMETER(OutputBufferLength); + + if (IoControlCode == IOCTL_LIBREPODS_MIC_WRITE_PCM && InputBufferLength > 0) { + PVOID buf = NULL; + size_t len = 0; + status = WdfRequestRetrieveInputBuffer(Request, 1, &buf, &len); + if (NT_SUCCESS(status)) { + MicPipeWrite(buf, (ULONG)len); + info = len; + } + } + + WdfRequestCompleteWithInformation(Request, status, info); +} + +NTSTATUS +MicPipeCreateControlDevice( + _In_ WDFDEVICE Parent +) +{ + NTSTATUS status; + PWDFDEVICE_INIT init = NULL; + WDFDEVICE ctl = NULL; + WDFQUEUE queue; + WDF_IO_QUEUE_CONFIG qCfg; + + // SYSTEM: all, Builtin Admins: RWX, Everyone: RW (so a non-elevated app can + // open \\.\LibrePodsMic and push audio). + DECLARE_CONST_UNICODE_STRING(sddl, + L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGW;;;WD)"); + DECLARE_CONST_UNICODE_STRING(ntName, L"\\Device\\LibrePodsMic"); + DECLARE_CONST_UNICODE_STRING(symLink, L"\\DosDevices\\LibrePodsMic"); + + // Driver-scoped, created once. Survives PnP device remove/re-add. + if (g_ControlDevice != NULL) { + return STATUS_SUCCESS; + } + + init = WdfControlDeviceInitAllocate(WdfDeviceGetDriver(Parent), &sddl); + if (init == NULL) { + return STATUS_INSUFFICIENT_RESOURCES; + } + + WdfDeviceInitSetDeviceType(init, FILE_DEVICE_UNKNOWN); + WdfDeviceInitSetIoType(init, WdfDeviceIoBuffered); + + status = WdfDeviceInitAssignName(init, &ntName); + if (!NT_SUCCESS(status)) { + WdfDeviceInitFree(init); + return status; + } + + status = WdfDeviceCreate(&init, WDF_NO_OBJECT_ATTRIBUTES, &ctl); + if (!NT_SUCCESS(status)) { + WdfDeviceInitFree(init); // WdfDeviceCreate only consumes init on success + return status; + } + + status = WdfDeviceCreateSymbolicLink(ctl, &symLink); + if (!NT_SUCCESS(status)) { + WdfObjectDelete(ctl); + return status; + } + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&qCfg, WdfIoQueueDispatchParallel); + qCfg.EvtIoDeviceControl = MicPipe_EvtIoDeviceControl; + status = WdfIoQueueCreate(ctl, &qCfg, WDF_NO_OBJECT_ATTRIBUTES, &queue); + if (!NT_SUCCESS(status)) { + WdfObjectDelete(ctl); + return status; + } + + WdfControlFinishInitializing(ctl); + g_ControlDevice = ctl; + return STATUS_SUCCESS; +} + +EXTERN_C_END diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h new file mode 100644 index 000000000..429f256e8 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h @@ -0,0 +1,80 @@ +/*++ + +Module Name: + + MicPipe.h + +Abstract: + + LibrePods hi-res microphone bridge (Phase 2). A global ring buffer that + user mode fills with decoded PCM over an IOCTL, and the ACX capture stream + engine drains one packet per notification tick (see StreamEngine.cpp + ProcessPacket). Exposed to user mode through a control device + (\\.\LibrePodsMic). + + PCM format: mono, 16-bit, 44100 or 48000 Hz (whatever the client opens the + capture endpoint with — see Capture_AllocateSupportedFormats). + +Environment: + + Kernel mode + +--*/ + +#pragma once + +#include +#include + +// +// IOCTL: user mode pushes raw PCM bytes into the mic ring buffer. +// Value (precomputed for the user-mode side): 0x0022A000. +// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) +// +#define IOCTL_LIBREPODS_MIC_WRITE_PCM \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) + +EXTERN_C_START + +// +// Initialize the global ring buffer. Call once, early (device add), before any +// read/write. Idempotent. +// +VOID +MicPipeInit( + VOID +); + +// +// Create the control device (\Device\LibrePodsMic + \DosDevices\LibrePodsMic) +// that exposes IOCTL_LIBREPODS_MIC_WRITE_PCM. Driver-scoped and created once; +// safe to call again (returns STATUS_SUCCESS if already created). Best-effort: +// a failure here must not fail device add (the mic still enumerates, just with +// no user-mode feed yet). +// +NTSTATUS +MicPipeCreateControlDevice( + _In_ WDFDEVICE Parent +); + +// +// Append PCM bytes to the ring (called from the IOCTL handler, PASSIVE_LEVEL). +// On overflow the oldest bytes are dropped so we always keep the newest audio. +// +VOID +MicPipeWrite( + _In_reads_bytes_(Len) PVOID Data, + _In_ ULONG Len +); + +// +// Fill Out with Len bytes from the ring (called from ProcessPacket, up to +// DISPATCH_LEVEL). Any underrun is zero-filled (silence). +// +VOID +MicPipeRead( + _Out_writes_bytes_(Len) PVOID Out, + _In_ ULONG Len +); + +EXTERN_C_END diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj b/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj index ce54f8ead..72ee8f0f9 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj +++ b/crossplatform/windows-driver/LibrePodsMic/Common/SamplesCommon.vcxproj @@ -151,6 +151,7 @@ + @@ -166,6 +167,7 @@ + diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp index 441b53c04..6f1b2afe3 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/Common/StreamEngine.cpp @@ -27,6 +27,7 @@ Module Name: #include #include #include "streamengine.h" +#include "MicPipe.h" #ifndef __INTELLISENSE__ #include "streamengine.tmh" @@ -1000,14 +1001,11 @@ CCaptureStreamEngine::ProcessPacket() packetBuffer += m_FirstPacketOffset; } - if (m_EnableWaveCapture) - { - m_WaveReader.ReadWaveData(packetBuffer, m_PacketSize); - } - else - { - m_ToneGenerator.GenerateSine(packetBuffer, m_PacketSize); - } + // LibrePods: fill this capture packet from the mic pipe — the PCM that user + // mode pushed over IOCTL_LIBREPODS_MIC_WRITE_PCM (the decoded AirPods audio). + // Underrun is zero-filled (silence). Replaces the sample's WAV-file / tone + // dummy sources. + MicPipeRead(packetBuffer, m_PacketSize); } _Use_decl_annotations_ From 1456c23909bf2a5d0d8964562a17e6f823d30732 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:22:41 +0100 Subject: [PATCH 09/48] =?UTF-8?q?hires-mic(Phase=202):=20lp-mic-test=20?= =?UTF-8?q?=E2=80=94=20feed=20a=20tone=20into=20the=20virtual=20mic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A tiny user-mode tool that opens \\.\LibrePodsMic and streams a 440 Hz sine (mono 16-bit, 48 kHz by default) via IOCTL_LIBREPODS_MIC_WRITE_PCM, in real-time 10 ms chunks. Record from "Microphone (AudioCodec Device)" to hear it — proves the user-mode -> IOCTL -> ring -> ACX capture path end to end. Raw kernel32 FFI, no deps. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-test/.gitignore | 1 + .../windows-driver/lp-mic-test/Cargo.toml | 13 ++ .../windows-driver/lp-mic-test/src/main.rs | 120 ++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 crossplatform/windows-driver/lp-mic-test/.gitignore create mode 100644 crossplatform/windows-driver/lp-mic-test/Cargo.toml create mode 100644 crossplatform/windows-driver/lp-mic-test/src/main.rs diff --git a/crossplatform/windows-driver/lp-mic-test/.gitignore b/crossplatform/windows-driver/lp-mic-test/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-test/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crossplatform/windows-driver/lp-mic-test/Cargo.toml b/crossplatform/windows-driver/lp-mic-test/Cargo.toml new file mode 100644 index 000000000..7492789f1 --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-test/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "lp-mic-test" +version = "0.1.0" +edition = "2021" +description = "Feed a test tone into the LibrePodsMic virtual microphone (Phase 2 pipe test)." + +[[bin]] +name = "lp-mic-test" +path = "src/main.rs" + +[profile.release] +opt-level = 2 +strip = true diff --git a/crossplatform/windows-driver/lp-mic-test/src/main.rs b/crossplatform/windows-driver/lp-mic-test/src/main.rs new file mode 100644 index 000000000..821c8902c --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-test/src/main.rs @@ -0,0 +1,120 @@ +//! Phase-2 pipe test: stream a sine tone into the LibrePodsMic virtual +//! microphone via the control device `\\.\LibrePodsMic`. +//! +//! Usage: run this, then record from "Microphone (AudioCodec Device)" in Voice +//! Recorder / Audacity — you should hear a steady tone. Proves the +//! user-mode -> IOCTL -> ring -> ACX capture path end to end. +//! +//! lp-mic-test [freq_hz] [sample_rate] +//! defaults: 440 Hz tone, 48000 Hz mono 16-bit (match the recording app's rate) + +use std::f64::consts::PI; +use std::os::raw::c_void; + +type Handle = *mut c_void; + +const GENERIC_WRITE: u32 = 0x4000_0000; +const FILE_SHARE_RW: u32 = 0x0000_0003; +const OPEN_EXISTING: u32 = 3; +const INVALID_HANDLE: Handle = usize::MAX as Handle; + +// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) +const IOCTL_LIBREPODS_MIC_WRITE_PCM: u32 = 0x0022_A000; + +#[link(name = "kernel32")] +extern "system" { + fn CreateFileW( + name: *const u16, + access: u32, + share: u32, + sec: *mut c_void, + disp: u32, + flags: u32, + template: Handle, + ) -> Handle; + fn DeviceIoControl( + dev: Handle, + code: u32, + in_buf: *const c_void, + in_len: u32, + out_buf: *mut c_void, + out_len: u32, + returned: *mut u32, + overlapped: *mut c_void, + ) -> i32; + fn CloseHandle(h: Handle) -> i32; + fn GetLastError() -> u32; + fn Sleep(ms: u32); +} + +fn wide(s: &str) -> Vec { + s.encode_utf16().chain(std::iter::once(0)).collect() +} + +fn main() { + let args: Vec = std::env::args().collect(); + let freq: f64 = args.get(1).and_then(|s| s.parse().ok()).unwrap_or(440.0); + let rate: u32 = args.get(2).and_then(|s| s.parse().ok()).unwrap_or(48_000); + + let path = wide(r"\\.\LibrePodsMic"); + let dev = unsafe { + CreateFileW( + path.as_ptr(), + GENERIC_WRITE, + FILE_SHARE_RW, + std::ptr::null_mut(), + OPEN_EXISTING, + 0, + std::ptr::null_mut(), + ) + }; + if dev == INVALID_HANDLE { + let e = unsafe { GetLastError() }; + eprintln!( + "Could not open \\\\.\\LibrePodsMic (error {e}). Is the LibrePodsMic \ + driver installed (install.ps1) and the virtual mic present?" + ); + std::process::exit(1); + } + println!("Feeding a {freq} Hz tone at {rate} Hz mono 16-bit into the virtual mic."); + println!("Record from \"Microphone (AudioCodec Device)\" to hear it. Ctrl+C to stop."); + + // 10 ms chunks, fed in real time so the ring tracks "now". + let chunk_frames = (rate / 100) as usize; // 10 ms + let mut phase: f64 = 0.0; + let step = 2.0 * PI * freq / rate as f64; + let amp = (i16::MAX as f64) * 0.30; + let mut pcm: Vec = vec![0; chunk_frames]; + + loop { + for s in pcm.iter_mut() { + *s = (phase.sin() * amp) as i16; + phase += step; + if phase >= 2.0 * PI { + phase -= 2.0 * PI; + } + } + let bytes = pcm.len() * 2; + let mut returned: u32 = 0; + let ok = unsafe { + DeviceIoControl( + dev, + IOCTL_LIBREPODS_MIC_WRITE_PCM, + pcm.as_ptr() as *const c_void, + bytes as u32, + std::ptr::null_mut(), + 0, + &mut returned, + std::ptr::null_mut(), + ) + }; + if ok == 0 { + let e = unsafe { GetLastError() }; + eprintln!("DeviceIoControl failed (error {e})."); + break; + } + unsafe { Sleep(10) }; + } + + unsafe { CloseHandle(dev) }; +} From 740914c1a0e6824106d65c55d9b32b7e798392b7 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:28:11 +0100 Subject: [PATCH 10/48] hires-mic: mark Phase 2 done (validated on hardware, clean tone) Bridge proven end-to-end: lp-mic-test's 440 Hz sine recorded and audible on the virtual mic, clean waveform with a single feeder. Phase 3 (AAP enable-mic + AAC-ELD decode from PR #655) is next. Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index ed1bd6ad1..426819538 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -73,7 +73,19 @@ the sink. Windows shows a virtual **"Microphone (AudioCodec Device)"** (confirmed on hardware). The audio source is still the sample's dummy; feeding real audio is next. -- **Phase 2 — next**: IOCTL/ring bridge so user mode can push PCM into the - capture circuit (`Common/CaptureCircuit.cpp` / `WaveReader.cpp`); test with a - tone/WAV heard on the virtual mic. +- **Phase 1b — DONE** ✅ (`522f9e8`): trimmed to **capture-only** — dropped the + render (speaker) circuit in `Device.cpp` (create/add/remove) so only a mic + endpoint exists (no phantom speaker grabbing default output). Builds clean. + `install.ps1` now `devcon remove`s any prior device before installing so + re-running updates in place. +- **Phase 2 — DONE** ✅ (`87ed69f`, validated on hardware): `Common/MicPipe.{h,cpp}` + — a spin-locked global PCM ring buffer + a control device `\\.\LibrePodsMic` + exposing `IOCTL_LIBREPODS_MIC_WRITE_PCM` (0x0022A000). `StreamEngine.cpp` + `ProcessPacket` drains the ring instead of the WAV/tone dummy. Proven end to + end: `lp-mic-test` (a user-mode tone feeder, `windows-driver/lp-mic-test/`) + pushed a 440 Hz sine and it was **recorded and audible** on "Microphone + (AudioCodec Device)". The audio-driver de-risk is complete. +- **Phase 3 — next**: replace the tone with the real thing — the AAP command + that enables the AirPods hi-res mic + AAC-ELD decode (FFmpeg) from PR #655, + pushing decoded PCM into `\\.\LibrePodsMic`. - Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. From 379e25b67a76a9072bbd85434c4f129b79a5695e Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:29:27 +0100 Subject: [PATCH 11/48] hires-mic(Phase 2): make the mic control device exclusive (one writer) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A virtual mic has a single audio source. Two processes writing the ring concurrently interleave and sound like static (seen while testing with multiple tone feeders running at once). WdfDeviceInitSetExclusive refuses a second open, so this class of corruption can't happen — the right behavior for Phase 3 where the app opens \\.\LibrePodsMic once and feeds the decoded AirPods audio. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp index 362357edc..a58019bd0 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp @@ -172,6 +172,11 @@ MicPipeCreateControlDevice( WdfDeviceInitSetDeviceType(init, FILE_DEVICE_UNKNOWN); WdfDeviceInitSetIoType(init, WdfDeviceIoBuffered); + // Single audio source: only one process may feed the mic at a time. Two + // writers interleaving in the ring sound like static, so refuse a second + // open (a stuck feeder is freed on its process exit / a driver reload). + WdfDeviceInitSetExclusive(init, TRUE); + status = WdfDeviceInitAssignName(init, &ntName); if (!NT_SUCCESS(status)) { WdfDeviceInitFree(init); From e810c95400b4258231b9c1925eb83c2798ef5ee7 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:44:26 +0100 Subject: [PATCH 12/48] =?UTF-8?q?hires-mic:=20lp-mic-rename=20=E2=80=94=20?= =?UTF-8?q?set=20the=20virtual=20mic's=20name=20(e.g.=20the=20AirPods')?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Standalone tool that finds the AudioCodec capture endpoint and sets its PKEY_Device_FriendlyName via IPolicyConfig (CPolicyConfigClient) — user-mode, no admin, no reboot. So the virtual mic can show "AirPods Pro de Pedro" instead of the driver's static "CustomName2 (AudioCodec Device)" in Discord/Teams/Zoom. The app will call this at runtime in Phase 4; this proves the mechanism. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-rename/.gitignore | 1 + .../windows-driver/lp-mic-rename/Cargo.toml | 22 +++ .../windows-driver/lp-mic-rename/src/main.rs | 186 ++++++++++++++++++ 3 files changed, 209 insertions(+) create mode 100644 crossplatform/windows-driver/lp-mic-rename/.gitignore create mode 100644 crossplatform/windows-driver/lp-mic-rename/Cargo.toml create mode 100644 crossplatform/windows-driver/lp-mic-rename/src/main.rs diff --git a/crossplatform/windows-driver/lp-mic-rename/.gitignore b/crossplatform/windows-driver/lp-mic-rename/.gitignore new file mode 100644 index 000000000..ea8c4bf7f --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-rename/.gitignore @@ -0,0 +1 @@ +/target diff --git a/crossplatform/windows-driver/lp-mic-rename/Cargo.toml b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml new file mode 100644 index 000000000..c1b25441f --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "lp-mic-rename" +version = "0.1.0" +edition = "2021" +description = "Rename the LibrePodsMic virtual microphone endpoint (e.g. to the connected AirPods' name) via IPolicyConfig." + +[dependencies] +windows = { version = "0.58", features = [ + "Win32_Foundation", + "Win32_System_Com", + "Win32_System_Com_StructuredStorage", + "Win32_Media_Audio", + "Win32_UI_Shell_PropertiesSystem", +] } + +[[bin]] +name = "lp-mic-rename" +path = "src/main.rs" + +[profile.release] +opt-level = "s" +strip = true diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs new file mode 100644 index 000000000..dfa56df12 --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -0,0 +1,186 @@ +//! Rename the LibrePodsMic virtual microphone endpoint's friendly name — e.g. to +//! the connected AirPods' name, so it shows as "AirPods Pro de Pedro" in Discord, +//! Teams, Zoom, etc. instead of the driver's static "CustomName2 (AudioCodec +//! Device)". +//! +//! It enumerates active capture endpoints, finds the one whose name contains +//! "AudioCodec", and sets its PKEY_Device_FriendlyName via IPolicyConfig +//! (CPolicyConfigClient) — the same runtime API MagicPods & co. use. User-mode, +//! no admin, no reboot. +//! +//! lp-mic-rename "AirPods Pro de Pedro" + +use std::ffi::c_void; + +use windows::core::{Interface, IUnknown, IUnknown_Vtbl, GUID, HRESULT, PWSTR}; +use windows::Win32::Media::Audio::{ + eCapture, IMMDeviceEnumerator, MMDeviceEnumerator, DEVICE_STATE_ACTIVE, +}; +use windows::Win32::System::Com::{ + CoCreateInstance, CoInitializeEx, CoTaskMemFree, CLSCTX_ALL, COINIT_MULTITHREADED, STGM_READ, +}; +use windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY; + +const CLSID_POLICY_CONFIG_CLIENT: GUID = GUID::from_u128(0x870af99c_171d_4f9e_af0d_e63df40c2bc9); + +// PKEY_Device_FriendlyName = {a45c254e-df1c-4efd-8020-67d146a850e0}, 14 +const PKEY_DEVICE_FRIENDLYNAME: PROPERTYKEY = PROPERTYKEY { + fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), + pid: 14, +}; + +const VT_LPWSTR: u16 = 31; + +// A PROPVARIANT holding a VT_LPWSTR — laid out to match the real 24-byte x64 +// PROPVARIANT (vt + 3 reserved u16, then the pointer union). We only ever set +// the string case, so the rest is padding. +#[repr(C)] +struct PropVariantStr { + vt: u16, + r1: u16, + r2: u16, + r3: u16, + pwsz: *mut u16, + _pad: u64, +} + +// IPolicyConfig (CPolicyConfigClient), IID f8679f50-850a-41cf-9c72-430f290290c8. +// We only need SetPropertyValue (the 10th method); everything before it is an +// opaque slot so the vtable offset is right. +#[repr(transparent)] +#[derive(Clone)] +struct IPolicyConfig(IUnknown); + +#[repr(C)] +#[allow(non_snake_case)] +struct IPolicyConfig_Vtbl { + base__: IUnknown_Vtbl, + GetMixFormat: usize, + GetDeviceFormat: usize, + ResetDeviceFormat: usize, + SetDeviceFormat: usize, + GetProcessingPeriod: usize, + SetProcessingPeriod: usize, + GetShareMode: usize, + SetShareMode: usize, + GetPropertyValue: usize, + // SetPropertyValue(PCWSTR name, const PROPERTYKEY& key, PROPVARIANT* pv) + SetPropertyValue: + unsafe extern "system" fn(*mut c_void, *const u16, *const c_void, *const c_void) -> HRESULT, +} + +unsafe impl Interface for IPolicyConfig { + type Vtable = IPolicyConfig_Vtbl; + const IID: GUID = GUID::from_u128(0xf8679f50_850a_41cf_9c72_430f290290c8); +} + +fn wide(s: &str) -> Vec { + s.encode_utf16().chain(std::iter::once(0)).collect() +} + +/// Read a null-terminated wide (UTF-16) string from a raw pointer. +unsafe fn wide_ptr_to_string(p: *const u16) -> String { + if p.is_null() { + return String::new(); + } + let mut len = 0isize; + while *p.offset(len) != 0 { + len += 1; + } + let slice = std::slice::from_raw_parts(p, len as usize); + String::from_utf16_lossy(slice) +} + +fn main() { + let name = std::env::args().nth(1).unwrap_or_else(|| { + eprintln!("usage: lp-mic-rename \"\""); + std::process::exit(2); + }); + + unsafe { + let _ = CoInitializeEx(None, COINIT_MULTITHREADED); + + let enumerator: IMMDeviceEnumerator = + CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL).expect("MMDeviceEnumerator"); + let collection = enumerator + .EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE) + .expect("EnumAudioEndpoints"); + let count = collection.GetCount().unwrap_or(0); + + let mut target: Option = None; + for i in 0..count { + let device = match collection.Item(i) { + Ok(d) => d, + Err(_) => continue, + }; + let id = match device.GetId() { + Ok(id) => id, + Err(_) => continue, + }; + let friendly = device + .OpenPropertyStore(STGM_READ) + .ok() + .and_then(|store| store.GetValue(&PKEY_DEVICE_FRIENDLYNAME).ok()) + .map(|pv| { + // PROPVARIANT holding the friendly name (VT_LPWSTR). Read the + // pointer directly via the matching layout; `pv` clears itself + // on drop. + let raw = &pv as *const _ as *const PropVariantStr; + if (*raw).vt == VT_LPWSTR { + wide_ptr_to_string((*raw).pwsz) + } else { + String::new() + } + }) + .unwrap_or_default(); + + if friendly.contains("AudioCodec") { + println!("Found the virtual mic: \"{friendly}\""); + target = Some(id); + break; + } + CoTaskMemFree(Some(id.0 as *const c_void)); + } + + let id = match target { + Some(id) => id, + None => { + eprintln!( + "Could not find the AudioCodec capture endpoint. Is the LibrePodsMic \ + driver installed and the virtual mic present?" + ); + std::process::exit(1); + } + }; + + let policy: IPolicyConfig = + CoCreateInstance(&CLSID_POLICY_CONFIG_CLIENT, None, CLSCTX_ALL) + .expect("CPolicyConfigClient"); + + let wname = wide(&name); + let pv = PropVariantStr { + vt: VT_LPWSTR, + r1: 0, + r2: 0, + r3: 0, + pwsz: wname.as_ptr() as *mut u16, + _pad: 0, + }; + + let hr = (policy.vtable().SetPropertyValue)( + policy.as_raw(), + id.0, + &PKEY_DEVICE_FRIENDLYNAME as *const _ as *const c_void, + &pv as *const _ as *const c_void, + ); + + CoTaskMemFree(Some(id.0 as *const c_void)); + + if hr.is_ok() { + println!("Renamed the virtual microphone to \"{name}\"."); + } else { + eprintln!("SetPropertyValue failed: {hr:?}"); + std::process::exit(1); + } + } +} From 66549f2399410dce2207702720fd5501f16b23a7 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:50:36 +0100 Subject: [PATCH 13/48] =?UTF-8?q?hires-mic:=20rename-mic.ps1=20=E2=80=94?= =?UTF-8?q?=20set=20the=20virtual=20mic=20name=20via=20registry=20(plan=20?= =?UTF-8?q?B)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The IPolicyConfig runtime path (lp-mic-rename) crashed on Win11 (the interface vtable layout varies by Windows version). This is the reliable fallback: write PKEY_Device_FriendlyName on the AudioCodec capture endpoint in the registry (elevated) and restart AudioEndpointBuilder to apply without a reboot — the same mechanism SoundVolumeView uses. Co-Authored-By: Claude Opus 4.8 --- .../LibrePodsMic/rename-mic.ps1 | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 diff --git a/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 new file mode 100644 index 000000000..aa57dbad5 --- /dev/null +++ b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 @@ -0,0 +1,37 @@ +<# + rename-mic.ps1 - set the LibrePodsMic virtual microphone's display name (e.g. + the connected AirPods' name), the reliable registry way. RUN AS ADMINISTRATOR. + + .\rename-mic.ps1 "AirPods Pro de Pedro" + + Writes PKEY_Device_FriendlyName on the AudioCodec capture endpoint and + refreshes the audio endpoint service so apps pick it up without a reboot. + (Plan B for when the IPolicyConfig runtime path isn't available.) +#> +param([Parameter(Mandatory)][string]$Name) +$ErrorActionPreference = 'Stop' + +$base = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture' +$descKey = '{a45c254e-df1c-4efd-8020-67d146a850e0},2' # PKEY_Device_DeviceDesc +$fnKey = '{a45c254e-df1c-4efd-8020-67d146a850e0},14' # PKEY_Device_FriendlyName + +$found = $false +Get-ChildItem $base | ForEach-Object { + $props = Join-Path $_.PSPath 'Properties' + try { $desc = (Get-ItemProperty -Path $props -Name $descKey -ErrorAction Stop).$descKey } + catch { $desc = $null } + if ($desc -like '*AudioCodec*') { + Set-ItemProperty -Path $props -Name $fnKey -Value $Name -Type String + Write-Host "==> Renamed '$desc' -> '$Name'" + $found = $true + } +} + +if (-not $found) { + Write-Host 'AudioCodec capture endpoint not found. Is the LibrePodsMic driver installed?' + exit 1 +} + +Write-Host '==> Refreshing the audio endpoint service (brief audio drop)...' +Restart-Service -Name AudioEndpointBuilder -Force +Write-Host '==> Done. Check Sound settings / Discord - it should show the new name.' From 1df638b84a09494ea459d5260058845433a1101c Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 18:54:37 +0100 Subject: [PATCH 14/48] =?UTF-8?q?hires-mic:=20rename-mic.ps1=20=E2=80=94?= =?UTF-8?q?=20handle=20REG=5FBINARY=20PROPVARIANT=20+=20list=20endpoints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MMDevices property values are REG_BINARY (4-byte type tag + UTF-16), not plain strings, so the first version never matched. Decode/encode the PROPVARIANT properly, match on decoded DeviceDesc OR FriendlyName, and list all capture endpoints for visibility. Co-Authored-By: Claude Opus 4.8 --- .../LibrePodsMic/rename-mic.ps1 | 45 +++++++++++++------ 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 index aa57dbad5..877ba463d 100644 --- a/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 +++ b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 @@ -1,12 +1,14 @@ <# rename-mic.ps1 - set the LibrePodsMic virtual microphone's display name (e.g. - the connected AirPods' name), the reliable registry way. RUN AS ADMINISTRATOR. + the connected AirPods' name). RUN AS ADMINISTRATOR. .\rename-mic.ps1 "AirPods Pro de Pedro" - Writes PKEY_Device_FriendlyName on the AudioCodec capture endpoint and - refreshes the audio endpoint service so apps pick it up without a reboot. - (Plan B for when the IPolicyConfig runtime path isn't available.) + MMDevices property values are REG_BINARY serialized PROPVARIANTs (4-byte type + tag + UTF-16 string), not plain strings - this reads/writes them correctly. + It matches the AudioCodec capture endpoint by DeviceDesc/FriendlyName, sets + PKEY_Device_FriendlyName, and refreshes the audio endpoint service so apps + pick it up without a reboot. (Plan B for when IPolicyConfig isn't available.) #> param([Parameter(Mandatory)][string]$Name) $ErrorActionPreference = 'Stop' @@ -15,23 +17,40 @@ $base = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capt $descKey = '{a45c254e-df1c-4efd-8020-67d146a850e0},2' # PKEY_Device_DeviceDesc $fnKey = '{a45c254e-df1c-4efd-8020-67d146a850e0},14' # PKEY_Device_FriendlyName -$found = $false +# Decode a REG_BINARY PROPVARIANT string value (skip the 4-byte type tag). +function Decode-PropStr($bytes) { + if (-not $bytes -or $bytes.Length -le 4) { return '' } + $s = [System.Text.Encoding]::Unicode.GetString($bytes[4..($bytes.Length - 1)]) + return $s.TrimEnd([char]0) +} +# Encode a string as a VT_LPWSTR PROPVARIANT REG_BINARY (0x1F tag + UTF-16 + NUL). +function Encode-PropStr([string]$s) { + $prefix = [byte[]](0x1F, 0x00, 0x00, 0x00) + $data = [System.Text.Encoding]::Unicode.GetBytes($s + [char]0) + return $prefix + $data +} + +$target = $null +Write-Host '==> Capture endpoints found:' Get-ChildItem $base | ForEach-Object { $props = Join-Path $_.PSPath 'Properties' - try { $desc = (Get-ItemProperty -Path $props -Name $descKey -ErrorAction Stop).$descKey } - catch { $desc = $null } - if ($desc -like '*AudioCodec*') { - Set-ItemProperty -Path $props -Name $fnKey -Value $Name -Type String - Write-Host "==> Renamed '$desc' -> '$Name'" - $found = $true + $p = Get-ItemProperty -Path $props -ErrorAction SilentlyContinue + $desc = if ($p.$descKey) { Decode-PropStr $p.$descKey } else { '' } + $fn = if ($p.$fnKey) { Decode-PropStr $p.$fnKey } else { '' } + Write-Host (" [{0}] desc='{1}' friendly='{2}'" -f $_.PSChildName, $desc, $fn) + if ($desc -like '*AudioCodec*' -or $fn -like '*AudioCodec*') { + $target = $props } } -if (-not $found) { - Write-Host 'AudioCodec capture endpoint not found. Is the LibrePodsMic driver installed?' +if (-not $target) { + Write-Host 'No AudioCodec capture endpoint matched. Is the LibrePodsMic driver installed?' exit 1 } +Set-ItemProperty -Path $target -Name $fnKey -Value (Encode-PropStr $Name) -Type Binary +Write-Host "==> Set FriendlyName -> '$Name'" + Write-Host '==> Refreshing the audio endpoint service (brief audio drop)...' Restart-Service -Name AudioEndpointBuilder -Force Write-Host '==> Done. Check Sound settings / Discord - it should show the new name.' From 224d78d4c942afa5baf919d1a93ad32738c114a0 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:01:45 +0100 Subject: [PATCH 15/48] windows-tray: theme-aware UI (dark/light) + Win11-flyout overlay style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the Windows theme instead of a fixed dark look: - theme.rs: read AppsUseLightTheme / SystemUsesLightTheme from the registry. - Overlay: restyle like the Win11 volume/brightness flyout — native DWM rounded corners + immersive dark-mode chrome + a subtle border, and a theme-aware fill (dark card/light text in dark mode, light card/dark text in light mode). Replaces the color-key rounding hack. Re-reads the theme on each show. - Tray icon: draw the battery % digits dark on a light taskbar, white on a dark one (SystemUsesLightTheme) — otherwise white digits vanished on a light taskbar. Note: the flyout's translucent acrylic *blur* isn't included (that needs per-pixel-alpha layered compositing); this matches the shape, color, and theme. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/Cargo.toml | 2 + .../windows-app/librepods-tray/src/main.rs | 10 ++- .../windows-app/librepods-tray/src/overlay.rs | 74 ++++++++++++------- .../windows-app/librepods-tray/src/theme.rs | 40 ++++++++++ 4 files changed, 100 insertions(+), 26 deletions(-) create mode 100644 crossplatform/windows-app/librepods-tray/src/theme.rs diff --git a/crossplatform/windows-app/librepods-tray/Cargo.toml b/crossplatform/windows-app/librepods-tray/Cargo.toml index e083698b3..a46570bd5 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.toml +++ b/crossplatform/windows-app/librepods-tray/Cargo.toml @@ -13,12 +13,14 @@ imageproc = "0.25" windows-sys = { version = "0.59", features = [ "Win32_Foundation", "Win32_System_IO", + "Win32_System_Registry", "Win32_Storage_FileSystem", "Win32_Security", "Win32_Devices_DeviceAndDriverInstallation", "Win32_Devices_Bluetooth", "Win32_UI_WindowsAndMessaging", "Win32_Graphics_Gdi", + "Win32_Graphics_Dwm", "Win32_System_LibraryLoader", ] } # `windows` (full COM/WinRT) for Core Audio volume control + SMTC media control. diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 9f5d1cf95..eb33e45a6 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -14,6 +14,7 @@ mod bt; mod driver; mod media; mod overlay; +mod theme; mod volume; use std::sync::{Arc, Mutex}; @@ -94,7 +95,14 @@ fn battery_icon(percent: u8) -> Icon { let x = ((w as f32 - tw) / 2.0).max(0.0) as i32; let y = ((h as f32 - scale.y) / 2.0).max(0.0) as i32 - 2; - draw_text_mut(&mut img, Rgba([255u8, 255, 255, 255]), x, y, scale, &font, &text); + // Contrast with the taskbar: white digits on a dark taskbar, near-black on a + // light one (otherwise white digits vanish on a light taskbar). + let digit = if theme::system_dark() { + Rgba([255u8, 255, 255, 255]) + } else { + Rgba([24u8, 24, 24, 255]) + }; + draw_text_mut(&mut img, digit, x, y, scale, &font, &text); Icon::from_rgba(img.into_raw(), w, h).unwrap_or_else(|_| make_icon()) } diff --git a/crossplatform/windows-app/librepods-tray/src/overlay.rs b/crossplatform/windows-app/librepods-tray/src/overlay.rs index 2e9cf8ba1..74dadf3bd 100644 --- a/crossplatform/windows-app/librepods-tray/src/overlay.rs +++ b/crossplatform/windows-app/librepods-tray/src/overlay.rs @@ -1,7 +1,8 @@ -//! MagicPods-style centered popup overlay. A borderless, always-on-top, -//! click-through window that appears near the top-center of the screen on events -//! (connect, ANC change, case open/close), shows the AirPods name + a status -//! line, and auto-hides after a few seconds. +//! MagicPods-style centered popup overlay, styled like the Windows 11 volume/ +//! brightness flyout: a rounded card (native DWM corners), a subtle border, and +//! a theme-aware fill (dark card in dark mode, light in light mode). Appears near +//! the top-center on events (connect, ANC change, case open/close), shows the +//! AirPods name + a status line, and auto-hides after a few seconds. //! //! Created on the main (message-loop) thread via `init()`; `show()` is callable //! from any thread — it stashes the text and posts a message to the window, @@ -10,16 +11,16 @@ use std::sync::{Mutex, OnceLock}; use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM}; +use windows_sys::Win32::Graphics::Dwm::DwmSetWindowAttribute; use windows_sys::Win32::Graphics::Gdi::{ BeginPaint, CreateFontW, CreateSolidBrush, DeleteObject, DrawTextW, EndPaint, FillRect, - InvalidateRect, PAINTSTRUCT, RoundRect, SelectObject, SetBkMode, SetTextColor, + InvalidateRect, PAINTSTRUCT, SelectObject, SetBkMode, SetTextColor, }; use windows_sys::Win32::System::LibraryLoader::GetModuleHandleW; use windows_sys::Win32::UI::WindowsAndMessaging::{ - CreateWindowExW, DefWindowProcW, GetSystemMetrics, KillTimer, LWA_COLORKEY, PostMessageW, - RegisterClassW, SM_CXSCREEN, SW_HIDE, SW_SHOWNA, SWP_NOACTIVATE, SetLayeredWindowAttributes, - SetTimer, SetWindowPos, ShowWindow, WM_APP, WM_PAINT, WM_TIMER, WNDCLASSW, WS_EX_LAYERED, - WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_EX_TRANSPARENT, WS_POPUP, + CreateWindowExW, DefWindowProcW, GetSystemMetrics, KillTimer, PostMessageW, RegisterClassW, + SM_CXSCREEN, SW_HIDE, SW_SHOWNA, SWP_NOACTIVATE, SetTimer, SetWindowPos, ShowWindow, WM_APP, + WM_PAINT, WM_TIMER, WNDCLASSW, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TOPMOST, WS_POPUP, }; const WIDTH: i32 = 380; @@ -36,6 +37,12 @@ const FW_BOLD: i32 = 700; const FW_NORMAL: i32 = 400; const DEFAULT_CHARSET_U: u32 = 1; +// DWM window attributes (dwmapi). +const DWMWA_USE_IMMERSIVE_DARK_MODE: u32 = 20; +const DWMWA_WINDOW_CORNER_PREFERENCE: u32 = 33; +const DWMWA_BORDER_COLOR: u32 = 34; +const DWMWCP_ROUND: u32 = 2; + /// (title, subtitle) to render. `show()` sets it from any thread. static CONTENT: Mutex<(String, String)> = Mutex::new((String::new(), String::new())); /// The overlay window handle as usize (HWND isn't Send). Set once in `init()`. @@ -45,6 +52,21 @@ fn to_utf16(s: &str) -> Vec { s.encode_utf16().chain(std::iter::once(0)).collect() } +unsafe fn dwm_set_u32(hwnd: HWND, attr: u32, value: u32) { + DwmSetWindowAttribute(hwnd, attr, &value as *const u32 as *const core::ffi::c_void, 4); +} + +/// Apply the current Windows theme to the window chrome (immersive dark title/ +/// border tone + a subtle border color). Called on each show so a theme switch +/// is reflected. +unsafe fn apply_theme(hwnd: HWND) { + let dark = crate::theme::apps_dark(); + dwm_set_u32(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, dark as u32); + // Subtle 1px border (COLORREF 0x00BBGGRR), a touch lighter/darker than the card. + let border = if dark { 0x0045_4545 } else { 0x00D0_D0D0 }; + dwm_set_u32(hwnd, DWMWA_BORDER_COLOR, border); +} + /// Create the (hidden) overlay window. Call once on the message-loop thread. pub fn init() { unsafe { @@ -66,7 +88,7 @@ pub fn init() { RegisterClassW(&wc); let hwnd = CreateWindowExW( - WS_EX_LAYERED | WS_EX_TOPMOST | WS_EX_TOOLWINDOW | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT, + WS_EX_TOOLWINDOW | WS_EX_TOPMOST | WS_EX_NOACTIVATE, class_name.as_ptr(), std::ptr::null(), WS_POPUP, @@ -82,10 +104,9 @@ pub fn init() { if hwnd.is_null() { return; } - // Color-key pure black to transparent: the window fills black (invisible) - // and only the non-black rounded card + text show — so it's a floating - // pill, not a black square. - SetLayeredWindowAttributes(hwnd, 0x0000_0000, 0, LWA_COLORKEY); + // Native rounded corners (Windows 11), like the system flyouts. + dwm_set_u32(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_ROUND); + apply_theme(hwnd); let _ = HWND_CELL.set(hwnd as usize); } } @@ -106,6 +127,7 @@ pub fn show(title: &str, subtitle: &str) { unsafe extern "system" fn wnd_proc(hwnd: HWND, msg: u32, wp: WPARAM, lp: LPARAM) -> LRESULT { match msg { WM_SHOW_OVERLAY => { + apply_theme(hwnd); // pick up a theme switch since last shown let x = (GetSystemMetrics(SM_CXSCREEN) - WIDTH) / 2; SetWindowPos(hwnd, HWND_TOPMOST, x, TOP_MARGIN, WIDTH, HEIGHT, SWP_NOACTIVATE); ShowWindow(hwnd, SW_SHOWNA); @@ -145,31 +167,33 @@ unsafe fn paint(hwnd: HWND) { let mut ps: PAINTSTRUCT = std::mem::zeroed(); let hdc = BeginPaint(hwnd, &mut ps); - // Opaque black backdrop (the layered alpha softens the edges). + // Theme-aware fill (COLORREF is 0x00BBGGRR). DWM clips the corners round, so + // we just fill the whole client with the flyout card color. Dark card + light + // text in dark mode; light card + dark text in light mode. + let dark = crate::theme::apps_dark(); + let (card_col, title_col, sub_col) = if dark { + (0x002B_2B2B, 0x00FF_FFFF, 0x00C8_C8C8) + } else { + (0x00F3_F3F3, 0x0020_2020, 0x0060_6060) + }; + let full = RECT { left: 0, top: 0, right: WIDTH, bottom: HEIGHT }; - let bg = CreateSolidBrush(0x00000000); + let bg = CreateSolidBrush(card_col); FillRect(hdc, &full, bg); DeleteObject(bg); - // Rounded dark card (COLORREF is 0x00BBGGRR). - let card = CreateSolidBrush(0x0022262A); - let old_brush = SelectObject(hdc, card); - RoundRect(hdc, 6, 6, WIDTH - 6, HEIGHT - 6, 28, 28); - SelectObject(hdc, old_brush); - DeleteObject(card); - let (title, subtitle) = CONTENT.lock().map(|c| c.clone()).unwrap_or_default(); SetBkMode(hdc, BK_TRANSPARENT); let title_font = font(26, FW_BOLD); let old = SelectObject(hdc, title_font); - draw_line(hdc, &title, 16, 52, 0x00FFFFFF); // white + draw_line(hdc, &title, 16, 52, title_col); SelectObject(hdc, old); DeleteObject(title_font); let sub_font = font(20, FW_NORMAL); let old = SelectObject(hdc, sub_font); - draw_line(hdc, &subtitle, 52, HEIGHT - 12, 0x00B8B8B8); // gray + draw_line(hdc, &subtitle, 52, HEIGHT - 12, sub_col); SelectObject(hdc, old); DeleteObject(sub_font); diff --git a/crossplatform/windows-app/librepods-tray/src/theme.rs b/crossplatform/windows-app/librepods-tray/src/theme.rs new file mode 100644 index 000000000..439216326 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/theme.rs @@ -0,0 +1,40 @@ +//! Windows light/dark theme detection via the registry. Windows tracks two +//! flags: `AppsUseLightTheme` (app windows — our overlay) and +//! `SystemUsesLightTheme` (the shell/taskbar — our tray icon). They can differ, +//! so read the one that matches the surface being drawn. + +use windows_sys::Win32::System::Registry::{RegGetValueW, HKEY_CURRENT_USER, RRF_RT_REG_DWORD}; + +fn dword(value: &str) -> Option { + let sub: Vec = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize" + .encode_utf16() + .chain(std::iter::once(0)) + .collect(); + let val: Vec = value.encode_utf16().chain(std::iter::once(0)).collect(); + let mut data: u32 = 0; + let mut size = 4u32; + let r = unsafe { + RegGetValueW( + HKEY_CURRENT_USER, + sub.as_ptr(), + val.as_ptr(), + RRF_RT_REG_DWORD, + std::ptr::null_mut(), + &mut data as *mut u32 as *mut core::ffi::c_void, + &mut size, + ) + }; + if r == 0 { Some(data) } else { None } +} + +/// True if app windows use the dark theme. Defaults to dark if the key is +/// missing (the common Windows default, and our historical look). +pub fn apps_dark() -> bool { + dword("AppsUseLightTheme").map(|v| v == 0).unwrap_or(true) +} + +/// True if the system (taskbar) uses the dark theme. Governs the tray-icon +/// contrast. Defaults to dark if unknown. +pub fn system_dark() -> bool { + dword("SystemUsesLightTheme").map(|v| v == 0).unwrap_or(true) +} From b3855f1943c7cb2511adcac24cd3ec954dcb0dfd Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:09:23 +0100 Subject: [PATCH 16/48] windows-tray: acrylic flyout overlay + dark/light context menu - Overlay: add the Win11 acrylic backdrop (DWMWA_SYSTEMBACKDROP_TYPE = DWMSBT_TRANSIENTWINDOW) with the frame extended across the client, painting the client "glass" (black) so the translucent material shows through. Falls back to the solid theme card on OSes that don't support it (hr < 0). - Context menu: Win32 menus ignore dark mode by default; opt in via the undocumented uxtheme SetPreferredAppMode (135) + FlushMenuThemes (136), keyed to the app theme (theme::apply_menu_theme), applied at startup and each refresh. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/Cargo.toml | 1 + .../windows-app/librepods-tray/src/main.rs | 2 + .../windows-app/librepods-tray/src/overlay.rs | 48 +++++++++++++++++-- .../windows-app/librepods-tray/src/theme.rs | 24 ++++++++++ 4 files changed, 71 insertions(+), 4 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/Cargo.toml b/crossplatform/windows-app/librepods-tray/Cargo.toml index a46570bd5..707128919 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.toml +++ b/crossplatform/windows-app/librepods-tray/Cargo.toml @@ -19,6 +19,7 @@ windows-sys = { version = "0.59", features = [ "Win32_Devices_DeviceAndDriverInstallation", "Win32_Devices_Bluetooth", "Win32_UI_WindowsAndMessaging", + "Win32_UI_Controls", "Win32_Graphics_Gdi", "Win32_Graphics_Dwm", "Win32_System_LibraryLoader", diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index eb33e45a6..b3cc8984e 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -269,6 +269,7 @@ fn run_receiver( fn main() { volume::init(); // COM for Core Audio, on this (main) thread overlay::init(); // create the (hidden) centered popup window on this thread + theme::apply_menu_theme(); // dark/light Win32 context menu, per the OS theme let state: Shared = Arc::new(Mutex::new(State::default())); @@ -383,6 +384,7 @@ fn main() { _ => make_icon(), }; let _ = tray.set_icon(Some(icon)); + theme::apply_menu_theme(); // keep the menu theme in sync with the OS }; unsafe { diff --git a/crossplatform/windows-app/librepods-tray/src/overlay.rs b/crossplatform/windows-app/librepods-tray/src/overlay.rs index 74dadf3bd..7694158c5 100644 --- a/crossplatform/windows-app/librepods-tray/src/overlay.rs +++ b/crossplatform/windows-app/librepods-tray/src/overlay.rs @@ -8,10 +8,12 @@ //! from any thread — it stashes the text and posts a message to the window, //! which the main thread's `GetMessage` loop dispatches to `wnd_proc`. +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Mutex, OnceLock}; use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM}; -use windows_sys::Win32::Graphics::Dwm::DwmSetWindowAttribute; +use windows_sys::Win32::Graphics::Dwm::{DwmExtendFrameIntoClientArea, DwmSetWindowAttribute}; +use windows_sys::Win32::UI::Controls::MARGINS; use windows_sys::Win32::Graphics::Gdi::{ BeginPaint, CreateFontW, CreateSolidBrush, DeleteObject, DrawTextW, EndPaint, FillRect, InvalidateRect, PAINTSTRUCT, SelectObject, SetBkMode, SetTextColor, @@ -41,7 +43,13 @@ const DEFAULT_CHARSET_U: u32 = 1; const DWMWA_USE_IMMERSIVE_DARK_MODE: u32 = 20; const DWMWA_WINDOW_CORNER_PREFERENCE: u32 = 33; const DWMWA_BORDER_COLOR: u32 = 34; +const DWMWA_SYSTEMBACKDROP_TYPE: u32 = 38; const DWMWCP_ROUND: u32 = 2; +const DWMSBT_TRANSIENTWINDOW: u32 = 3; // acrylic flyout material + +/// Whether the acrylic backdrop is active (Win11 22H2+). When true we paint the +/// client "glass" (black) so the acrylic shows; otherwise a solid card. +static ACRYLIC: AtomicBool = AtomicBool::new(false); /// (title, subtitle) to render. `show()` sets it from any thread. static CONTENT: Mutex<(String, String)> = Mutex::new((String::new(), String::new())); @@ -106,6 +114,28 @@ pub fn init() { } // Native rounded corners (Windows 11), like the system flyouts. dwm_set_u32(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_ROUND); + + // Acrylic flyout backdrop (Win11 22H2+). If it takes, extend the frame + // across the whole client so the material fills the card, and paint the + // client "glass" (black) so it shows through. Older OSes ignore it (hr<0) + // and we fall back to the solid card. + let hr = DwmSetWindowAttribute( + hwnd, + DWMWA_SYSTEMBACKDROP_TYPE, + &DWMSBT_TRANSIENTWINDOW as *const u32 as *const core::ffi::c_void, + 4, + ); + if hr >= 0 { + let m = MARGINS { + cxLeftWidth: -1, + cxRightWidth: -1, + cyTopHeight: -1, + cyBottomHeight: -1, + }; + DwmExtendFrameIntoClientArea(hwnd, &m); + ACRYLIC.store(true, Ordering::Relaxed); + } + apply_theme(hwnd); let _ = HWND_CELL.set(hwnd as usize); } @@ -171,10 +201,20 @@ unsafe fn paint(hwnd: HWND) { // we just fill the whole client with the flyout card color. Dark card + light // text in dark mode; light card + dark text in light mode. let dark = crate::theme::apps_dark(); - let (card_col, title_col, sub_col) = if dark { - (0x002B_2B2B, 0x00FF_FFFF, 0x00C8_C8C8) + let acrylic = ACRYLIC.load(Ordering::Relaxed); + let (title_col, sub_col) = if dark { + (0x00FF_FFFF, 0x00C8_C8C8) + } else { + (0x0020_2020, 0x0060_6060) + }; + // In acrylic mode the client is glass: pure black = fully transparent, so the + // acrylic backdrop shows through. Otherwise a solid theme card. + let card_col: u32 = if acrylic { + 0x0000_0000 + } else if dark { + 0x002B_2B2B } else { - (0x00F3_F3F3, 0x0020_2020, 0x0060_6060) + 0x00F3_F3F3 }; let full = RECT { left: 0, top: 0, right: WIDTH, bottom: HEIGHT }; diff --git a/crossplatform/windows-app/librepods-tray/src/theme.rs b/crossplatform/windows-app/librepods-tray/src/theme.rs index 439216326..78a578ce7 100644 --- a/crossplatform/windows-app/librepods-tray/src/theme.rs +++ b/crossplatform/windows-app/librepods-tray/src/theme.rs @@ -3,6 +3,7 @@ //! `SystemUsesLightTheme` (the shell/taskbar — our tray icon). They can differ, //! so read the one that matches the surface being drawn. +use windows_sys::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryW}; use windows_sys::Win32::System::Registry::{RegGetValueW, HKEY_CURRENT_USER, RRF_RT_REG_DWORD}; fn dword(value: &str) -> Option { @@ -38,3 +39,26 @@ pub fn apps_dark() -> bool { pub fn system_dark() -> bool { dword("SystemUsesLightTheme").map(|v| v == 0).unwrap_or(true) } + +/// Make Win32 context menus (the tray's right-click menu) follow the app theme, +/// via the undocumented uxtheme ordinals SetPreferredAppMode (135) + +/// FlushMenuThemes (136). Win32 menus don't honor dark mode otherwise. No-op on +/// OSes without these exports. Call at startup and whenever the theme may change. +pub fn apply_menu_theme() { + unsafe { + let name: Vec = "uxtheme.dll".encode_utf16().chain(std::iter::once(0)).collect(); + let lib = LoadLibraryW(name.as_ptr()); + if lib.is_null() { + return; + } + // SetPreferredAppMode(PreferredAppMode): 2 = ForceDark, 3 = ForceLight. + if let Some(set) = GetProcAddress(lib, 135usize as *const u8) { + let set: unsafe extern "system" fn(i32) -> i32 = std::mem::transmute(set); + set(if apps_dark() { 2 } else { 3 }); + } + if let Some(flush) = GetProcAddress(lib, 136usize as *const u8) { + let flush: unsafe extern "system" fn() = std::mem::transmute(flush); + flush(); + } + } +} From 74912f604f10f456d78537b6c669e3d8f4ed26c0 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:14:10 +0100 Subject: [PATCH 17/48] windows-tray: revert overlay to the solid card (acrylic looked worse) The acrylic backdrop washed the card out and muddied the corner; the solid theme-aware card with native rounded corners + border looks cleaner. Keep the rounded corners, theme-following colors, and the dark/light context menu; drop only the acrylic backdrop + glass fill. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/Cargo.toml | 1 - .../windows-app/librepods-tray/src/overlay.rs | 48 ++----------------- 2 files changed, 4 insertions(+), 45 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/Cargo.toml b/crossplatform/windows-app/librepods-tray/Cargo.toml index 707128919..a46570bd5 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.toml +++ b/crossplatform/windows-app/librepods-tray/Cargo.toml @@ -19,7 +19,6 @@ windows-sys = { version = "0.59", features = [ "Win32_Devices_DeviceAndDriverInstallation", "Win32_Devices_Bluetooth", "Win32_UI_WindowsAndMessaging", - "Win32_UI_Controls", "Win32_Graphics_Gdi", "Win32_Graphics_Dwm", "Win32_System_LibraryLoader", diff --git a/crossplatform/windows-app/librepods-tray/src/overlay.rs b/crossplatform/windows-app/librepods-tray/src/overlay.rs index 7694158c5..74dadf3bd 100644 --- a/crossplatform/windows-app/librepods-tray/src/overlay.rs +++ b/crossplatform/windows-app/librepods-tray/src/overlay.rs @@ -8,12 +8,10 @@ //! from any thread — it stashes the text and posts a message to the window, //! which the main thread's `GetMessage` loop dispatches to `wnd_proc`. -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Mutex, OnceLock}; use windows_sys::Win32::Foundation::{HWND, LPARAM, LRESULT, RECT, WPARAM}; -use windows_sys::Win32::Graphics::Dwm::{DwmExtendFrameIntoClientArea, DwmSetWindowAttribute}; -use windows_sys::Win32::UI::Controls::MARGINS; +use windows_sys::Win32::Graphics::Dwm::DwmSetWindowAttribute; use windows_sys::Win32::Graphics::Gdi::{ BeginPaint, CreateFontW, CreateSolidBrush, DeleteObject, DrawTextW, EndPaint, FillRect, InvalidateRect, PAINTSTRUCT, SelectObject, SetBkMode, SetTextColor, @@ -43,13 +41,7 @@ const DEFAULT_CHARSET_U: u32 = 1; const DWMWA_USE_IMMERSIVE_DARK_MODE: u32 = 20; const DWMWA_WINDOW_CORNER_PREFERENCE: u32 = 33; const DWMWA_BORDER_COLOR: u32 = 34; -const DWMWA_SYSTEMBACKDROP_TYPE: u32 = 38; const DWMWCP_ROUND: u32 = 2; -const DWMSBT_TRANSIENTWINDOW: u32 = 3; // acrylic flyout material - -/// Whether the acrylic backdrop is active (Win11 22H2+). When true we paint the -/// client "glass" (black) so the acrylic shows; otherwise a solid card. -static ACRYLIC: AtomicBool = AtomicBool::new(false); /// (title, subtitle) to render. `show()` sets it from any thread. static CONTENT: Mutex<(String, String)> = Mutex::new((String::new(), String::new())); @@ -114,28 +106,6 @@ pub fn init() { } // Native rounded corners (Windows 11), like the system flyouts. dwm_set_u32(hwnd, DWMWA_WINDOW_CORNER_PREFERENCE, DWMWCP_ROUND); - - // Acrylic flyout backdrop (Win11 22H2+). If it takes, extend the frame - // across the whole client so the material fills the card, and paint the - // client "glass" (black) so it shows through. Older OSes ignore it (hr<0) - // and we fall back to the solid card. - let hr = DwmSetWindowAttribute( - hwnd, - DWMWA_SYSTEMBACKDROP_TYPE, - &DWMSBT_TRANSIENTWINDOW as *const u32 as *const core::ffi::c_void, - 4, - ); - if hr >= 0 { - let m = MARGINS { - cxLeftWidth: -1, - cxRightWidth: -1, - cyTopHeight: -1, - cyBottomHeight: -1, - }; - DwmExtendFrameIntoClientArea(hwnd, &m); - ACRYLIC.store(true, Ordering::Relaxed); - } - apply_theme(hwnd); let _ = HWND_CELL.set(hwnd as usize); } @@ -201,20 +171,10 @@ unsafe fn paint(hwnd: HWND) { // we just fill the whole client with the flyout card color. Dark card + light // text in dark mode; light card + dark text in light mode. let dark = crate::theme::apps_dark(); - let acrylic = ACRYLIC.load(Ordering::Relaxed); - let (title_col, sub_col) = if dark { - (0x00FF_FFFF, 0x00C8_C8C8) - } else { - (0x0020_2020, 0x0060_6060) - }; - // In acrylic mode the client is glass: pure black = fully transparent, so the - // acrylic backdrop shows through. Otherwise a solid theme card. - let card_col: u32 = if acrylic { - 0x0000_0000 - } else if dark { - 0x002B_2B2B + let (card_col, title_col, sub_col) = if dark { + (0x002B_2B2B, 0x00FF_FFFF, 0x00C8_C8C8) } else { - 0x00F3_F3F3 + (0x00F3_F3F3, 0x0020_2020, 0x0060_6060) }; let full = RECT { left: 0, top: 0, right: WIDTH, bottom: HEIGHT }; From c843d32aa9305e6ca8d3da3c198da5876376ef39 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:21:00 +0100 Subject: [PATCH 18/48] hires-mic(Phase 3a): enable-command de-risk in the tray MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the AAP hi-res mic start/stop commands (from PR #655) and a "Hi-res microphone (test)" menu toggle. On enable, send START_AUDIO over the existing AAP session; the receive loop counts the 0x58 uplink audio packets and pops a "receiving audio" card once the stream is confirmed flowing. No decode yet — this proves the enable command works on real AirPods before investing in the AAC-ELD (FFmpeg) decode. aap.rs: START_AUDIO/STOP_AUDIO + is_audio_packet. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/aap.rs | 21 ++++++++++ .../windows-app/librepods-tray/src/main.rs | 41 ++++++++++++++++++- 2 files changed, 60 insertions(+), 2 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/aap.rs b/crossplatform/windows-app/librepods-tray/src/aap.rs index 1d7ca563f..75c9ca126 100644 --- a/crossplatform/windows-app/librepods-tray/src/aap.rs +++ b/crossplatform/windows-app/librepods-tray/src/aap.rs @@ -11,6 +11,27 @@ pub const SET_FEATURES: [u8; 14] = [ pub const REQUEST_NOTIFS: [u8; 10] = [0x04, 0x00, 0x04, 0x00, 0x0F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; +/// Enable the hi-res (AAC-ELD) microphone stream — the AirPods start pushing +/// 0x58 uplink audio packets. From LibrePods PR #655. +pub const START_AUDIO: [u8; 19] = [ + 0x04, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00, 0x00, + 0x04, 0x96, 0x00, +]; +/// Stop the hi-res microphone stream. +pub const STOP_AUDIO: [u8; 12] = [ + 0x04, 0x00, 0x04, 0x00, 0x58, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x01, +]; + +/// True if `data` is a 0x58 uplink audio packet (carries AAC-ELD frames). +pub fn is_audio_packet(data: &[u8]) -> bool { + data.len() >= 8 + && data[0] == 0x04 + && data[2] == 0x04 + && data[4] == 0x58 + && data[6] == 0x01 + && data[7] == 0x00 +} + /// Listening-mode (ANC) control command. value = mode (1 off, 2 anc, 3 transparency, 4 adaptive). pub fn anc_command(mode: u8) -> [u8; 11] { [0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x0D, mode, 0x00, 0x00, 0x00] diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index b3cc8984e..d933f4c74 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -17,6 +17,7 @@ mod overlay; mod theme; mod volume; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::thread; use std::time::Duration; @@ -127,8 +128,10 @@ fn run_receiver( state: Shared, dev_name: String, driver_cell: Arc>>, + mic_on: Arc, ) { - let mut buf = [0u8; 1024]; + let mut buf = [0u8; 2048]; + let mut audio_pkts = 0u32; media::init(); // COM (MTA) for the SMTC ear-detection auto-pause on this thread let mut last_anc = 0u8; let mut last_case_present: Option = None; @@ -178,6 +181,18 @@ fn run_receiver( if n > 0 { got_data = true; let data = &buf[..n]; + // Hi-res mic (Phase 3 de-risk): while enabled, count the 0x58 + // uplink audio packets and confirm the stream actually started. + if mic_on.load(Ordering::Relaxed) { + if aap::is_audio_packet(data) { + audio_pkts = audio_pkts.saturating_add(1); + if audio_pkts == 10 { + overlay::show(&dev_name, "Hi-res mic: receiving audio"); + } + } + } else { + audio_pkts = 0; + } if let Some(b) = aap::parse_battery(data) { let mut s = state.lock().unwrap(); // merge — a packet may carry only some components @@ -282,6 +297,10 @@ fn main() { // so a stale handle fails) and publishes the live one here. let driver_cell: Arc>> = Arc::new(Mutex::new(None)); + // Whether the hi-res mic stream is enabled (toggled from the menu, read by + // the receive loop). Phase 3. + let mic_on = Arc::new(AtomicBool::new(false)); + // Start the background AAP session if the AirPods are paired. run_receiver // opens the driver itself and keeps retrying, so this works even if they // aren't connected yet at startup. @@ -289,7 +308,8 @@ fn main() { let st = state.clone(); let name = dev_name.clone(); let cell = driver_cell.clone(); - thread::spawn(move || run_receiver(mac, st, name, cell)); + let mic = mic_on.clone(); + thread::spawn(move || run_receiver(mac, st, name, cell, mic)); } // --- Tray menu --- @@ -304,6 +324,7 @@ fn main() { let m_vol_up = MenuItem::new("Volume +", true, None); let m_vol_down = MenuItem::new("Volume −", true, None); let m_mute = MenuItem::new("Mute / Unmute", true, None); + let m_mic = CheckMenuItem::new("Hi-res microphone (test)", true, false, None); let m_open = MenuItem::new("Open App", true, None); let quit = MenuItem::new("Quit", true, None); @@ -314,6 +335,7 @@ fn main() { let vol_up_id = m_vol_up.id().clone(); let vol_down_id = m_vol_down.id().clone(); let mute_id = m_mute.id().clone(); + let mic_id = m_mic.id().clone(); let open_id = m_open.id().clone(); let quit_id = quit.id().clone(); @@ -332,6 +354,7 @@ fn main() { menu.append(&m_vol_down).unwrap(); menu.append(&m_mute).unwrap(); menu.append(&PredefinedMenuItem::separator()).unwrap(); + menu.append(&m_mic).unwrap(); menu.append(&m_open).unwrap(); menu.append(&quit).unwrap(); @@ -427,6 +450,20 @@ fn main() { } else if ev.id == mute_id { volume::toggle_mute(); refresh(); + } else if ev.id == mic_id { + // Toggle the hi-res mic stream (Phase 3 de-risk): send the + // enable/stop command; the receive loop confirms audio flow. + let on = !mic_on.load(Ordering::Relaxed); + mic_on.store(on, Ordering::Relaxed); + m_mic.set_checked(on); + if let Some(drv) = driver_cell.lock().unwrap().clone() { + let cmd: &[u8] = if on { &aap::START_AUDIO } else { &aap::STOP_AUDIO }; + let _ = drv.send(cmd); + } + overlay::show( + &dev_name, + if on { "Hi-res mic: enabling…" } else { "Hi-res mic: off" }, + ); } else if let Some(mode) = mode_for(&ev.id) { if let Some(drv) = driver_cell.lock().unwrap().clone() { let _ = drv.send(&aap::anc_command(mode)); From bc6b41d5766147c68aa12f7aa430ee0951faba2b Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:26:02 +0100 Subject: [PATCH 19/48] hires-mic: mark Phase 3a done (enable command + 0x58 stream validated) Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index 426819538..a74862cb4 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -85,7 +85,17 @@ the sink. end: `lp-mic-test` (a user-mode tone feeder, `windows-driver/lp-mic-test/`) pushed a 440 Hz sine and it was **recorded and audible** on "Microphone (AudioCodec Device)". The audio-driver de-risk is complete. -- **Phase 3 — next**: replace the tone with the real thing — the AAP command - that enables the AirPods hi-res mic + AAC-ELD decode (FFmpeg) from PR #655, - pushing decoded PCM into `\\.\LibrePodsMic`. +- **Phase 3a — DONE** ✅ (`c843d32`, validated on hardware): the AAP enable + command works. The tray's "Hi-res microphone (test)" toggle sends `START_AUDIO` + (`04 00 04 00 58 …`, from PR #655); the AirPods enter mic mode (A2DP playback + drops to right-only mono, as expected — needs an A2DP reset like #655), and the + receive loop confirmed the **0x58 uplink audio packets flow** ("receiving + audio" card). Constants + `is_audio_packet` in `aap.rs`; protocol in + [[hires-mic-protocol]]. +- **Phase 3b — next (the hard part)**: decode the 0x58 packets' **AAC-ELD** to + PCM and feed `\\.\LibrePodsMic`. Parse AUs (header 22, AU len at `off+4`, + payload `off+5`), decode AAC-ELD (64000/480/mono, ASC `F8 E6 30 00`) → f32 → + i16. **Blocker: the decoder on Windows/mingw** — FFmpeg libavcodec (native + AAC-ELD, LGPL) or libfdk-aac, cross-compiled for `x86_64-pc-windows-gnu` or + linked against prebuilt DLLs. Plus the A2DP reset to restore stereo playback. - Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. From 09477d5ec3e0b0845c5eb3a5ba54536d5f50c723 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:44:13 +0100 Subject: [PATCH 20/48] hires-mic(Phase 3b): decode AAC-ELD and feed the virtual mic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The tray now turns the AirPods' hi-res mic into real audio: enable → decode → virtual mic. Wired end to end. - eld_shim.c + build.rs: a tiny C shim over FFmpeg libavcodec (LGPL, native AAC-ELD) behind a stable ABI (eld_open/decode/close), compiled via cc against vendored FFmpeg headers and linked to the import libs. (libfdk-aac is non-free and won't cross-compile for mingw64, so FFmpeg native like PR #655.) - eld.rs: Rust wrapper; opens the decoder with the AirPods ASC F8 E6 30 00 (AOT 39 ELD, 48 kHz mono), decodes AUs to i16. - micpipe.rs: writes decoded PCM into \\.\LibrePodsMic (IOCTL 0x0022A000). - aap.rs for_each_au: parse the 0x58 packet's AUs (22-byte header, len at off+4). - main.rs: on the "Hi-res microphone" toggle, the receive loop decodes each 0x58 packet's AUs and streams the PCM to the virtual mic. - vendor/ffmpeg: committed headers + import libs; the ~75 MB runtime DLLs are gitignored (fetched, shipped alongside the exe). Builds + runs on hardware (FFmpeg DLLs load). Pending: on-hardware voice test, plus A2DP reset (playback drops to right-only mono while the mic is active) and the 2s stall watchdog. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/Cargo.toml | 3 + .../windows-app/librepods-tray/build.rs | 23 + .../windows-app/librepods-tray/src/aap.rs | 18 + .../windows-app/librepods-tray/src/eld.rs | 66 + .../windows-app/librepods-tray/src/eld_shim.c | 68 + .../windows-app/librepods-tray/src/main.rs | 35 +- .../windows-app/librepods-tray/src/micpipe.rs | 75 + .../librepods-tray/vendor/ffmpeg/.gitignore | 2 + .../vendor/ffmpeg/LICENSE-ffmpeg.txt | 165 + .../librepods-tray/vendor/ffmpeg/README.md | 11 + .../ffmpeg/include/libavcodec/ac3_parser.h | 36 + .../ffmpeg/include/libavcodec/adts_parser.h | 37 + .../ffmpeg/include/libavcodec/avcodec.h | 2961 +++++++++++++++++ .../vendor/ffmpeg/include/libavcodec/avdct.h | 91 + .../vendor/ffmpeg/include/libavcodec/bsf.h | 708 ++++ .../vendor/ffmpeg/include/libavcodec/codec.h | 345 ++ .../ffmpeg/include/libavcodec/codec_desc.h | 142 + .../ffmpeg/include/libavcodec/codec_id.h | 688 ++++ .../ffmpeg/include/libavcodec/codec_par.h | 302 ++ .../ffmpeg/include/libavcodec/d3d11va.h | 109 + .../vendor/ffmpeg/include/libavcodec/defs.h | 362 ++ .../vendor/ffmpeg/include/libavcodec/dirac.h | 135 + .../ffmpeg/include/libavcodec/dv_profile.h | 82 + .../vendor/ffmpeg/include/libavcodec/dxva2.h | 90 + .../vendor/ffmpeg/include/libavcodec/exif.h | 242 ++ .../vendor/ffmpeg/include/libavcodec/jni.h | 67 + .../ffmpeg/include/libavcodec/mediacodec.h | 103 + .../vendor/ffmpeg/include/libavcodec/packet.h | 950 ++++++ .../vendor/ffmpeg/include/libavcodec/qsv.h | 109 + .../ffmpeg/include/libavcodec/smpte_436m.h | 254 ++ .../vendor/ffmpeg/include/libavcodec/vdpau.h | 138 + .../ffmpeg/include/libavcodec/version.h | 45 + .../ffmpeg/include/libavcodec/version_major.h | 45 + .../ffmpeg/include/libavcodec/videotoolbox.h | 85 + .../ffmpeg/include/libavcodec/vorbis_parser.h | 74 + .../vendor/ffmpeg/include/libavutil/adler32.h | 63 + .../vendor/ffmpeg/include/libavutil/aes.h | 69 + .../vendor/ffmpeg/include/libavutil/aes_ctr.h | 99 + .../libavutil/ambient_viewing_environment.h | 72 + .../ffmpeg/include/libavutil/attributes.h | 235 ++ .../ffmpeg/include/libavutil/audio_fifo.h | 187 ++ .../ffmpeg/include/libavutil/avassert.h | 125 + .../ffmpeg/include/libavutil/avconfig.h | 6 + .../ffmpeg/include/libavutil/avstring.h | 428 +++ .../vendor/ffmpeg/include/libavutil/avutil.h | 340 ++ .../vendor/ffmpeg/include/libavutil/base64.h | 72 + .../ffmpeg/include/libavutil/blowfish.h | 82 + .../vendor/ffmpeg/include/libavutil/bprint.h | 254 ++ .../vendor/ffmpeg/include/libavutil/bswap.h | 105 + .../vendor/ffmpeg/include/libavutil/buffer.h | 322 ++ .../ffmpeg/include/libavutil/camellia.h | 70 + .../vendor/ffmpeg/include/libavutil/cast5.h | 80 + .../ffmpeg/include/libavutil/channel_layout.h | 762 +++++ .../vendor/ffmpeg/include/libavutil/common.h | 578 ++++ .../ffmpeg/include/libavutil/container_fifo.h | 130 + .../vendor/ffmpeg/include/libavutil/cpu.h | 152 + .../vendor/ffmpeg/include/libavutil/crc.h | 102 + .../vendor/ffmpeg/include/libavutil/csp.h | 208 ++ .../vendor/ffmpeg/include/libavutil/des.h | 81 + .../ffmpeg/include/libavutil/detection_bbox.h | 108 + .../vendor/ffmpeg/include/libavutil/dict.h | 242 ++ .../vendor/ffmpeg/include/libavutil/display.h | 109 + .../ffmpeg/include/libavutil/dovi_meta.h | 408 +++ .../ffmpeg/include/libavutil/downmix_info.h | 180 + .../include/libavutil/encryption_info.h | 205 ++ .../vendor/ffmpeg/include/libavutil/error.h | 129 + .../vendor/ffmpeg/include/libavutil/eval.h | 140 + .../ffmpeg/include/libavutil/executor.h | 67 + .../ffmpeg/include/libavutil/ffversion.h | 5 + .../vendor/ffmpeg/include/libavutil/fifo.h | 242 ++ .../vendor/ffmpeg/include/libavutil/file.h | 62 + .../include/libavutil/film_grain_params.h | 282 ++ .../vendor/ffmpeg/include/libavutil/frame.h | 1221 +++++++ .../vendor/ffmpeg/include/libavutil/hash.h | 264 ++ .../include/libavutil/hdr_dynamic_metadata.h | 480 +++ .../libavutil/hdr_dynamic_vivid_metadata.h | 292 ++ .../vendor/ffmpeg/include/libavutil/hmac.h | 99 + .../ffmpeg/include/libavutil/hwcontext.h | 601 ++++ .../ffmpeg/include/libavutil/hwcontext_amf.h | 58 + .../ffmpeg/include/libavutil/hwcontext_cuda.h | 146 + .../include/libavutil/hwcontext_d3d11va.h | 192 ++ .../include/libavutil/hwcontext_d3d12va.h | 209 ++ .../ffmpeg/include/libavutil/hwcontext_drm.h | 169 + .../include/libavutil/hwcontext_dxva2.h | 75 + .../include/libavutil/hwcontext_mediacodec.h | 61 + .../ffmpeg/include/libavutil/hwcontext_oh.h | 34 + .../include/libavutil/hwcontext_opencl.h | 100 + .../ffmpeg/include/libavutil/hwcontext_qsv.h | 86 + .../include/libavutil/hwcontext_vaapi.h | 117 + .../include/libavutil/hwcontext_vdpau.h | 44 + .../libavutil/hwcontext_videotoolbox.h | 106 + .../include/libavutil/hwcontext_vulkan.h | 355 ++ .../vendor/ffmpeg/include/libavutil/iamf.h | 697 ++++ .../ffmpeg/include/libavutil/imgutils.h | 377 +++ .../ffmpeg/include/libavutil/intfloat.h | 77 + .../ffmpeg/include/libavutil/intreadwrite.h | 677 ++++ .../vendor/ffmpeg/include/libavutil/lfg.h | 81 + .../vendor/ffmpeg/include/libavutil/log.h | 427 +++ .../vendor/ffmpeg/include/libavutil/lzo.h | 66 + .../vendor/ffmpeg/include/libavutil/macros.h | 80 + .../libavutil/mastering_display_metadata.h | 137 + .../ffmpeg/include/libavutil/mathematics.h | 300 ++ .../vendor/ffmpeg/include/libavutil/md5.h | 89 + .../vendor/ffmpeg/include/libavutil/mem.h | 607 ++++ .../ffmpeg/include/libavutil/motion_vector.h | 57 + .../vendor/ffmpeg/include/libavutil/murmur3.h | 115 + .../vendor/ffmpeg/include/libavutil/opt.h | 1160 +++++++ .../ffmpeg/include/libavutil/parseutils.h | 197 ++ .../vendor/ffmpeg/include/libavutil/pixdesc.h | 450 +++ .../ffmpeg/include/libavutil/pixelutils.h | 51 + .../vendor/ffmpeg/include/libavutil/pixfmt.h | 823 +++++ .../ffmpeg/include/libavutil/random_seed.h | 57 + .../ffmpeg/include/libavutil/rational.h | 225 ++ .../include/libavutil/raw_color_params.h | 147 + .../vendor/ffmpeg/include/libavutil/rc4.h | 69 + .../ffmpeg/include/libavutil/refstruct.h | 297 ++ .../ffmpeg/include/libavutil/replaygain.h | 50 + .../vendor/ffmpeg/include/libavutil/ripemd.h | 83 + .../ffmpeg/include/libavutil/samplefmt.h | 268 ++ .../vendor/ffmpeg/include/libavutil/sha.h | 90 + .../vendor/ffmpeg/include/libavutil/sha512.h | 92 + .../ffmpeg/include/libavutil/spherical.h | 249 ++ .../ffmpeg/include/libavutil/stereo3d.h | 325 ++ .../vendor/ffmpeg/include/libavutil/tdrdi.h | 164 + .../vendor/ffmpeg/include/libavutil/tea.h | 71 + .../ffmpeg/include/libavutil/threadmessage.h | 115 + .../vendor/ffmpeg/include/libavutil/time.h | 56 + .../ffmpeg/include/libavutil/timecode.h | 199 ++ .../ffmpeg/include/libavutil/timestamp.h | 85 + .../vendor/ffmpeg/include/libavutil/tree.h | 137 + .../vendor/ffmpeg/include/libavutil/twofish.h | 70 + .../vendor/ffmpeg/include/libavutil/tx.h | 210 ++ .../vendor/ffmpeg/include/libavutil/uuid.h | 146 + .../vendor/ffmpeg/include/libavutil/version.h | 118 + .../include/libavutil/video_enc_params.h | 171 + .../ffmpeg/include/libavutil/video_hint.h | 107 + .../vendor/ffmpeg/include/libavutil/xtea.h | 94 + .../ffmpeg/include/libswresample/swresample.h | 587 ++++ .../ffmpeg/include/libswresample/version.h | 46 + .../include/libswresample/version_major.h | 31 + 140 files changed, 30999 insertions(+), 4 deletions(-) create mode 100644 crossplatform/windows-app/librepods-tray/build.rs create mode 100644 crossplatform/windows-app/librepods-tray/src/eld.rs create mode 100644 crossplatform/windows-app/librepods-tray/src/eld_shim.c create mode 100644 crossplatform/windows-app/librepods-tray/src/micpipe.rs create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/ac3_parser.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/adts_parser.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/d3d11va.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dirac.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dv_profile.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dxva2.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/jni.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/mediacodec.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/qsv.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/videotoolbox.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vorbis_parser.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/adler32.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes_ctr.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ambient_viewing_environment.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/audio_fifo.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avconfig.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/base64.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/blowfish.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bprint.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/buffer.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/camellia.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cast5.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/crc.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/des.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/detection_bbox.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/display.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/encryption_info.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/error.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/eval.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/executor.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/fifo.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/file.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hash.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hmac.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_drm.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_dxva2.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_mediacodec.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vdpau.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_videotoolbox.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/imgutils.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intfloat.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intreadwrite.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lzo.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/macros.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mastering_display_metadata.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/md5.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mem.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/motion_vector.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/murmur3.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/parseutils.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixelutils.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixfmt.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/random_seed.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/replaygain.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ripemd.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha512.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/stereo3d.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tea.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/threadmessage.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/time.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timecode.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timestamp.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tree.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/twofish.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/uuid.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_enc_params.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/xtea.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h diff --git a/crossplatform/windows-app/librepods-tray/Cargo.toml b/crossplatform/windows-app/librepods-tray/Cargo.toml index a46570bd5..b660c36df 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.toml +++ b/crossplatform/windows-app/librepods-tray/Cargo.toml @@ -33,6 +33,9 @@ windows = { version = "0.58", features = [ "Media_Control", # GlobalSystemMediaTransportControlsSession* (auto-pause) ] } +[build-dependencies] +cc = "1" + [[bin]] name = "librepods-tray" path = "src/main.rs" diff --git a/crossplatform/windows-app/librepods-tray/build.rs b/crossplatform/windows-app/librepods-tray/build.rs new file mode 100644 index 000000000..338ed7f49 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/build.rs @@ -0,0 +1,23 @@ +use std::path::PathBuf; + +fn main() { + // The AAC-ELD decoder (FFmpeg) is only used on Windows. + if std::env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("windows") { + return; + } + let manifest = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + let ff = manifest.join("vendor/ffmpeg"); + + // Compile the tiny C shim against the vendored FFmpeg headers. + cc::Build::new() + .file("src/eld_shim.c") + .include(ff.join("include")) + .compile("eld_shim"); + + // Link the FFmpeg import libs (avcodec pulls avutil + swresample). + println!("cargo:rustc-link-search=native={}", ff.join("lib").display()); + println!("cargo:rustc-link-lib=avcodec"); + println!("cargo:rustc-link-lib=avutil"); + println!("cargo:rustc-link-lib=swresample"); + println!("cargo:rerun-if-changed=src/eld_shim.c"); +} diff --git a/crossplatform/windows-app/librepods-tray/src/aap.rs b/crossplatform/windows-app/librepods-tray/src/aap.rs index 75c9ca126..6b164c608 100644 --- a/crossplatform/windows-app/librepods-tray/src/aap.rs +++ b/crossplatform/windows-app/librepods-tray/src/aap.rs @@ -32,6 +32,24 @@ pub fn is_audio_packet(data: &[u8]) -> bool { && data[7] == 0x00 } +/// 0x58 packet layout (PR #655): a 22-byte header, then one or more access +/// units, each a 5-byte record header (length at byte 4) followed by the AU +/// payload. Calls `f` with each AU's AAC-ELD bytes. +pub fn for_each_au(sdu: &[u8], mut f: impl FnMut(&[u8])) { + const HEADER_LEN: usize = 22; + let mut off = HEADER_LEN; + while off + 5 <= sdu.len() { + let au_len = sdu[off + 4] as usize; + let start = off + 5; + let end = start + au_len; + if au_len == 0 || end > sdu.len() { + break; + } + f(&sdu[start..end]); + off = end; + } +} + /// Listening-mode (ANC) control command. value = mode (1 off, 2 anc, 3 transparency, 4 adaptive). pub fn anc_command(mode: u8) -> [u8; 11] { [0x04, 0x00, 0x04, 0x00, 0x09, 0x00, 0x0D, mode, 0x00, 0x00, 0x00] diff --git a/crossplatform/windows-app/librepods-tray/src/eld.rs b/crossplatform/windows-app/librepods-tray/src/eld.rs new file mode 100644 index 000000000..6abe7df36 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/eld.rs @@ -0,0 +1,66 @@ +//! AAC-ELD decoder — thin Rust wrapper over the FFmpeg C shim (`eld_shim.c`). +//! Decodes the AirPods' hi-res mic frames (AAC-ELD, mono 48 kHz) to i16 PCM. + +use std::ffi::c_void; +use std::os::raw::c_int; + +extern "C" { + fn eld_open(asc: *const u8, asc_len: c_int, sample_rate: c_int) -> *mut c_void; + fn eld_decode( + h: *mut c_void, + au: *const u8, + au_len: c_int, + out: *mut i16, + out_cap: c_int, + ) -> c_int; + fn eld_close(h: *mut c_void); +} + +/// AudioSpecificConfig for the AirPods hi-res mic: AOT 39 (ER AAC ELD), 48 kHz, +/// mono. From LibrePods PR #655. +const ASC: [u8; 4] = [0xF8, 0xE6, 0x30, 0x00]; +const SAMPLE_RATE: c_int = 48_000; + +pub struct Decoder { + h: *mut c_void, + out: Vec, +} + +// The handle is only ever used from the receive thread. +unsafe impl Send for Decoder {} + +impl Decoder { + pub fn new() -> Option { + let h = unsafe { eld_open(ASC.as_ptr(), ASC.len() as c_int, SAMPLE_RATE) }; + if h.is_null() { + None + } else { + Some(Decoder { h, out: vec![0i16; 8192] }) + } + } + + /// Decode one access unit into i16 mono samples (48 kHz). May return empty + /// (the decoder buffers a frame of latency before the first output). + pub fn decode(&mut self, au: &[u8]) -> &[i16] { + let n = unsafe { + eld_decode( + self.h, + au.as_ptr(), + au.len() as c_int, + self.out.as_mut_ptr(), + self.out.len() as c_int, + ) + }; + if n <= 0 { + &[] + } else { + &self.out[..n as usize] + } + } +} + +impl Drop for Decoder { + fn drop(&mut self) { + unsafe { eld_close(self.h) }; + } +} diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c new file mode 100644 index 000000000..a0bfd878c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -0,0 +1,68 @@ +// Minimal AAC-ELD decoder shim over FFmpeg libavcodec (LGPL). Exposes a small, +// version-stable C ABI so the Rust side never touches AVCodecContext internals. +#include +#include +#include +#include +#include +#include + +typedef struct { + AVCodecContext *ctx; + AVPacket *pkt; + AVFrame *frame; +} EldDec; + +// Open an AAC-ELD decoder configured by `asc` (AudioSpecificConfig). Returns an +// opaque handle or NULL. +void *eld_open(const uint8_t *asc, int asc_len, int sample_rate) { + const AVCodec *c = avcodec_find_decoder_by_name("aac"); + if (!c) return NULL; + AVCodecContext *ctx = avcodec_alloc_context3(c); + if (!ctx) return NULL; + ctx->extradata = (uint8_t *)av_malloc(asc_len + AV_INPUT_BUFFER_PADDING_SIZE); + if (!ctx->extradata) { avcodec_free_context(&ctx); return NULL; } + memset(ctx->extradata, 0, asc_len + AV_INPUT_BUFFER_PADDING_SIZE); + memcpy(ctx->extradata, asc, asc_len); + ctx->extradata_size = asc_len; + ctx->sample_rate = sample_rate; // channels/rate also come from the ASC + if (avcodec_open2(ctx, c, NULL) < 0) { avcodec_free_context(&ctx); return NULL; } + EldDec *d = (EldDec *)malloc(sizeof(EldDec)); + if (!d) { avcodec_free_context(&ctx); return NULL; } + d->ctx = ctx; + d->pkt = av_packet_alloc(); + d->frame = av_frame_alloc(); + return d; +} + +// Decode one access unit into interleaved mono i16 `out` (capacity `out_cap` +// samples). Returns the number of samples written, or -1 on error. +int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int out_cap) { + EldDec *d = (EldDec *)handle; + if (!d) return -1; + d->pkt->data = (uint8_t *)au; + d->pkt->size = au_len; + if (avcodec_send_packet(d->ctx, d->pkt) < 0) return -1; + int total = 0; + while (avcodec_receive_frame(d->ctx, d->frame) == 0) { + int n = d->frame->nb_samples; + const float *p = (const float *)d->frame->data[0]; // FLTP mono -> plane 0 + for (int i = 0; i < n && total < out_cap; i++) { + float s = p[i]; + if (s > 1.0f) s = 1.0f; + if (s < -1.0f) s = -1.0f; + out[total++] = (int16_t)(s * 32767.0f); + } + av_frame_unref(d->frame); + } + return total; +} + +void eld_close(void *handle) { + EldDec *d = (EldDec *)handle; + if (!d) return; + av_frame_free(&d->frame); + av_packet_free(&d->pkt); + avcodec_free_context(&d->ctx); + free(d); +} diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index d933f4c74..430eec021 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -12,7 +12,9 @@ mod aap; mod bt; mod driver; +mod eld; mod media; +mod micpipe; mod overlay; mod theme; mod volume; @@ -132,6 +134,11 @@ fn run_receiver( ) { let mut buf = [0u8; 2048]; let mut audio_pkts = 0u32; + // Hi-res mic pipeline (Phase 3b): created on first audio packet, torn down + // when the mic is disabled. The decoder holds the FFmpeg AAC-ELD context; + // the pipe writes decoded PCM into \\.\LibrePodsMic. + let mut decoder: Option = None; + let mut pipe: Option = None; media::init(); // COM (MTA) for the SMTC ear-detection auto-pause on this thread let mut last_anc = 0u8; let mut last_case_present: Option = None; @@ -185,12 +192,32 @@ fn run_receiver( // uplink audio packets and confirm the stream actually started. if mic_on.load(Ordering::Relaxed) { if aap::is_audio_packet(data) { - audio_pkts = audio_pkts.saturating_add(1); - if audio_pkts == 10 { - overlay::show(&dev_name, "Hi-res mic: receiving audio"); + // Lazily bring up the decoder + mic pipe on the first + // audio packet, and report the outcome once. + if decoder.is_none() { + decoder = eld::Decoder::new(); + pipe = micpipe::MicPipe::open(); + let msg = match (decoder.is_some(), pipe.is_some()) { + (true, true) => "Hi-res mic: streaming to the mic", + (false, _) => "Hi-res mic: decoder failed (FFmpeg)", + (_, false) => "Hi-res mic: virtual mic not found", + }; + overlay::show(&dev_name, msg); + } + if let (Some(dec), Some(pp)) = (decoder.as_mut(), pipe.as_ref()) { + aap::for_each_au(data, |au| { + let pcm = dec.decode(au); + if !pcm.is_empty() { + pp.write(pcm); + } + }); } + audio_pkts = audio_pkts.saturating_add(1); } - } else { + } else if decoder.is_some() || pipe.is_some() { + // Mic disabled: tear the pipeline down. + decoder = None; + pipe = None; audio_pkts = 0; } if let Some(b) = aap::parse_battery(data) { diff --git a/crossplatform/windows-app/librepods-tray/src/micpipe.rs b/crossplatform/windows-app/librepods-tray/src/micpipe.rs new file mode 100644 index 000000000..15583c16c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/micpipe.rs @@ -0,0 +1,75 @@ +//! Writer for the LibrePodsMic virtual microphone: pushes decoded PCM into the +//! driver's ring buffer over the control device `\\.\LibrePodsMic`. + +use std::ffi::c_void; +use std::ptr; + +use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE}; +use windows_sys::Win32::Storage::FileSystem::{ + CreateFileW, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, +}; +use windows_sys::Win32::System::IO::DeviceIoControl; + +const GENERIC_WRITE: u32 = 0x4000_0000; +// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) +const IOCTL_LIBREPODS_MIC_WRITE_PCM: u32 = 0x0022_A000; + +pub struct MicPipe { + handle: HANDLE, +} + +unsafe impl Send for MicPipe {} + +impl MicPipe { + /// Open the virtual-mic control device. None if the LibrePodsMic driver + /// isn't installed (or another writer holds the exclusive handle). + pub fn open() -> Option { + let path: Vec = r"\\.\LibrePodsMic" + .encode_utf16() + .chain(std::iter::once(0)) + .collect(); + let handle = unsafe { + CreateFileW( + path.as_ptr(), + GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, + ptr::null(), + OPEN_EXISTING, + 0, + ptr::null_mut(), + ) + }; + if handle == INVALID_HANDLE_VALUE || handle.is_null() { + None + } else { + Some(MicPipe { handle }) + } + } + + /// Push mono 16-bit PCM samples into the mic ring. + pub fn write(&self, samples: &[i16]) { + if samples.is_empty() { + return; + } + let bytes = std::mem::size_of_val(samples); + let mut returned = 0u32; + unsafe { + DeviceIoControl( + self.handle, + IOCTL_LIBREPODS_MIC_WRITE_PCM, + samples.as_ptr() as *const c_void, + bytes as u32, + ptr::null_mut(), + 0, + &mut returned, + ptr::null_mut(), + ); + } + } +} + +impl Drop for MicPipe { + fn drop(&mut self) { + unsafe { CloseHandle(self.handle) }; + } +} diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore new file mode 100644 index 000000000..4b7734f67 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore @@ -0,0 +1,2 @@ +# Runtime DLLs (~75 MB) — fetched, not committed. See README / fetch note. +bin/*.dll diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt new file mode 100644 index 000000000..65c5ca88a --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md new file mode 100644 index 000000000..8c2a6794e --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md @@ -0,0 +1,11 @@ +# Vendored FFmpeg (LGPL) — AAC-ELD decoder for the hi-res mic + +From BtbN's **`ffmpeg-master-latest-win64-lgpl-shared`** +(https://github.com/BtbN/FFmpeg-Builds/releases/latest) — LGPLv3, no GPL/nonfree, +`--disable-libfdk-aac`. See `LICENSE-ffmpeg.txt`. + +Committed (needed to *build*): `include/` (libavcodec, libavutil, libswresample) +and `lib/*.dll.a` (mingw import libs). The `bin/*.dll` runtime libraries +(`avcodec-63.dll`, `avutil-61.dll`, `swresample-7.dll`, ~75 MB) are **not** in git +— download the same BtbN build and copy them into `bin/`, and ship them next to +`librepods-tray.exe`. diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/ac3_parser.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/ac3_parser.h new file mode 100644 index 000000000..ff8cc4cf0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/ac3_parser.h @@ -0,0 +1,36 @@ +/* + * AC-3 parser prototypes + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2003 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 AVCODEC_AC3_PARSER_H +#define AVCODEC_AC3_PARSER_H + +#include +#include + +/** + * Extract the bitstream ID and the frame size from AC-3 data. + */ +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size); + + +#endif /* AVCODEC_AC3_PARSER_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/adts_parser.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/adts_parser.h new file mode 100644 index 000000000..f85becd13 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/adts_parser.h @@ -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 + */ + +#ifndef AVCODEC_ADTS_PARSER_H +#define AVCODEC_ADTS_PARSER_H + +#include +#include + +#define AV_AAC_ADTS_HEADER_SIZE 7 + +/** + * Extract the number of samples and frames from AAC data. + * @param[in] buf pointer to AAC data buffer + * @param[out] samples Pointer to where number of samples is written + * @param[out] frames Pointer to where number of frames is written + * @return Returns 0 on success, error code on failure. + */ +int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, + uint8_t *frames); + +#endif /* AVCODEC_ADTS_PARSER_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h new file mode 100644 index 000000000..6bce0d388 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h @@ -0,0 +1,2961 @@ +/* + * copyright (c) 2001 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 AVCODEC_AVCODEC_H +#define AVCODEC_AVCODEC_H + +/** + * @file + * @ingroup libavc + * Libavcodec external API header + */ + +#include "libavutil/samplefmt.h" +#include "libavutil/attributes.h" +#include "libavutil/avutil.h" +#include "libavutil/buffer.h" +#include "libavutil/channel_layout.h" +#include "libavutil/dict.h" +#include "libavutil/frame.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +#include "codec.h" +#include "codec_id.h" +#include "defs.h" +#include "packet.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" + +#include "codec_desc.h" +#include "codec_par.h" +#endif + +struct AVCodecParameters; + +/** + * @defgroup libavc libavcodec + * Encoding/Decoding Library + * + * @{ + * + * @defgroup lavc_decoding Decoding + * @{ + * @} + * + * @defgroup lavc_encoding Encoding + * @{ + * @} + * + * @defgroup lavc_codec Codecs + * @{ + * @defgroup lavc_codec_native Native Codecs + * @{ + * @} + * @defgroup lavc_codec_wrappers External library wrappers + * @{ + * @} + * @defgroup lavc_codec_hwaccel Hardware Accelerators bridge + * @{ + * @} + * @} + * @defgroup lavc_internal Internal + * @{ + * @} + * @} + */ + +/** + * @ingroup libavc + * @defgroup lavc_encdec send/receive encoding and decoding API overview + * @{ + * + * The avcodec_send_packet()/avcodec_receive_frame()/avcodec_send_frame()/ + * avcodec_receive_packet() functions provide an encode/decode API, which + * decouples input and output. + * + * The API is very similar for encoding/decoding and audio/video, and works as + * follows: + * - Set up and open the AVCodecContext as usual. + * - Send valid input: + * - For decoding, call avcodec_send_packet() to give the decoder raw + * compressed data in an AVPacket. + * - For encoding, call avcodec_send_frame() to give the encoder an AVFrame + * containing uncompressed audio or video. + * + * In both cases, it is recommended that AVPackets and AVFrames are + * refcounted, or libavcodec might have to copy the input data. (libavformat + * always returns refcounted AVPackets, and av_frame_get_buffer() allocates + * refcounted AVFrames.) + * - Receive output in a loop. Periodically call one of the avcodec_receive_*() + * functions and process their output: + * - For decoding, call avcodec_receive_frame(). On success, it will return + * an AVFrame containing uncompressed audio or video data. + * - For encoding, call avcodec_receive_packet(). On success, it will return + * an AVPacket with a compressed frame. + * + * Repeat this call until it returns AVERROR(EAGAIN) or an error. The + * AVERROR(EAGAIN) return value means that new input data is required to + * return new output. In this case, continue with sending input. For each + * input frame/packet, the codec will typically return 1 output frame/packet, + * but it can also be 0 or more than 1. + * + * At the beginning of decoding or encoding, the codec might accept multiple + * input frames/packets without returning a frame, until its internal buffers + * are filled. This situation is handled transparently if you follow the steps + * outlined above. + * + * In theory, sending input can result in EAGAIN - this should happen only if + * not all output was received. You can use this to structure alternative decode + * or encode loops other than the one suggested above. For example, you could + * try sending new input on each iteration, and try to receive output if that + * returns EAGAIN. + * + * End of stream situations. These require "flushing" (aka draining) the codec, + * as the codec might buffer multiple frames or packets internally for + * performance or out of necessity (consider B-frames). + * This is handled as follows: + * - Instead of valid input, send NULL to the avcodec_send_packet() (decoding) + * or avcodec_send_frame() (encoding) functions. This will enter draining + * mode. + * - Call avcodec_receive_frame() (decoding) or avcodec_receive_packet() + * (encoding) in a loop until AVERROR_EOF is returned. The functions will + * not return AVERROR(EAGAIN), unless you forgot to enter draining mode. + * - Before decoding can be resumed again, the codec has to be reset with + * avcodec_flush_buffers(). + * + * Using the API as outlined above is highly recommended. But it is also + * possible to call functions outside of this rigid schema. For example, you can + * call avcodec_send_packet() repeatedly without calling + * avcodec_receive_frame(). In this case, avcodec_send_packet() will succeed + * until the codec's internal buffer has been filled up (which is typically of + * size 1 per output frame, after initial input), and then reject input with + * AVERROR(EAGAIN). Once it starts rejecting input, you have no choice but to + * read at least some output. + * + * Not all codecs will follow a rigid and predictable dataflow; the only + * guarantee is that an AVERROR(EAGAIN) return value on a send/receive call on + * one end implies that a receive/send call on the other end will succeed, or + * at least will not fail with AVERROR(EAGAIN). In general, no codec will + * permit unlimited buffering of input or output. + * + * A codec is not allowed to return AVERROR(EAGAIN) for both sending and receiving. This + * would be an invalid state, which could put the codec user into an endless + * loop. The API has no concept of time either: it cannot happen that trying to + * do avcodec_send_packet() results in AVERROR(EAGAIN), but a repeated call 1 second + * later accepts the packet (with no other receive/flush API calls involved). + * The API is a strict state machine, and the passage of time is not supposed + * to influence it. Some timing-dependent behavior might still be deemed + * acceptable in certain cases. But it must never result in both send/receive + * returning EAGAIN at the same time at any point. It must also absolutely be + * avoided that the current state is "unstable" and can "flip-flop" between + * the send/receive APIs allowing progress. For example, it's not allowed that + * the codec randomly decides that it actually wants to consume a packet now + * instead of returning a frame, after it just returned AVERROR(EAGAIN) on an + * avcodec_send_packet() call. + * @} + */ + +/** + * @defgroup lavc_core Core functions/structures. + * @ingroup libavc + * + * Basic definitions, functions for querying libavcodec capabilities, + * allocating core structures, etc. + * @{ + */ + +/** + * @ingroup lavc_encoding + */ +typedef struct RcOverride{ + int start_frame; + int end_frame; + int qscale; // If this is 0 then quality_factor will be used instead. + float quality_factor; +} RcOverride; + +/* encoding support + These flags can be passed in AVCodecContext.flags before initialization. + Note: Not everything is supported yet. +*/ + +/** + * Allow decoders to produce frames with data planes that are not aligned + * to CPU requirements (e.g. due to cropping). + */ +#define AV_CODEC_FLAG_UNALIGNED (1 << 0) +/** + * Use fixed qscale. + */ +#define AV_CODEC_FLAG_QSCALE (1 << 1) +/** + * 4 MV per MB allowed / advanced prediction for H.263. + */ +#define AV_CODEC_FLAG_4MV (1 << 2) +/** + * Output even those frames that might be corrupted. + */ +#define AV_CODEC_FLAG_OUTPUT_CORRUPT (1 << 3) +/** + * Use qpel MC. + */ +#define AV_CODEC_FLAG_QPEL (1 << 4) +/** + * Request the encoder to output reconstructed frames, i.e.\ frames that would + * be produced by decoding the encoded bitstream. These frames may be retrieved + * by calling avcodec_receive_frame() immediately after a successful call to + * avcodec_receive_packet(). + * + * Should only be used with encoders flagged with the + * @ref AV_CODEC_CAP_ENCODER_RECON_FRAME capability. + * + * @note + * Each reconstructed frame returned by the encoder corresponds to the last + * encoded packet, i.e. the frames are returned in coded order rather than + * presentation order. + * + * @note + * Frame parameters (like pixel format or dimensions) do not have to match the + * AVCodecContext values. Make sure to use the values from the returned frame. + */ +#define AV_CODEC_FLAG_RECON_FRAME (1 << 6) +/** + * @par decoding + * Request the decoder to propagate each packet's AVPacket.opaque and + * AVPacket.opaque_ref to its corresponding output AVFrame. + * + * @par encoding: + * Request the encoder to propagate each frame's AVFrame.opaque and + * AVFrame.opaque_ref values to its corresponding output AVPacket. + * + * @par + * May only be set on encoders that have the + * @ref AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE capability flag. + * + * @note + * While in typical cases one input frame produces exactly one output packet + * (perhaps after a delay), in general the mapping of frames to packets is + * M-to-N, so + * - Any number of input frames may be associated with any given output packet. + * This includes zero - e.g. some encoders may output packets that carry only + * metadata about the whole stream. + * - A given input frame may be associated with any number of output packets. + * Again this includes zero - e.g. some encoders may drop frames under certain + * conditions. + * . + * This implies that when using this flag, the caller must NOT assume that + * - a given input frame's opaques will necessarily appear on some output packet; + * - every output packet will have some non-NULL opaque value. + * . + * When an output packet contains multiple frames, the opaque values will be + * taken from the first of those. + * + * @note + * The converse holds for decoders, with frames and packets switched. + */ +#define AV_CODEC_FLAG_COPY_OPAQUE (1 << 7) +/** + * Signal to the encoder that the values of AVFrame.duration are valid and + * should be used (typically for transferring them to output packets). + * + * If this flag is not set, frame durations are ignored. + */ +#define AV_CODEC_FLAG_FRAME_DURATION (1 << 8) +/** + * Use internal 2pass ratecontrol in first pass mode. + */ +#define AV_CODEC_FLAG_PASS1 (1 << 9) +/** + * Use internal 2pass ratecontrol in second pass mode. + */ +#define AV_CODEC_FLAG_PASS2 (1 << 10) +/** + * loop filter. + */ +#define AV_CODEC_FLAG_LOOP_FILTER (1 << 11) +/** + * Only decode/encode grayscale. + */ +#define AV_CODEC_FLAG_GRAY (1 << 13) +/** + * error[?] variables will be set during encoding. + */ +#define AV_CODEC_FLAG_PSNR (1 << 15) +/** + * Use interlaced DCT. + */ +#define AV_CODEC_FLAG_INTERLACED_DCT (1 << 18) +/** + * Force low delay. + */ +#define AV_CODEC_FLAG_LOW_DELAY (1 << 19) +/** + * Place global headers in extradata instead of every keyframe. + */ +#define AV_CODEC_FLAG_GLOBAL_HEADER (1 << 22) +/** + * Use only bitexact stuff (except (I)DCT). + */ +#define AV_CODEC_FLAG_BITEXACT (1 << 23) +/* Fx : Flag for H.263+ extra options */ +/** + * H.263 advanced intra coding / MPEG-4 AC prediction + */ +#define AV_CODEC_FLAG_AC_PRED (1 << 24) +/** + * interlaced motion estimation + */ +#define AV_CODEC_FLAG_INTERLACED_ME (1 << 29) +#define AV_CODEC_FLAG_CLOSED_GOP (1U << 31) + +/** + * Allow non spec compliant speedup tricks. + */ +#define AV_CODEC_FLAG2_FAST (1 << 0) +/** + * Skip bitstream encoding. + */ +#define AV_CODEC_FLAG2_NO_OUTPUT (1 << 2) +/** + * Place global headers at every keyframe instead of in extradata. + */ +#define AV_CODEC_FLAG2_LOCAL_HEADER (1 << 3) + +/** + * Input bitstream might be truncated at a packet boundaries + * instead of only at frame boundaries. + */ +#define AV_CODEC_FLAG2_CHUNKS (1 << 15) +/** + * Discard cropping information from SPS. + */ +#define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) +/** + * Force audio encoders to use a fixed frame size. + */ +#define AV_CODEC_FLAG2_FIXED_FRAME_SIZE (1 << 17) + +/** + * Show all frames before the first keyframe + */ +#define AV_CODEC_FLAG2_SHOW_ALL (1 << 22) +/** + * Export motion vectors through frame side data + */ +#define AV_CODEC_FLAG2_EXPORT_MVS (1 << 28) +/** + * Do not skip samples and export skip information as frame side data + */ +#define AV_CODEC_FLAG2_SKIP_MANUAL (1 << 29) +/** + * Do not reset ASS ReadOrder field on flush (subtitles decoding) + */ +#define AV_CODEC_FLAG2_RO_FLUSH_NOOP (1 << 30) +/** + * Generate/parse ICC profiles on encode/decode, as appropriate for the type of + * file. No effect on codecs which cannot contain embedded ICC profiles, or + * when compiled without support for lcms2. + */ +#define AV_CODEC_FLAG2_ICC_PROFILES (1U << 31) + +/* Exported side data. + These flags can be passed in AVCodecContext.export_side_data before initialization. +*/ +/** + * Export motion vectors through frame side data + */ +#define AV_CODEC_EXPORT_DATA_MVS (1 << 0) +/** + * Export encoder Producer Reference Time through packet side data + */ +#define AV_CODEC_EXPORT_DATA_PRFT (1 << 1) +/** + * Decoding only. + * Export the AVVideoEncParams structure through frame side data. + */ +#define AV_CODEC_EXPORT_DATA_VIDEO_ENC_PARAMS (1 << 2) +/** + * Decoding only. + * Do not apply film grain, export it instead. + */ +#define AV_CODEC_EXPORT_DATA_FILM_GRAIN (1 << 3) + +/** + * Decoding only. + * Do not apply picture enhancement layers, export them instead. + */ +#define AV_CODEC_EXPORT_DATA_ENHANCEMENTS (1 << 4) + +/** + * The decoder will keep a reference to the frame and may reuse it later. + */ +#define AV_GET_BUFFER_FLAG_REF (1 << 0) + +/** + * The encoder will keep a reference to the packet and may reuse it later. + */ +#define AV_GET_ENCODE_BUFFER_FLAG_REF (1 << 0) + +/** + * The decoder will bypass frame threading and return the next frame as soon as + * possible. Note that this may deliver frames earlier than the advertised + * `AVCodecContext.delay`. No effect when frame threading is disabled, or on + * encoding. + */ +#define AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS (1 << 0) + +/** + * 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. + * You can use AVOptions (av_opt* / av_set/get*()) to access these fields from user + * applications. + * The name string for AVOptions options matches the associated command line + * parameter name and can be found in libavcodec/options_table.h + * The AVOption/command line parameter names differ in some cases from the C + * structure field names for historic reasons or brevity. + * sizeof(AVCodecContext) must not be used outside libav*. + */ +typedef struct AVCodecContext { + /** + * information on struct for av_log + * - set by avcodec_alloc_context3 + */ + const AVClass *av_class; + int log_level_offset; + + enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ + const struct AVCodec *codec; + enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ + + /** + * fourcc (LSB first, so "ABCD" -> ('D'<<24) + ('C'<<16) + ('B'<<8) + 'A'). + * This is used to work around some encoder bugs. + * A demuxer should set this to what is stored in the field used to identify the codec. + * If there are multiple such fields in a container then the demuxer should choose the one + * which maximizes the information about the used codec. + * If the codec tag field in a container is larger than 32 bits then the demuxer should + * remap the longer ID to 32 bits with a table or other structure. Alternatively a new + * extra_codec_tag + size could be added but for this a clear advantage must be demonstrated + * first. + * - encoding: Set by user, if not then the default based on codec_id will be used. + * - decoding: Set by user, will be converted to uppercase by libavcodec during init. + */ + unsigned int codec_tag; + + void *priv_data; + + /** + * Private context used for internal data. + * + * Unlike priv_data, this is not codec-specific. It is used in general + * libavcodec functions. + */ + struct AVCodecInternal *internal; + + /** + * Private data of the user, can be used to carry app specific stuff. + * - encoding: Set by user. + * - decoding: Set by user. + */ + void *opaque; + + /** + * the average bitrate + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: Set by user, may be overwritten by libavcodec + * if this info is available in the stream + */ + int64_t bit_rate; + + /** + * AV_CODEC_FLAG_*. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags; + + /** + * AV_CODEC_FLAG2_* + * - encoding: Set by user. + * - decoding: Set by user. + */ + int flags2; + + /** + * Out-of-band global headers that may be used by some codecs. + * + * - decoding: Should be set by the caller when available (typically from a + * demuxer) before opening the decoder; some decoders require this to be + * set and will fail to initialize otherwise. + * + * The array must be allocated with the av_malloc() family of functions; + * allocated size must be at least AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than extradata_size. + * + * - encoding: May be set by the encoder in avcodec_open2() (possibly + * depending on whether the AV_CODEC_FLAG_GLOBAL_HEADER flag is set). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). + */ + uint8_t *extradata; + int extradata_size; + + /** + * This is the fundamental unit of time (in seconds) in terms + * of which frame timestamps are represented. For fixed-fps content, + * timebase should be 1/framerate and timestamp increments should be + * identically 1. + * This often, but not always is the inverse of the frame rate or field rate + * for video. 1/time_base is not the average frame rate if the frame rate is not + * constant. + * + * Like containers, elementary streams also can store timestamps, 1/time_base + * is the unit in which these timestamps are specified. + * As example of such codec time base see ISO/IEC 14496-2:2001(E) + * vop_time_increment_resolution and fixed_vop_rate + * (fixed_vop_rate == 0 implies that it is different from the framerate) + * + * - encoding: MUST be set by user. + * - decoding: unused. + */ + AVRational time_base; + + /** + * Timebase in which pkt_dts/pts and AVPacket.dts/pts are expressed. + * - encoding: unused. + * - decoding: set by user. + */ + AVRational pkt_timebase; + + /** + * - decoding: For codecs that store a framerate value in the compressed + * bitstream, the decoder may export it here. { 0, 1} when + * unknown. + * - encoding: May be used to signal the framerate of CFR content to an + * encoder. + */ + AVRational framerate; + + /** + * Codec delay. + * + * Encoding: Number of frames delay there will be from the encoder input to + * the decoder output. (we assume the decoder matches the spec) + * Decoding: Number of frames delay in addition to what a standard decoder + * as specified in the spec would produce. + * + * Video: + * Number of frames the decoded output will be delayed relative to the + * encoded input. + * + * Audio: + * For encoding, this field is unused (see initial_padding). + * + * For decoding, this is the number of samples the decoder needs to + * output before the decoder's output is valid. When seeking, you should + * start decoding this many samples prior to your desired seek point. + * + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int delay; + + + /* video only */ + /** + * picture width / height. + * + * @note Those fields may not match the values of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: MUST be set by user. + * - decoding: May be set by the user before opening the decoder if known e.g. + * from the container. Some decoders will require the dimensions + * to be set by the caller. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int width, height; + + /** + * Bitstream width / height, may be different from width/height e.g. when + * the decoded frame is cropped before being output or lowres is enabled. + * + * @note Those field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: unused + * - decoding: May be set by the user before opening the decoder if known + * e.g. from the container. During decoding, the decoder may + * overwrite those values as required while parsing the data. + */ + int coded_width, coded_height; + + /** + * sample aspect ratio (0 if unknown) + * That is the width of a pixel divided by the height of the pixel. + * Numerator and denominator must be relatively prime and smaller than 256 for some video standards. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + AVRational sample_aspect_ratio; + + /** + * Pixel format, see AV_PIX_FMT_xxx. + * May be set by the demuxer if known from headers. + * May be overridden by the decoder if it knows better. + * + * @note This field may not match the value of the last + * AVFrame output by avcodec_receive_frame() due frame + * reordering. + * + * - encoding: Set by user. + * - decoding: Set by user if known, overridden by libavcodec while + * parsing the data. + */ + enum AVPixelFormat pix_fmt; + + /** + * Nominal unaccelerated pixel format, see AV_PIX_FMT_xxx. + * - encoding: unused. + * - decoding: Set by libavcodec before calling get_format() + */ + enum AVPixelFormat sw_pix_fmt; + + /** + * Chromaticity coordinates of the source primaries. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorPrimaries color_primaries; + + /** + * Color Transfer Characteristic. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorTransferCharacteristic color_trc; + + /** + * YUV colorspace type. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVColorSpace colorspace; + + /** + * MPEG vs JPEG YUV range. + * - encoding: Set by user to override the default output color range value, + * If not specified, libavcodec sets the color range depending on the + * output format. + * - decoding: Set by libavcodec, can be set by the user to propagate the + * color range to components reading from the decoder context. + */ + enum AVColorRange color_range; + + /** + * This defines the location of chroma samples. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVChromaLocation chroma_sample_location; + + /** Field order + * - encoding: set by libavcodec + * - decoding: Set by user. + */ + enum AVFieldOrder field_order; + + /** + * number of reference frames + * - encoding: Set by user. + * - decoding: Set by lavc. + */ + int refs; + + /** + * Size of the frame reordering buffer in the decoder. + * For MPEG-2 it is 1 IPB or 0 low delay IP. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int has_b_frames; + + /** + * slice flags + * - encoding: unused + * - decoding: Set by user. + */ + int slice_flags; +#define SLICE_FLAG_CODED_ORDER 0x0001 ///< draw_horiz_band() is called in coded order instead of display +#define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG-2 field pics) +#define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) + + /** + * If non NULL, 'draw_horiz_band' is called by the libavcodec + * decoder to draw a horizontal band. It improves cache usage. Not + * all codecs can do that. You must check the codec capabilities + * beforehand. + * When multithreading is used, it may be called from multiple threads + * at the same time; threads might draw different parts of the same AVFrame, + * or multiple AVFrames, and there is no guarantee that slices will be drawn + * in order. + * The function is also used by hardware acceleration APIs. + * It is called at least once during frame decoding to pass + * the data needed for hardware render. + * In that mode instead of pixel data, AVFrame points to + * a structure specific to the acceleration API. The application + * reads the structure and can change some fields to indicate progress + * or mark state. + * - encoding: unused + * - decoding: Set by user. + * @param height the height of the slice + * @param y the y position of the slice + * @param type 1->top field, 2->bottom field, 3->frame + * @param offset offset into the AVFrame.data from which the slice should be read + */ + void (*draw_horiz_band)(struct AVCodecContext *s, + const AVFrame *src, int offset[AV_NUM_DATA_POINTERS], + int y, int type, int height); + + /** + * Callback to negotiate the pixel format. Decoding only, may be set by the + * caller before avcodec_open2(). + * + * Called by some decoders to select the pixel format that will be used for + * the output frames. This is mainly used to set up hardware acceleration, + * then the provided format list contains the corresponding hwaccel pixel + * formats alongside the "software" one. The software pixel format may also + * be retrieved from \ref sw_pix_fmt. + * + * This callback will be called when the coded frame properties (such as + * resolution, pixel format, etc.) change and more than one output format is + * supported for those new properties. If a hardware pixel format is chosen + * and initialization for it fails, the callback may be called again + * immediately. + * + * This callback may be called from different threads if the decoder is + * multi-threaded, but not from more than one thread simultaneously. + * + * @param fmt list of formats which may be used in the current + * configuration, terminated by AV_PIX_FMT_NONE. + * @warning Behavior is undefined if the callback returns a value other + * than one of the formats in fmt or AV_PIX_FMT_NONE. + * @return the chosen format or AV_PIX_FMT_NONE + */ + enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + + /** + * maximum number of B-frames between non-B-frames + * Note: The output will be delayed by max_b_frames+1 relative to the input. + * - encoding: Set by user. + * - decoding: unused + */ + int max_b_frames; + + /** + * qscale factor between IP and B-frames + * If > 0 then the last P-frame quantizer will be used (q= lastp_q*factor+offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_factor; + + /** + * qscale offset between IP and B-frames + * - encoding: Set by user. + * - decoding: unused + */ + float b_quant_offset; + + /** + * qscale factor between P- and I-frames + * If > 0 then the last P-frame quantizer will be used (q = lastp_q * factor + offset). + * If < 0 then normal ratecontrol will be done (q= -normal_q*factor+offset). + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_factor; + + /** + * qscale offset between P and I-frames + * - encoding: Set by user. + * - decoding: unused + */ + float i_quant_offset; + + /** + * luminance masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float lumi_masking; + + /** + * temporary complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float temporal_cplx_masking; + + /** + * spatial complexity masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float spatial_cplx_masking; + + /** + * p block masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float p_masking; + + /** + * darkness masking (0-> disabled) + * - encoding: Set by user. + * - decoding: unused + */ + float dark_masking; + + /** + * noise vs. sse weight for the nsse comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int nsse_weight; + + /** + * motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_cmp; + /** + * subpixel motion estimation comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_sub_cmp; + /** + * macroblock comparison function (not supported yet) + * - encoding: Set by user. + * - decoding: unused + */ + int mb_cmp; + /** + * interlaced DCT comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int ildct_cmp; +#define FF_CMP_SAD 0 +#define FF_CMP_SSE 1 +#define FF_CMP_SATD 2 +#define FF_CMP_DCT 3 +#define FF_CMP_PSNR 4 +#define FF_CMP_BIT 5 +#define FF_CMP_RD 6 +#define FF_CMP_ZERO 7 +#define FF_CMP_VSAD 8 +#define FF_CMP_VSSE 9 +#define FF_CMP_NSSE 10 +#define FF_CMP_W53 11 +#define FF_CMP_W97 12 +#define FF_CMP_DCTMAX 13 +#define FF_CMP_DCT264 14 +#define FF_CMP_MEDIAN_SAD 15 +#define FF_CMP_CHROMA 256 + + /** + * ME diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int dia_size; + + /** + * amount of previous MV predictors (2a+1 x 2a+1 square) + * - encoding: Set by user. + * - decoding: unused + */ + int last_predictor_count; + + /** + * motion estimation prepass comparison function + * - encoding: Set by user. + * - decoding: unused + */ + int me_pre_cmp; + + /** + * ME prepass diamond size & shape + * - encoding: Set by user. + * - decoding: unused + */ + int pre_dia_size; + + /** + * subpel ME quality + * - encoding: Set by user. + * - decoding: unused + */ + int me_subpel_quality; + + /** + * maximum motion estimation search range in subpel units + * If 0 then no limit. + * + * - encoding: Set by user. + * - decoding: unused + */ + int me_range; + + /** + * macroblock decision mode + * - encoding: Set by user. + * - decoding: unused + */ + int mb_decision; +#define FF_MB_DECISION_SIMPLE 0 ///< uses mb_cmp +#define FF_MB_DECISION_BITS 1 ///< chooses the one which needs the fewest bits +#define FF_MB_DECISION_RD 2 ///< rate distortion + + /** + * custom intra quantization matrix + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. + */ + uint16_t *intra_matrix; + + /** + * custom inter quantization matrix + * Must be allocated with the av_malloc() family of functions, and will be freed in + * avcodec_free_context(). + * - encoding: Set/allocated by user, freed by libavcodec. Can be NULL. + * - decoding: Set/allocated/freed by libavcodec. + */ + uint16_t *inter_matrix; + + /** + * custom intra quantization matrix + * - encoding: Set by user, can be NULL. + * - decoding: unused. + */ + uint16_t *chroma_intra_matrix; + +#if FF_API_INTRA_DC_PRECISION + /** + * precision of the intra DC coefficient - 8 + * - encoding: Set by user. + * - decoding: Set by libavcodec + * @deprecated Use the MPEG-2 encoder's private option "intra_dc_precision" instead. + */ + attribute_deprecated + int intra_dc_precision; +#endif + + /** + * minimum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmin; + + /** + * maximum MB Lagrange multiplier + * - encoding: Set by user. + * - decoding: unused + */ + int mb_lmax; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int bidir_refine; + + /** + * minimum GOP size + * - encoding: Set by user. + * - decoding: unused + */ + int keyint_min; + + /** + * the number of pictures in a group of pictures, or 0 for intra_only + * - encoding: Set by user. + * - decoding: unused + */ + int gop_size; + + /** + * Note: Value depends upon the compare function used for fullpel ME. + * - encoding: Set by user. + * - decoding: unused + */ + int mv0_threshold; + + /** + * Number of slices. + * Indicates number of picture subdivisions. Used for parallelized + * decoding. + * - encoding: Set by user + * - decoding: unused + */ + int slices; + + /* audio only */ + int sample_rate; ///< samples per second + + /** + * audio sample format + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVSampleFormat sample_fmt; ///< sample format + + /** + * Audio channel layout. + * - encoding: must be set by the caller, to one of AVCodec.ch_layouts. + * - decoding: may be set by the caller if known e.g. from the container. + * The decoder can then override during decoding as needed. + */ + AVChannelLayout ch_layout; + + /** + * Number of samples per channel in an audio frame. + * + * - encoding: may be set by the user before calling avcodec_open2(), and + * libavcodec may then overwrite it if needed. Each submitted frame + * except the last must contain exactly frame_size samples per channel. + * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, except + * when AV_CODEC_FLAG2_FIXED_FRAME_SIZE is requested, then the + * frame size is not restricted. + * - decoding: may be set by some decoders to indicate constant frame size + */ + int frame_size; + + /* The following data should not be initialized. */ + /** + * number of bytes per packet if constant and known or 0 + * Used by some WAV based audio codecs. + */ + int block_align; + + /** + * Audio cutoff bandwidth (0 means "automatic") + * - encoding: Set by user. + * - decoding: unused + */ + int cutoff; + + /** + * Type of service that the audio stream conveys. + * - encoding: Set by user. + * - decoding: Set by libavcodec. + */ + enum AVAudioServiceType audio_service_type; + + /** + * desired sample format + * - encoding: Not used. + * - decoding: Set by user. + * Decoder will decode to this format if it can. + */ + enum AVSampleFormat request_sample_fmt; + + /** + * Audio only. The number of "priming" samples (padding) inserted by the + * encoder at the beginning of the audio. I.e. this number of leading + * decoded samples must be discarded by the caller to get the original audio + * without leading padding. + * + * - decoding: unused + * - encoding: Set by libavcodec. The timestamps on the output packets are + * adjusted by the encoder so that they always refer to the + * first sample of the data actually contained in the packet, + * including any added padding. E.g. if the timebase is + * 1/samplerate and the timestamp of the first input sample is + * 0, the timestamp of the first output packet will be + * -initial_padding. + */ + int initial_padding; + + /** + * Audio only. The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded by the caller from the end of the stream to get the original + * audio without any trailing padding. + * + * - decoding: unused + * - encoding: unused + */ + int trailing_padding; + + /** + * Number of samples to skip after a discontinuity + * - decoding: unused + * - encoding: set by libavcodec + */ + int seek_preroll; + + /** + * This callback is called at the beginning of each frame to get data + * buffer(s) for it. There may be one contiguous buffer for all the data or + * there may be a buffer per each data plane or anything in between. What + * this means is, you may set however many entries in buf[] you feel necessary. + * Each buffer must be reference-counted using the AVBuffer API (see description + * of buf[] below). + * + * The following fields will be set in the frame before this callback is + * called: + * - format + * - width, height (video only) + * - sample_rate, channel_layout, nb_samples (audio only) + * Their values may differ from the corresponding values in + * AVCodecContext. This callback must use the frame values, not the codec + * context values, to calculate the required buffer size. + * + * This callback must fill the following fields in the frame: + * - data[] + * - linesize[] + * - extended_data: + * * if the data is planar audio with more than 8 channels, then this + * callback must allocate and fill extended_data to contain all pointers + * to all data planes. data[] must hold as many pointers as it can. + * extended_data must be allocated with av_malloc() and will be freed in + * av_frame_unref(). + * * otherwise extended_data must point to data + * - buf[] must contain one or more pointers to AVBufferRef structures. Each of + * the frame's data and extended_data pointers must be contained in these. That + * is, one AVBufferRef for each allocated chunk of memory, not necessarily one + * AVBufferRef per data[] entry. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * - extended_buf and nb_extended_buf must be allocated with av_malloc() by + * this callback and filled with the extra buffers if there are more + * buffers than buf[] can hold. extended_buf will be freed in + * av_frame_unref(). + * Decoders will generally initialize the whole buffer before it is output + * but it can in rare error conditions happen that uninitialized data is passed + * through. \important The buffers returned by get_buffer* should thus not contain sensitive + * data. + * + * If AV_CODEC_CAP_DR1 is not set then get_buffer2() must call + * avcodec_default_get_buffer2() instead of providing buffers allocated by + * some other means. + * + * Each data plane must be aligned to the maximum required by the target + * CPU. + * + * @see avcodec_default_get_buffer2() + * + * Video: + * + * If AV_GET_BUFFER_FLAG_REF is set in flags then the frame may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * avcodec_align_dimensions2() should be used to find the required width and + * height, as they normally need to be rounded up to the next multiple of 16. + * + * Some decoders do not support linesizes changing between frames. + * + * If frame multithreading is used, this callback may be called from a + * different thread, but not from more than one at once. Does not need to be + * reentrant. + * + * @see avcodec_align_dimensions2() + * + * Audio: + * + * Decoders request a buffer of a particular size by setting + * AVFrame.nb_samples prior to calling get_buffer2(). The decoder may, + * however, utilize only part of the buffer by setting AVFrame.nb_samples + * to a smaller value in the output frame. + * + * As a convenience, av_samples_get_buffer_size() and + * av_samples_fill_arrays() in libavutil may be used by custom get_buffer2() + * functions to find the required data size and to fill data pointers and + * linesize. In AVFrame.linesize, only linesize[0] may be set for audio + * since all planes must be the same size. + * + * @see av_samples_get_buffer_size(), av_samples_fill_arrays() + * + * - encoding: unused + * - decoding: Set by libavcodec, user can override. + */ + int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); + + /* - encoding parameters */ + /** + * number of bits the bitstream is allowed to diverge from the reference. + * the reference can be CBR (for CBR pass1) or VBR (for pass2) + * - encoding: Set by user; unused for constant quantizer encoding. + * - decoding: unused + */ + int bit_rate_tolerance; + + /** + * Global quality for codecs which cannot change it per frame. + * This should be proportional to MPEG-1/2/4 qscale. + * - encoding: Set by user. + * - decoding: unused + */ + int global_quality; + + /** + * - encoding: Set by user. + * - decoding: unused + */ + int compression_level; +#define FF_COMPRESSION_DEFAULT -1 + + float qcompress; ///< amount of qscale change between easy & hard scenes (0.0-1.0) + float qblur; ///< amount of qscale smoothing over time (0.0-1.0) + + /** + * minimum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmin; + + /** + * maximum quantizer + * - encoding: Set by user. + * - decoding: unused + */ + int qmax; + + /** + * maximum quantizer difference between frames + * - encoding: Set by user. + * - decoding: unused + */ + int max_qdiff; + + /** + * decoder bitstream buffer size + * - encoding: Set by user. + * - decoding: May be set by libavcodec. + */ + int rc_buffer_size; + + /** + * ratecontrol override, see RcOverride + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + int rc_override_count; + RcOverride *rc_override; + + /** + * maximum bitrate + * - encoding: Set by user. + * - decoding: Set by user, may be overwritten by libavcodec. + */ + int64_t rc_max_rate; + + /** + * minimum bitrate + * - encoding: Set by user. + * - decoding: unused + */ + int64_t rc_min_rate; + + /** + * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_max_available_vbv_use; + + /** + * Ratecontrol attempt to use, at least, times the amount needed to prevent a vbv overflow. + * - encoding: Set by user. + * - decoding: unused. + */ + float rc_min_vbv_overflow_use; + + /** + * Number of bits which should be loaded into the rc buffer before decoding starts. + * - encoding: Set by user. + * - decoding: unused + */ + int rc_initial_buffer_occupancy; + + /** + * trellis RD quantization + * - encoding: Set by user. + * - decoding: unused + */ + int trellis; + + /** + * pass1 encoding statistics output buffer + * - encoding: Set by libavcodec. + * - decoding: unused + */ + char *stats_out; + + /** + * pass2 encoding statistics input buffer + * Concatenated stuff from stats_out of pass1 should be placed here. + * - encoding: Allocated/set/freed by user. + * - decoding: unused + */ + char *stats_in; + + /** + * Work around bugs in encoders which sometimes cannot be detected automatically. + * - encoding: Set by user + * - decoding: Set by user + */ + int workaround_bugs; +#define FF_BUG_AUTODETECT 1 ///< autodetection +#define FF_BUG_XVID_ILACE 4 +#define FF_BUG_UMP4 8 +#define FF_BUG_NO_PADDING 16 +#define FF_BUG_AMV 32 +#define FF_BUG_QPEL_CHROMA 64 +#define FF_BUG_STD_QPEL 128 +#define FF_BUG_QPEL_CHROMA2 256 +#define FF_BUG_DIRECT_BLOCKSIZE 512 +#define FF_BUG_EDGE 1024 +#define FF_BUG_HPEL_CHROMA 2048 +#define FF_BUG_DC_CLIP 4096 +#define FF_BUG_MS 8192 ///< Work around various bugs in Microsoft's broken decoders. +#define FF_BUG_TRUNCATED 16384 +#define FF_BUG_IEDGE 32768 + + /** + * strictly follow the standard (MPEG-4, ...). + * - encoding: Set by user. + * - decoding: Set by user. + * Setting this to STRICT or higher means the encoder and decoder will + * generally do stupid things, whereas setting it to unofficial or lower + * will mean the encoder might produce output that is not supported by all + * spec-compliant decoders. Decoders don't differentiate between normal, + * unofficial and experimental (that is, they always try to decode things + * when they can) unless they are explicitly asked to behave stupidly + * (=strictly conform to the specs) + * This may only be set to one of the FF_COMPLIANCE_* values in defs.h. + */ + int strict_std_compliance; + + /** + * error concealment flags + * - encoding: unused + * - decoding: Set by user. + */ + int error_concealment; +#define FF_EC_GUESS_MVS 1 +#define FF_EC_DEBLOCK 2 +#define FF_EC_FAVOR_INTER 256 + + /** + * debug + * - encoding: Set by user. + * - decoding: Set by user. + */ + int debug; +#define FF_DEBUG_PICT_INFO 1 +#define FF_DEBUG_RC 2 +#define FF_DEBUG_BITSTREAM 4 +#define FF_DEBUG_MB_TYPE 8 +#define FF_DEBUG_QP 16 +#define FF_DEBUG_DCT_COEFF 0x00000040 +#define FF_DEBUG_SKIP 0x00000080 +#define FF_DEBUG_STARTCODE 0x00000100 +#define FF_DEBUG_ER 0x00000400 +#define FF_DEBUG_MMCO 0x00000800 +#define FF_DEBUG_BUGS 0x00001000 +#define FF_DEBUG_BUFFERS 0x00008000 +#define FF_DEBUG_THREADS 0x00010000 +#define FF_DEBUG_GREEN_MD 0x00800000 +#define FF_DEBUG_NOMC 0x01000000 + + /** + * Error recognition; may misdetect some more or less valid parts as errors. + * This is a bitfield of the AV_EF_* values defined in defs.h. + * + * - encoding: Set by user. + * - decoding: Set by user. + */ + int err_recognition; + + /** + * Hardware accelerator in use + * - encoding: unused. + * - decoding: Set by libavcodec + */ + const struct AVHWAccel *hwaccel; + + /** + * Legacy hardware accelerator context. + * + * For some hardware acceleration methods, the caller may use this field to + * signal hwaccel-specific data to the codec. The struct pointed to by this + * pointer is hwaccel-dependent and defined in the respective header. Please + * refer to the FFmpeg HW accelerator documentation to know how to fill + * this. + * + * In most cases this field is optional - the necessary information may also + * be provided to libavcodec through @ref hw_frames_ctx or @ref + * hw_device_ctx (see avcodec_get_hw_config()). However, in some cases it + * may be the only method of signalling some (optional) information. + * + * The struct and its contents are owned by the caller. + * + * - encoding: May be set by the caller before avcodec_open2(). Must remain + * valid until avcodec_free_context(). + * - decoding: May be set by the caller in the get_format() callback. + * Must remain valid until the next get_format() call, + * or avcodec_free_context() (whichever comes first). + */ + void *hwaccel_context; + + /** + * A reference to the AVHWFramesContext describing the input (for encoding) + * or output (decoding) frames. The reference is set by the caller and + * afterwards owned (and freed) by libavcodec - it should never be read by + * the caller after being set. + * + * - decoding: This field should be set by the caller from the get_format() + * callback. The previous reference (if any) will always be + * unreffed by libavcodec before the get_format() call. + * + * If the default get_buffer2() is used with a hwaccel pixel + * format, then this AVHWFramesContext will be used for + * allocating the frame buffers. + * + * - encoding: For hardware encoders configured to use a hwaccel pixel + * format, this field should be set by the caller to a reference + * to the AVHWFramesContext describing input frames. + * AVHWFramesContext.format must be equal to + * AVCodecContext.pix_fmt. + * + * This field should be set before avcodec_open2() is called. + */ + AVBufferRef *hw_frames_ctx; + + /** + * A reference to the AVHWDeviceContext describing the device which will + * be used by a hardware encoder/decoder. The reference is set by the + * caller and afterwards owned (and freed) by libavcodec. + * + * This should be used if either the codec device does not require + * hardware frames or any that are used are to be allocated internally by + * libavcodec. If the user wishes to supply any of the frames used as + * encoder input or decoder output then hw_frames_ctx should be used + * instead. When hw_frames_ctx is set in get_format() for a decoder, this + * field will be ignored while decoding the associated stream segment, but + * may again be used on a following one after another get_format() call. + * + * For both encoders and decoders this field should be set before + * avcodec_open2() is called and must not be written to thereafter. + * + * Note that some decoders may require this field to be set initially in + * order to support hw_frames_ctx at all - in that case, all frames + * contexts used must be created on the same device. + */ + AVBufferRef *hw_device_ctx; + + /** + * Bit set of AV_HWACCEL_FLAG_* flags, which affect hardware accelerated + * decoding (if active). + * - encoding: unused + * - decoding: Set by user (either before avcodec_open2(), or in the + * AVCodecContext.get_format callback) + */ + int hwaccel_flags; + + /** + * Video decoding only. Sets the number of extra hardware frames which + * the decoder will allocate for use by the caller. This must be set + * before avcodec_open2() is called. + * + * Some hardware decoders require all frames that they will use for + * output to be defined in advance before decoding starts. For such + * decoders, the hardware frame pool must therefore be of a fixed size. + * The extra frames set here are on top of any number that the decoder + * needs internally in order to operate normally (for example, frames + * used as reference pictures). + */ + int extra_hw_frames; + + /** + * error + * - encoding: Set by libavcodec if flags & AV_CODEC_FLAG_PSNR. + * - decoding: unused + */ + uint64_t error[AV_NUM_DATA_POINTERS]; + + /** + * DCT algorithm, see FF_DCT_* below + * - encoding: Set by user. + * - decoding: unused + */ + int dct_algo; +#define FF_DCT_AUTO 0 +#define FF_DCT_FASTINT 1 +#define FF_DCT_INT 2 +#define FF_DCT_MMX 3 +#define FF_DCT_ALTIVEC 5 +#define FF_DCT_FAAN 6 +#define FF_DCT_NEON 7 + + /** + * IDCT algorithm, see FF_IDCT_* below. + * - encoding: Set by user. + * - decoding: Set by user. + */ + int idct_algo; +#define FF_IDCT_AUTO 0 +#define FF_IDCT_INT 1 +#define FF_IDCT_SIMPLE 2 +#define FF_IDCT_SIMPLEMMX 3 +#define FF_IDCT_ARM 7 +#define FF_IDCT_ALTIVEC 8 +#define FF_IDCT_SIMPLEARM 10 +#define FF_IDCT_XVID 14 +#define FF_IDCT_SIMPLEARMV5TE 16 +#define FF_IDCT_SIMPLEARMV6 17 +#define FF_IDCT_FAAN 20 +#define FF_IDCT_SIMPLENEON 22 +#define FF_IDCT_SIMPLEAUTO 128 + + /** + * bits per sample/pixel from the demuxer (needed for huffyuv). + * - encoding: Set by libavcodec. + * - decoding: Set by user. + */ + int bits_per_coded_sample; + + /** + * Bits per sample/pixel of internal libavcodec pixel/sample format. + * - encoding: set by user. + * - decoding: set by libavcodec. + */ + int bits_per_raw_sample; + + /** + * thread count + * is used to decide how many independent tasks should be passed to execute() + * - encoding: Set by user. + * - decoding: Set by user. + */ + int thread_count; + + /** + * Which multithreading methods to use. + * Use of FF_THREAD_FRAME will increase decoding delay by one frame per thread, + * so clients which cannot provide future frames should not use it. + * + * - encoding: Set by user, otherwise the default is used. + * - decoding: Set by user, otherwise the default is used. + */ + int thread_type; +#define FF_THREAD_FRAME 1 ///< Decode more than one frame at once +#define FF_THREAD_SLICE 2 ///< Decode more than one part of a single frame at once + + /** + * Which multithreading methods are in use by the codec. + * - encoding: Set by libavcodec. + * - decoding: Set by libavcodec. + */ + int active_thread_type; + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param count the number of things to execute + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg), void *arg2, int *ret, int count, int size); + + /** + * The codec may call this to execute several independent things. + * It will return only after finishing all tasks. + * The user may replace this with some multithreaded implementation, + * the default implementation will execute the parts serially. + * @param c context passed also to func + * @param count the number of things to execute + * @param arg2 argument passed unchanged to func + * @param ret return values of executed functions, must have space for "count" values. May be NULL. + * @param func function that will be called count times, with jobnr from 0 to count-1. + * threadnr will be in the range 0 to c->thread_count-1 < MAX_THREADS and so that no + * two instances of func executing at the same time will have the same threadnr. + * @return always 0 currently, but code should handle a future improvement where when any call to func + * returns < 0 no further calls to func may be done and < 0 is returned. + * - encoding: Set by libavcodec, user can override. + * - decoding: Set by libavcodec, user can override. + */ + int (*execute2)(struct AVCodecContext *c, int (*func)(struct AVCodecContext *c2, void *arg, int jobnr, int threadnr), void *arg2, int *ret, int count); + + /** + * profile + * - encoding: Set by user. + * - decoding: Set by libavcodec. + * See the AV_PROFILE_* defines in defs.h. + */ + int profile; + + /** + * Encoding level descriptor. + * - encoding: Set by user, corresponds to a specific level defined by the + * codec, usually corresponding to the profile level, if not specified it + * is set to AV_LEVEL_UNKNOWN. + * - decoding: Set by libavcodec. + * See AV_LEVEL_* in defs.h. + */ + int level; + + /** + * Skip loop filtering for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_loop_filter; + + /** + * Skip IDCT/dequantization for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_idct; + + /** + * Skip decoding for selected frames. + * - encoding: unused + * - decoding: Set by user. + */ + enum AVDiscard skip_frame; + + /** + * Skip processing alpha if supported by codec. + * Note that if the format uses pre-multiplied alpha (common with VP6, + * and recommended due to better video quality/compression) + * the image will look as if alpha-blended onto a black background. + * However for formats that do not use pre-multiplied alpha + * there might be serious artefacts (though e.g. libswscale currently + * assumes pre-multiplied alpha anyway). + * + * - decoding: set by user + * - encoding: unused + */ + int skip_alpha; + + /** + * Number of macroblock rows at the top which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_top; + + /** + * Number of macroblock rows at the bottom which are skipped. + * - encoding: unused + * - decoding: Set by user. + */ + int skip_bottom; + + /** + * low resolution decoding, 1-> 1/2 size, 2->1/4 size + * - encoding: unused + * - decoding: Set by user. + */ + int lowres; + + /** + * AVCodecDescriptor + * - encoding: unused. + * - decoding: set by libavcodec. + */ + const struct AVCodecDescriptor *codec_descriptor; + + /** + * Character encoding of the input subtitles file. + * - decoding: set by user + * - encoding: unused + */ + char *sub_charenc; + + /** + * Subtitles character encoding mode. Formats or codecs might be adjusting + * this setting (if they are doing the conversion themselves for instance). + * - decoding: set by libavcodec + * - encoding: unused + */ + int sub_charenc_mode; +#define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) +#define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself +#define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv +#define FF_SUB_CHARENC_MODE_IGNORE 2 ///< neither convert the subtitles, nor check them for valid UTF-8 + + /** + * Header containing style information for text subtitles. + * For SUBTITLE_ASS subtitle type, it should contain the whole ASS + * [Script Info] and [V4+ Styles] section, plus the [Events] line and + * the Format line following. It shouldn't include any Dialogue line. + * + * - encoding: May be set by the caller before avcodec_open2() to an array + * allocated with the av_malloc() family of functions. + * - decoding: May be set by libavcodec in avcodec_open2(). + * + * After being set, the array is owned by the codec and freed in + * avcodec_free_context(). + */ + int subtitle_header_size; + uint8_t *subtitle_header; + + /** + * dump format separator. + * can be ", " or "\n " or anything else + * - encoding: Set by user. + * - decoding: Set by user. + */ + uint8_t *dump_separator; + + /** + * ',' separated list of allowed decoders. + * If NULL then all are allowed + * - encoding: unused + * - decoding: set by user + */ + char *codec_whitelist; + + /** + * Additional data associated with the entire coded stream. + * + * - decoding: may be set by user before calling avcodec_open2(). + * - encoding: may be set by libavcodec after avcodec_open2(). + */ + AVPacketSideData *coded_side_data; + int nb_coded_side_data; + + /** + * Bit set of AV_CODEC_EXPORT_DATA_* flags, which affects the kind of + * metadata exported in frame, packet, or coded stream side data by + * decoders and encoders. + * + * - decoding: set by user + * - encoding: set by user + */ + int export_side_data; + + /** + * The number of pixels per image to maximally accept. + * + * - decoding: set by user + * - encoding: set by user + */ + int64_t max_pixels; + + /** + * Video decoding only. Certain video codecs support cropping, meaning that + * only a sub-rectangle of the decoded frame is intended for display. This + * option controls how cropping is handled by libavcodec. + * + * When set to 1 (the default), libavcodec will apply cropping internally. + * I.e. it will modify the output frame width/height fields and offset the + * data pointers (only by as much as possible while preserving alignment, or + * by the full amount if the AV_CODEC_FLAG_UNALIGNED flag is set) so that + * the frames output by the decoder refer only to the cropped area. The + * crop_* fields of the output frames will be zero. + * + * When set to 0, the width/height fields of the output frames will be set + * to the coded dimensions and the crop_* fields will describe the cropping + * rectangle. Applying the cropping is left to the caller. + * + * @warning When hardware acceleration with opaque output frames is used, + * libavcodec is unable to apply cropping from the top/left border. + * + * @note when this option is set to zero, the width/height fields of the + * AVCodecContext and output AVFrames have different meanings. The codec + * context fields store display dimensions (with the coded dimensions in + * coded_width/height), while the frame fields store the coded dimensions + * (with the display dimensions being determined by the crop_* fields). + */ + int apply_cropping; + + /** + * The percentage of damaged samples to discard a frame. + * + * - decoding: set by user + * - encoding: unused + */ + int discard_damaged_percentage; + + /** + * The number of samples per frame to maximally accept. + * + * - decoding: set by user + * - encoding: set by user + */ + int64_t max_samples; + + /** + * This callback is called at the beginning of each packet to get a data + * buffer for it. + * + * The following field will be set in the packet before this callback is + * called: + * - size + * This callback must use the above value to calculate the required buffer size, + * which must padded by at least AV_INPUT_BUFFER_PADDING_SIZE bytes. + * + * In some specific cases, the encoder may not use the entire buffer allocated by this + * callback. This will be reflected in the size value in the packet once returned by + * avcodec_receive_packet(). + * + * This callback must fill the following fields in the packet: + * - data: alignment requirements for AVPacket apply, if any. Some architectures and + * encoders may benefit from having aligned data. + * - buf: must contain a pointer to an AVBufferRef structure. The packet's + * data pointer must be contained in it. See: av_buffer_create(), av_buffer_alloc(), + * and av_buffer_ref(). + * + * If AV_CODEC_CAP_DR1 is not set then get_encode_buffer() must call + * avcodec_default_get_encode_buffer() instead of providing a buffer allocated by + * some other means. + * + * The flags field may contain a combination of AV_GET_ENCODE_BUFFER_FLAG_ flags. + * They may be used for example to hint what use the buffer may get after being + * created. + * Implementations of this callback may ignore flags they don't understand. + * If AV_GET_ENCODE_BUFFER_FLAG_REF is set in flags then the packet may be reused + * (read and/or written to if it is writable) later by libavcodec. + * + * This callback must be thread-safe, as when frame threading is used, it may + * be called from multiple threads simultaneously. + * + * @see avcodec_default_get_encode_buffer() + * + * - encoding: Set by libavcodec, user can override. + * - decoding: unused + */ + int (*get_encode_buffer)(struct AVCodecContext *s, AVPacket *pkt, int flags); + + /** + * Frame counter, set by libavcodec. + * + * - decoding: total number of frames returned from the decoder so far. + * - encoding: total number of frames passed to the encoder so far. + * + * @note the counter is not incremented if encoding/decoding resulted in + * an error. + */ + int64_t frame_num; + + /** + * Decoding only. May be set by the caller before avcodec_open2() to an + * av_malloc()'ed array (or via AVOptions). Owned and freed by the decoder + * afterwards. + * + * Side data attached to decoded frames may come from several sources: + * 1. coded_side_data, which the decoder will for certain types translate + * from packet-type to frame-type and attach to frames; + * 2. side data attached to an AVPacket sent for decoding (same + * considerations as above); + * 3. extracted from the coded bytestream. + * The first two cases are supplied by the caller and typically come from a + * container. + * + * This array configures decoder behaviour in cases when side data of the + * same type is present both in the coded bytestream and in the + * user-supplied side data (items 1. and 2. above). In all cases, at most + * one instance of each side data type will be attached to output frames. By + * default it will be the bytestream side data. Adding an + * AVPacketSideDataType value to this array will flip the preference for + * this type, thus making the decoder prefer user-supplied side data over + * bytestream. In case side data of the same type is present both in + * coded_data and attacked to a packet, the packet instance always has + * priority. + * + * The array may also contain a single -1, in which case the preference is + * switched for all side data types. + */ + int *side_data_prefer_packet; + /** + * Number of entries in side_data_prefer_packet. + */ + unsigned nb_side_data_prefer_packet; + + /** + * Array containing static side data, such as HDR10 CLL / MDCV structures. + * Side data entries should be allocated by usage of helpers defined in + * libavutil/frame.h. + * + * - encoding: may be set by user before calling avcodec_open2() for + * encoder configuration. Afterwards owned and freed by the + * encoder. + * - decoding: may be set by libavcodec in avcodec_open2(). + */ + AVFrameSideData **decoded_side_data; + int nb_decoded_side_data; + + /** + * Indicates how the alpha channel of the video is represented. + * - encoding: Set by user + * - decoding: Set by libavcodec + */ + enum AVAlphaMode alpha_mode; +} AVCodecContext; + +/** + * @defgroup lavc_hwaccel AVHWAccel + * + * @note Nothing in this structure should be accessed by the user. At some + * point in future it will not be externally visible at all. + * + * @{ + */ +typedef struct AVHWAccel { + /** + * Name of the hardware accelerated codec. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + */ + const char *name; + + /** + * Type of codec implemented by the hardware accelerator. + * + * See AVMEDIA_TYPE_xxx + */ + enum AVMediaType type; + + /** + * Codec implemented by the hardware accelerator. + * + * See AV_CODEC_ID_xxx + */ + enum AVCodecID id; + + /** + * Supported pixel format. + * + * Only hardware accelerated formats are supported here. + */ + enum AVPixelFormat pix_fmt; + + /** + * Hardware accelerated codec capabilities. + * see AV_HWACCEL_CODEC_CAP_* + */ + int capabilities; +} AVHWAccel; + +/** + * HWAccel is experimental and is thus avoided in favor of non experimental + * codecs + */ +#define AV_HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 + +/** + * Hardware acceleration should be used for decoding even if the codec level + * used is unknown or higher than the maximum supported level reported by the + * hardware driver. + * + * It's generally a good idea to pass this flag unless you have a specific + * reason not to, as hardware tends to under-report supported levels. + */ +#define AV_HWACCEL_FLAG_IGNORE_LEVEL (1 << 0) + +/** + * Hardware acceleration can output YUV pixel formats with a different chroma + * sampling than 4:2:0 and/or other than 8 bits per component. + */ +#define AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH (1 << 1) + +/** + * Hardware acceleration should still be attempted for decoding when the + * codec profile does not match the reported capabilities of the hardware. + * + * For example, this can be used to try to decode baseline profile H.264 + * streams in hardware - it will often succeed, because many streams marked + * as baseline profile actually conform to constrained baseline profile. + * + * @warning If the stream is actually not supported then the behaviour is + * undefined, and may include returning entirely incorrect output + * while indicating success. + */ +#define AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH (1 << 2) + +/** + * Some hardware decoders (namely nvdec) can either output direct decoder + * surfaces, or make an on-device copy and return said copy. + * There is a hard limit on how many decoder surfaces there can be, and it + * cannot be accurately guessed ahead of time. + * For some processing chains, this can be okay, but others will run into the + * limit and in turn produce very confusing errors that require fine tuning of + * more or less obscure options by the user, or in extreme cases cannot be + * resolved at all without inserting an avfilter that forces a copy. + * + * Thus, the hwaccel will by default make a copy for safety and resilience. + * If a users really wants to minimize the amount of copies, they can set this + * flag and ensure their processing chain does not exhaust the surface pool. + */ +#define AV_HWACCEL_FLAG_UNSAFE_OUTPUT (1 << 3) + +/** + * @} + */ + +enum AVSubtitleType { + SUBTITLE_NONE, + + SUBTITLE_BITMAP, ///< A bitmap, pict will be set + + /** + * Plain text, the text field must be set by the decoder and is + * authoritative. ass and pict fields may contain approximations. + */ + SUBTITLE_TEXT, + + /** + * Formatted text, the ass field must be set by the decoder and is + * authoritative. pict and text fields may contain approximations. + */ + SUBTITLE_ASS, +}; + +#define AV_SUBTITLE_FLAG_FORCED 0x00000001 + +typedef struct AVSubtitleRect { + int x; ///< top left corner of pict, undefined when pict is not set + int y; ///< top left corner of pict, undefined when pict is not set + int w; ///< width of pict, undefined when pict is not set + int h; ///< height of pict, undefined when pict is not set + int nb_colors; ///< number of colors in pict, undefined when pict is not set + + /** + * data+linesize for the bitmap of this subtitle. + * Can be set for text/ass as well once they are rendered. + */ + uint8_t *data[4]; + int linesize[4]; + + int flags; + enum AVSubtitleType type; + + char *text; ///< 0 terminated plain UTF-8 text + + /** + * 0 terminated ASS/SSA compatible event line. + * The presentation of this is unaffected by the other values in this + * struct. + */ + char *ass; +} AVSubtitleRect; + +typedef struct AVSubtitle { + uint16_t format; /* 0 = graphics */ + uint32_t start_display_time; /* relative to packet pts, in ms */ + uint32_t end_display_time; /* relative to packet pts, in ms */ + unsigned num_rects; + AVSubtitleRect **rects; + int64_t pts; ///< Same as packet pts, in AV_TIME_BASE +} AVSubtitle; + +/** + * Return the LIBAVCODEC_VERSION_INT constant. + */ +unsigned avcodec_version(void); + +/** + * Return the libavcodec build-time configuration. + */ +const char *avcodec_configuration(void); + +/** + * Return the libavcodec license. + */ +const char *avcodec_license(void); + +/** + * Allocate an AVCodecContext and set its fields to default values. The + * resulting struct should be freed with avcodec_free_context(). + * + * @param codec if non-NULL, allocate private data and initialize defaults + * for the given codec. It is illegal to then call avcodec_open2() + * with a different codec. + * If NULL, then the codec-specific defaults won't be initialized, + * which may result in suboptimal default settings (this is + * important mainly for encoders, e.g. libx264). + * + * @return An AVCodecContext filled with default values or NULL on failure. + */ +AVCodecContext *avcodec_alloc_context3(const AVCodec *codec); + +/** + * Free the codec context and everything associated with it and write NULL to + * the provided pointer. + */ +void avcodec_free_context(AVCodecContext **avctx); + +/** + * Get the AVClass for AVCodecContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_class(void); + +/** + * Get the AVClass for AVSubtitleRect. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *avcodec_get_subtitle_rect_class(void); + +/** + * Fill the parameters struct based on the values from the supplied codec + * context. Any allocated fields in par are freed and replaced with duplicates + * of the corresponding fields in codec. + * + * @return >= 0 on success, a negative AVERROR code on failure + * + * @relates AVCodecParameters + */ +int avcodec_parameters_from_context(struct AVCodecParameters *par, + const AVCodecContext *codec); + +/** + * Fill the codec context based on the values from the supplied codec + * parameters. Any allocated fields in codec that have a corresponding field in + * par are freed and replaced with duplicates of the corresponding field in par. + * Fields in codec that do not have a counterpart in par are not touched. + * + * @return >= 0 on success, a negative AVERROR code on failure. + * + * @relates AVCodecParameters + */ +int avcodec_parameters_to_context(AVCodecContext *codec, + const struct AVCodecParameters *par); + +/** + * Initialize the AVCodecContext to use the given AVCodec. Prior to using this + * function the context has to be allocated with avcodec_alloc_context3(). + * + * The functions avcodec_find_decoder_by_name(), avcodec_find_encoder_by_name(), + * avcodec_find_decoder() and avcodec_find_encoder() provide an easy way for + * retrieving a codec. + * + * Depending on the codec, you might need to set options in the codec context + * also for decoding (e.g. width, height, or the pixel or audio sample format in + * the case the information is not available in the bitstream, as when decoding + * raw audio or video). + * + * Options in the codec context can be set either by setting them in the options + * AVDictionary, or by setting the values in the context itself, directly or by + * using the av_opt_set() API before calling this function. + * + * Example: + * @code + * av_dict_set(&opts, "b", "2.5M", 0); + * codec = avcodec_find_decoder(AV_CODEC_ID_H264); + * if (!codec) + * exit(1); + * + * context = avcodec_alloc_context3(codec); + * + * if (avcodec_open2(context, codec, opts) < 0) + * exit(1); + * @endcode + * + * In the case AVCodecParameters are available (e.g. when demuxing a stream + * using libavformat, and accessing the AVStream contained in the demuxer), the + * codec parameters can be copied to the codec context using + * avcodec_parameters_to_context(), as in the following example: + * + * @code + * AVStream *stream = ...; + * context = avcodec_alloc_context3(codec); + * if (avcodec_parameters_to_context(context, stream->codecpar) < 0) + * exit(1); + * if (avcodec_open2(context, codec, NULL) < 0) + * exit(1); + * @endcode + * + * @note Always call this function before using decoding routines (such as + * @ref avcodec_receive_frame()). + * + * @param avctx The context to initialize. + * @param codec The codec to open this context for. If a non-NULL codec has been + * previously passed to avcodec_alloc_context3() or + * for this context, then this parameter MUST be either NULL or + * equal to the previously passed codec. + * @param options A dictionary filled with AVCodecContext and codec-private + * options, which are set on top of the options already set in + * avctx, can be NULL. On return this object will be filled with + * options that were not found in the avctx codec context. + * + * @return zero on success, a negative value on error + * @see avcodec_alloc_context3(), avcodec_find_decoder(), avcodec_find_encoder(), + * av_dict_set(), av_opt_set(), av_opt_find(), avcodec_parameters_to_context() + */ +int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); + +/** + * Free all allocated data in the given subtitle struct. + * + * @param sub AVSubtitle to free. + */ +void avsubtitle_free(AVSubtitle *sub); + +/** + * @} + */ + +/** + * @addtogroup lavc_decoding + * @{ + */ + +/** + * The default callback for AVCodecContext.get_buffer2(). It is made public so + * it can be called by custom get_buffer2() implementations for decoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); + +/** + * The default callback for AVCodecContext.get_encode_buffer(). It is made public so + * it can be called by custom get_encode_buffer() implementations for encoders without + * AV_CODEC_CAP_DR1 set. + */ +int avcodec_default_get_encode_buffer(AVCodecContext *s, AVPacket *pkt, int flags); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you do not use any horizontal + * padding. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions(AVCodecContext *s, int *width, int *height); + +/** + * Modify width and height values so that they will result in a memory + * buffer that is acceptable for the codec if you also ensure that all + * line sizes are a multiple of the respective linesize_align[i]. + * + * May only be used if a codec with AV_CODEC_CAP_DR1 has been opened. + */ +void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, + int linesize_align[AV_NUM_DATA_POINTERS]); + +/** + * Decode a subtitle message. + * Return a negative value on error, otherwise return the number of bytes used. + * If no subtitle could be decompressed, got_sub_ptr is zero. + * Otherwise, the subtitle is stored in *sub. + * Note that AV_CODEC_CAP_DR1 is not available for subtitle codecs. This is for + * simplicity, because the performance difference is expected to be negligible + * and reusing a get_buffer written for video codecs would probably perform badly + * due to a potentially very different allocation pattern. + * + * Some decoders (those marked with AV_CODEC_CAP_DELAY) have a delay between input + * and output. This means that for some packets they will not immediately + * produce decoded output and need to be flushed at the end of decoding to get + * all the decoded data. Flushing is done by calling this function with packets + * with avpkt->data set to NULL and avpkt->size set to 0 until it stops + * returning subtitles. It is safe to flush even those decoders that are not + * marked with AV_CODEC_CAP_DELAY, then no subtitles will be returned. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx the codec context + * @param[out] sub The preallocated AVSubtitle in which the decoded subtitle will be stored, + * must be freed with avsubtitle_free if *got_sub_ptr is set. + * @param[in,out] got_sub_ptr Zero if no subtitle could be decompressed, otherwise, it is nonzero. + * @param[in] avpkt The input AVPacket containing the input buffer. + */ +int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, const AVPacket *avpkt); + +/** + * Supply raw packet data as input to a decoder. + * + * Internally, this call will copy relevant AVCodecContext fields, which can + * influence decoding per-packet, and apply them when the packet is actually + * decoded. (For example AVCodecContext.skip_frame, which might direct the + * decoder to drop the frame contained by the packet sent with this function.) + * + * @warning The input buffer, avpkt->data must be AV_INPUT_BUFFER_PADDING_SIZE + * larger than the actual read bytes because some optimized bitstream + * readers read 32 or 64 bits at once and could read over the end. + * + * @note The AVCodecContext MUST have been opened with @ref avcodec_open2() + * before packets may be fed to the decoder. + * + * @param avctx codec context + * @param[in] avpkt The input AVPacket. Usually, this will be a single video + * frame, or several complete audio frames. + * Ownership of the packet remains with the caller, and the + * decoder will not write to the packet. The decoder may create + * a reference to the packet data (or copy it if the packet is + * not reference-counted). + * Unlike with older APIs, the packet is always fully consumed, + * and if it contains multiple frames (e.g. some audio codecs), + * will require you to call avcodec_receive_frame() multiple + * times afterwards before you can send a new packet. + * It can be NULL (or an AVPacket with data set to NULL and + * size set to 0); in this case, it is considered a flush + * packet, which signals the end of the stream. Sending the + * first flush packet will return success. Subsequent ones are + * unnecessary and will return AVERROR_EOF. If the decoder + * still has frames buffered, it will return them after sending + * a flush packet. + * + * @retval 0 success + * @retval AVERROR(EAGAIN) input is not accepted in the current state - user + * must read output with avcodec_receive_frame() (once + * all output is read, the packet should be resent, + * and the call will not fail with EAGAIN). + * @retval AVERROR_EOF the decoder has been flushed, and no new packets can be + * sent to it (also returned if more than 1 flush + * packet is sent) + * @retval AVERROR(EINVAL) codec not opened, it is an encoder, or requires flush + * @retval AVERROR(ENOMEM) failed to add packet to internal queue, or similar + * @retval "another negative error code" legitimate decoding errors + */ +int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); + +/** + * Return decoded output data from a decoder or encoder (when the + * @ref AV_CODEC_FLAG_RECON_FRAME flag is used). + * + * @param avctx codec context + * @param frame This will be set to a reference-counted video or audio + * frame (depending on the decoder type) allocated by the + * codec. Note that the function will always call + * av_frame_unref(frame) before doing anything else. + * @param flags Combination of AV_CODEC_RECEIVE_FRAME_FLAG_* flags. + * + * @retval 0 success, a frame was returned + * @retval AVERROR(EAGAIN) output is not available in this state - user must + * try to send new input + * @retval AVERROR_EOF the codec has been fully flushed, and there will be + * no more output frames + * @retval AVERROR(EINVAL) codec not opened, or it is an encoder without the + * @ref AV_CODEC_FLAG_RECON_FRAME flag enabled + * @retval "other negative error code" legitimate decoding errors + */ +int avcodec_receive_frame_flags(AVCodecContext *avctx, AVFrame *frame, unsigned flags); + +/** + * Alias for `avcodec_receive_frame_flags(avctx, frame, 0)`. + */ +int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); + +/** + * Supply a raw video or audio frame to the encoder. Use avcodec_receive_packet() + * to retrieve buffered output packets. + * + * @param avctx codec context + * @param[in] frame AVFrame containing the raw audio or video frame to be encoded. + * Ownership of the frame remains with the caller, and the + * encoder will not write to the frame. The encoder may create + * a reference to the frame data (or copy it if the frame is + * not reference-counted). + * It can be NULL, in which case it is considered a flush + * packet. This signals the end of the stream. If the encoder + * still has packets buffered, it will return them after this + * call. Once flushing mode has been entered, additional flush + * packets are ignored, and sending frames will return + * AVERROR_EOF. + * + * For audio: + * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame + * can have any number of samples. + * If it is not set, or AV_CODEC_FLAG2_FIXED_FRAME_SIZE was + * requested, then frame->nb_samples must be equal to + * avctx->frame_size for all frames except the last. + * The final frame may be smaller than avctx->frame_size. + * @retval 0 success + * @retval AVERROR(EAGAIN) input is not accepted in the current state - user must + * read output with avcodec_receive_packet() (once all + * output is read, the packet should be resent, and the + * call will not fail with EAGAIN). + * @retval AVERROR_EOF the encoder has been flushed, and no new frames can + * be sent to it + * @retval AVERROR(EINVAL) codec not opened, it is a decoder, or requires flush + * @retval AVERROR(ENOMEM) failed to add packet to internal queue, or similar + * @retval "another negative error code" legitimate encoding errors + */ +int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); + +/** + * Read encoded data from the encoder. + * + * @param avctx codec context + * @param avpkt This will be set to a reference-counted packet allocated by the + * encoder. Note that the function will always call + * av_packet_unref(avpkt) before doing anything else. + * @retval 0 success + * @retval AVERROR(EAGAIN) output is not available in the current state - user must + * try to send input + * @retval AVERROR_EOF the encoder has been fully flushed, and there will be no + * more output packets + * @retval AVERROR(EINVAL) codec not opened, or it is a decoder + * @retval "another negative error code" legitimate encoding errors + */ +int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); + +/** + * Create and return a AVHWFramesContext with values adequate for hardware + * decoding. This is meant to get called from the get_format callback, and is + * a helper for preparing a AVHWFramesContext for AVCodecContext.hw_frames_ctx. + * This API is for decoding with certain hardware acceleration modes/APIs only. + * + * The returned AVHWFramesContext is not initialized. The caller must do this + * with av_hwframe_ctx_init(). + * + * Calling this function is not a requirement, but makes it simpler to avoid + * codec or hardware API specific details when manually allocating frames. + * + * Alternatively to this, an API user can set AVCodecContext.hw_device_ctx, + * which sets up AVCodecContext.hw_frames_ctx fully automatically, and makes + * it unnecessary to call this function or having to care about + * AVHWFramesContext initialization at all. + * + * There are a number of requirements for calling this function: + * + * - It must be called from get_format with the same avctx parameter that was + * passed to get_format. Calling it outside of get_format is not allowed, and + * can trigger undefined behavior. + * - The function is not always supported (see description of return values). + * Even if this function returns successfully, hwaccel initialization could + * fail later. (The degree to which implementations check whether the stream + * is actually supported varies. Some do this check only after the user's + * get_format callback returns.) + * - The hw_pix_fmt must be one of the choices suggested by get_format. If the + * user decides to use a AVHWFramesContext prepared with this API function, + * the user must return the same hw_pix_fmt from get_format. + * - The device_ref passed to this function must support the given hw_pix_fmt. + * - After calling this API function, it is the user's responsibility to + * initialize the AVHWFramesContext (returned by the out_frames_ref parameter), + * and to set AVCodecContext.hw_frames_ctx to it. If done, this must be done + * before returning from get_format (this is implied by the normal + * AVCodecContext.hw_frames_ctx API rules). + * - The AVHWFramesContext parameters may change every time time get_format is + * called. Also, AVCodecContext.hw_frames_ctx is reset before get_format. So + * you are inherently required to go through this process again on every + * get_format call. + * - It is perfectly possible to call this function without actually using + * the resulting AVHWFramesContext. One use-case might be trying to reuse a + * previously initialized AVHWFramesContext, and calling this API function + * only to test whether the required frame parameters have changed. + * - Fields that use dynamically allocated values of any kind must not be set + * by the user unless setting them is explicitly allowed by the documentation. + * If the user sets AVHWFramesContext.free and AVHWFramesContext.user_opaque, + * the new free callback must call the potentially set previous free callback. + * This API call may set any dynamically allocated fields, including the free + * callback. + * + * The function will set at least the following fields on AVHWFramesContext + * (potentially more, depending on hwaccel API): + * + * - All fields set by av_hwframe_ctx_alloc(). + * - Set the format field to hw_pix_fmt. + * - Set the sw_format field to the most suited and most versatile format. (An + * implication is that this will prefer generic formats over opaque formats + * with arbitrary restrictions, if possible.) + * - Set the width/height fields to the coded frame size, rounded up to the + * API-specific minimum alignment. + * - Only _if_ the hwaccel requires a pre-allocated pool: set the initial_pool_size + * field to the number of maximum reference surfaces possible with the codec, + * plus 1 surface for the user to work (meaning the user can safely reference + * at most 1 decoded surface at a time), plus additional buffering introduced + * by frame threading. If the hwaccel does not require pre-allocation, the + * field is left to 0, and the decoder will allocate new surfaces on demand + * during decoding. + * - Possibly AVHWFramesContext.hwctx fields, depending on the underlying + * hardware API. + * + * Essentially, out_frames_ref returns the same as av_hwframe_ctx_alloc(), but + * with basic frame parameters set. + * + * The function is stateless, and does not change the AVCodecContext or the + * device_ref AVHWDeviceContext. + * + * @param avctx The context which is currently calling get_format, and which + * implicitly contains all state needed for filling the returned + * AVHWFramesContext properly. + * @param device_ref A reference to the AVHWDeviceContext describing the device + * which will be used by the hardware decoder. + * @param hw_pix_fmt The hwaccel format you are going to return from get_format. + * @param out_frames_ref On success, set to a reference to an _uninitialized_ + * AVHWFramesContext, created from the given device_ref. + * Fields will be set to values required for decoding. + * Not changed if an error is returned. + * @return zero on success, a negative value on error. The following error codes + * have special semantics: + * AVERROR(ENOENT): the decoder does not support this functionality. Setup + * is always manual, or it is a decoder which does not + * support setting AVCodecContext.hw_frames_ctx at all, + * or it is a software format. + * AVERROR(EINVAL): it is known that hardware decoding is not supported for + * this configuration, or the device_ref is not supported + * for the hwaccel referenced by hw_pix_fmt. + */ +int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, + AVBufferRef *device_ref, + enum AVPixelFormat hw_pix_fmt, + AVBufferRef **out_frames_ref); + +enum AVCodecConfig { + AV_CODEC_CONFIG_PIX_FORMAT, ///< AVPixelFormat, terminated by AV_PIX_FMT_NONE + AV_CODEC_CONFIG_FRAME_RATE, ///< AVRational, terminated by {0, 0} + AV_CODEC_CONFIG_SAMPLE_RATE, ///< int, terminated by 0 + AV_CODEC_CONFIG_SAMPLE_FORMAT, ///< AVSampleFormat, terminated by AV_SAMPLE_FMT_NONE + AV_CODEC_CONFIG_CHANNEL_LAYOUT, ///< AVChannelLayout, terminated by {0} + AV_CODEC_CONFIG_COLOR_RANGE, ///< AVColorRange, terminated by AVCOL_RANGE_UNSPECIFIED + AV_CODEC_CONFIG_COLOR_SPACE, ///< AVColorSpace, terminated by AVCOL_SPC_UNSPECIFIED + AV_CODEC_CONFIG_ALPHA_MODE, ///< AVAlphaMode, terminated by AVALPHA_MODE_UNSPECIFIED +}; + +/** + * Retrieve a list of all supported values for a given configuration type. + * + * @param avctx An optional context to use. Values such as + * `strict_std_compliance` may affect the result. If NULL, + * default values are used. + * @param codec The codec to query, or NULL to use avctx->codec. + * @param config The configuration to query. + * @param flags Currently unused; should be set to zero. + * @param out_configs On success, set to a list of configurations, terminated + * by a config-specific terminator, or NULL if all + * possible values are supported. + * @param out_num_configs On success, set to the number of elements in + *out_configs, excluding the terminator. Optional. + */ +int avcodec_get_supported_config(const AVCodecContext *avctx, + const AVCodec *codec, enum AVCodecConfig config, + unsigned flags, const void **out_configs, + int *out_num_configs); + + + +/** + * @defgroup lavc_parsing Frame parsing + * @{ + */ + +enum AVPictureStructure { + AV_PICTURE_STRUCTURE_UNKNOWN, ///< unknown + AV_PICTURE_STRUCTURE_TOP_FIELD, ///< coded as top field + AV_PICTURE_STRUCTURE_BOTTOM_FIELD, ///< coded as bottom field + AV_PICTURE_STRUCTURE_FRAME, ///< coded as frame +}; + +typedef struct AVCodecParserContext { + void *priv_data; + const struct AVCodecParser *parser; + int64_t frame_offset; /* offset of the current frame */ + int64_t cur_offset; /* current offset + (incremented by each av_parser_parse()) */ + int64_t next_frame_offset; /* offset of the next frame */ + /* video info */ + int pict_type; /* XXX: Put it back in AVCodecContext. */ + /** + * This field is used for proper frame duration computation in lavf. + * It signals, how much longer the frame duration of the current frame + * is compared to normal frame duration. + * + * frame_duration = (1 + repeat_pict) * time_base + * + * It is used by codecs like H.264 to display telecined material. + */ + int repeat_pict; /* XXX: Put it back in AVCodecContext. */ + int64_t pts; /* pts of the current frame */ + int64_t dts; /* dts of the current frame */ + + /* private data */ + int64_t last_pts; + int64_t last_dts; + int fetch_timestamp; + +#define AV_PARSER_PTS_NB 4 + int cur_frame_start_index; + int64_t cur_frame_offset[AV_PARSER_PTS_NB]; + int64_t cur_frame_pts[AV_PARSER_PTS_NB]; + int64_t cur_frame_dts[AV_PARSER_PTS_NB]; + + int flags; +#define PARSER_FLAG_COMPLETE_FRAMES 0x0001 +#define PARSER_FLAG_ONCE 0x0002 +/// Set if the parser has a valid file offset +#define PARSER_FLAG_FETCHED_OFFSET 0x0004 +#define PARSER_FLAG_USE_CODEC_TS 0x1000 + + int64_t offset; ///< byte offset from starting packet start + int64_t cur_frame_end[AV_PARSER_PTS_NB]; + + /** + * Set by parser to 1 for key frames and 0 for non-key frames. + * It is initialized to -1, so if the parser doesn't set this flag, + * old-style fallback using AV_PICTURE_TYPE_I picture type as key frames + * will be used. + */ + int key_frame; + + // Timestamp generation support: + /** + * Synchronization point for start of timestamp generation. + * + * Set to >0 for sync point, 0 for no sync point and <0 for undefined + * (default). + * + * For example, this corresponds to presence of H.264 buffering period + * SEI message. + */ + int dts_sync_point; + + /** + * Offset of the current timestamp against last timestamp sync point in + * units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain a valid timestamp offset. + * + * Note that the timestamp of sync point has usually a nonzero + * dts_ref_dts_delta, which refers to the previous sync point. Offset of + * the next frame after timestamp sync point will be usually 1. + * + * For example, this corresponds to H.264 cpb_removal_delay. + */ + int dts_ref_dts_delta; + + /** + * Presentation delay of current frame in units of AVCodecContext.time_base. + * + * Set to INT_MIN when dts_sync_point unused. Otherwise, it must + * contain valid non-negative timestamp delta (presentation time of a frame + * must not lie in the past). + * + * This delay represents the difference between decoding and presentation + * time of the frame. + * + * For example, this corresponds to H.264 dpb_output_delay. + */ + int pts_dts_delta; + + /** + * Position of the packet in file. + * + * Analogous to cur_frame_pts/dts + */ + int64_t cur_frame_pos[AV_PARSER_PTS_NB]; + + /** + * Byte position of currently parsed frame in stream. + */ + int64_t pos; + + /** + * Previous frame byte position. + */ + int64_t last_pos; + + /** + * Duration of the current frame. + * For audio, this is in units of 1 / AVCodecContext.sample_rate. + * For all other types, this is in units of AVCodecContext.time_base. + */ + int duration; + + enum AVFieldOrder field_order; + + /** + * Indicate whether a picture is coded as a frame, top field or bottom field. + * + * For example, H.264 field_pic_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_FRAME. An H.264 picture with field_pic_flag + * equal to 1 and bottom_field_flag equal to 0 corresponds to + * AV_PICTURE_STRUCTURE_TOP_FIELD. + */ + enum AVPictureStructure picture_structure; + + /** + * Picture number incremented in presentation or output order. + * This field may be reinitialized at the first picture of a new sequence. + * + * For example, this corresponds to H.264 PicOrderCnt. + */ + int output_picture_number; + + /** + * Dimensions of the decoded video intended for presentation. + */ + int width; + int height; + + /** + * Dimensions of the coded video. + */ + int coded_width; + int coded_height; + + /** + * The format of the coded data, corresponds to enum AVPixelFormat for video + * and for enum AVSampleFormat for audio. + * + * Note that a decoder can have considerable freedom in how exactly it + * decodes the data, so the format reported here might be different from the + * one returned by a decoder. + */ + int format; +} AVCodecParserContext; + +typedef struct AVCodecParser { + enum AVCodecID codec_ids[7]; /* several codec IDs are permitted */ +} AVCodecParser; + +/** + * Iterate over all registered codec parsers. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec parser or NULL when the iteration is + * finished + */ +const AVCodecParser *av_parser_iterate(void **opaque); + +AVCodecParserContext *av_parser_init(enum AVCodecID codec_id); + +/** + * Parse a packet. + * + * @param s parser context. + * @param avctx codec context. + * @param poutbuf set to pointer to parsed buffer or NULL if not yet finished. + * @param poutbuf_size set to size of parsed buffer or zero if not yet finished. + * @param buf input buffer. + * @param buf_size buffer size in bytes without the padding. I.e. the full buffer + size is assumed to be buf_size + AV_INPUT_BUFFER_PADDING_SIZE. + To signal EOF, this should be 0 (so that the last frame + can be output). + * @param pts input presentation timestamp. + * @param dts input decoding timestamp. + * @param pos input byte position in stream. + * @return the number of bytes of the input bitstream used. + * + * Example: + * @code + * while(in_len){ + * len = av_parser_parse2(myparser, AVCodecContext, &data, &size, + * in_data, in_len, + * pts, dts, pos); + * in_data += len; + * in_len -= len; + * + * if(size) + * decode_frame(data, size); + * } + * @endcode + */ +int av_parser_parse2(AVCodecParserContext *s, + AVCodecContext *avctx, + uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size, + int64_t pts, int64_t dts, + int64_t pos); + +void av_parser_close(AVCodecParserContext *s); + +/** + * @} + * @} + */ + +/** + * @addtogroup lavc_encoding + * @{ + */ + +int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, + const AVSubtitle *sub); + + +/** + * @} + */ + +/** + * @defgroup lavc_misc Utility functions + * @ingroup libavc + * + * Miscellaneous utility functions related to both encoding and decoding + * (or neither). + * @{ + */ + +/** + * @defgroup lavc_misc_pixfmt Pixel formats + * + * Functions for working with pixel formats. + * @{ + */ + +/** + * Return a value representing the fourCC code associated to the + * pixel format pix_fmt, or 0 if no associated fourCC code can be + * found. + */ +unsigned int avcodec_pix_fmt_to_codec_tag(enum AVPixelFormat pix_fmt); + +/** + * Find the best pixel format to convert to given a certain source pixel + * format. 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. avcodec_find_best_pix_fmt_of_2() searches which of + * the given pixel formats should be used to suffer the least amount of loss. + * The pixel formats from which it chooses one, are determined by the + * pix_fmt_list parameter. + * + * + * @param[in] pix_fmt_list AV_PIX_FMT_NONE terminated array of pixel formats to choose from + * @param[in] src_pix_fmt source pixel format + * @param[in] has_alpha Whether the source pixel format alpha channel is used. + * @param[out] loss_ptr Combination of flags informing you what kind of losses will occur. + * @return The best pixel format to convert to or -1 if none was found. + */ +enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *pix_fmt_list, + enum AVPixelFormat src_pix_fmt, + int has_alpha, int *loss_ptr); + +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat * fmt); + +/** + * @} + */ + +void avcodec_string(char *buf, int buf_size, AVCodecContext *enc, int encode); + +int avcodec_default_execute(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2),void *arg, int *ret, int count, int size); +int avcodec_default_execute2(AVCodecContext *c, int (*func)(AVCodecContext *c2, void *arg2, int, int),void *arg, int *ret, int count); +//FIXME func typedef + +/** + * Fill AVFrame audio data and linesize pointers. + * + * The buffer buf must be a preallocated buffer with a size big enough + * to contain the specified samples amount. The filled AVFrame data + * pointers will point to this buffer. + * + * AVFrame extended_data channel pointers are allocated if necessary for + * planar audio. + * + * @param frame the AVFrame + * frame->nb_samples must be set prior to calling the + * function. This function fills in frame->data, + * frame->extended_data, frame->linesize[0]. + * @param nb_channels channel count + * @param sample_fmt sample format + * @param buf buffer to use for frame data + * @param buf_size size of buffer + * @param align plane size sample alignment (0 = default) + * @return >=0 on success, negative error code on failure + * @todo return the size in bytes required to store the samples in + * case of success, at the next libavutil bump + */ +int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, + enum AVSampleFormat sample_fmt, const uint8_t *buf, + int buf_size, int align); + +/** + * Reset the internal codec state / flush internal buffers. Should be called + * e.g. when seeking or when switching to a different stream. + * + * @note for decoders, this function just releases any references the decoder + * might keep internally, but the caller's references remain valid. + * + * @note for encoders, this function will only do something if the encoder + * declares support for AV_CODEC_CAP_ENCODER_FLUSH. When called, the encoder + * will drain any remaining packets, and can then be reused for a different + * stream (as opposed to sending a null frame which will leave the encoder + * in a permanent EOF state after draining). This can be desirable if the + * cost of tearing down and replacing the encoder instance is high. + */ +void avcodec_flush_buffers(AVCodecContext *avctx); + +/** + * Return audio frame duration. + * + * @param avctx codec context + * @param frame_bytes size of the frame, or 0 if unknown + * @return frame duration, in samples, if known. 0 if not able to + * determine. + */ +int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes); + +/* memory */ + +/** + * Same behaviour av_fast_malloc but the buffer has additional + * AV_INPUT_BUFFER_PADDING_SIZE at the end which will always be 0. + * + * In addition the whole buffer will initially and after resizes + * be 0-initialized so that no uninitialized data will ever appear. + */ +void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Same behaviour av_fast_padded_malloc except that buffer will always + * be 0-initialized after call. + */ +void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * @return a positive value if s is open (i.e. avcodec_open2() was called on it), + * 0 otherwise. + */ +int avcodec_is_open(AVCodecContext *s); + +/** + * @} + */ + +#endif /* AVCODEC_AVCODEC_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h new file mode 100644 index 000000000..f110ba724 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h @@ -0,0 +1,91 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_AVDCT_H +#define AVCODEC_AVDCT_H + +#include +#include + +#include "libavutil/opt.h" + +/** + * AVDCT context. + * @note function pointers can be NULL if the specific features have been + * disabled at build time. + */ +typedef struct AVDCT { + const AVClass *av_class; + + void (*idct)(int16_t *block /* align 16 */); + + /** + * IDCT input permutation. + * Several optimized IDCTs need a permutated input (relative to the + * normal order of the reference IDCT). + * This permutation must be performed before the idct_put/add. + * Note, normally this can be merged with the zigzag/alternate scan
+ * An example to avoid confusion: + * - (->decode coeffs -> zigzag reorder -> dequant -> reference IDCT -> ...) + * - (x -> reference DCT -> reference IDCT -> x) + * - (x -> reference DCT -> simple_mmx_perm = idct_permutation + * -> simple_idct_mmx -> x) + * - (-> decode coeffs -> zigzag reorder -> simple_mmx_perm -> dequant + * -> simple_idct_mmx -> ...) + */ + uint8_t idct_permutation[64]; + + void (*fdct)(int16_t *block /* align 16 */); + + + /** + * DCT algorithm. + * must use AVOptions to set this field. + */ + int dct_algo; + + /** + * IDCT algorithm. + * must use AVOptions to set this field. + */ + int idct_algo; + + void (*get_pixels)(int16_t *block /* align 16 */, + const uint8_t *pixels /* align 8 */, + ptrdiff_t line_size); + + int bits_per_sample; + + void (*get_pixels_unaligned)(int16_t *block /* align 16 */, + const uint8_t *pixels, + ptrdiff_t line_size); +} AVDCT; + +/** + * Allocates a AVDCT context. + * This needs to be initialized with avcodec_dct_init() after optionally + * configuring it with AVOptions. + * + * To free it use av_free() + */ +AVDCT *avcodec_dct_alloc(void); +int avcodec_dct_init(AVDCT *); + +const AVClass *avcodec_dct_get_class(void); + +#endif /* AVCODEC_AVDCT_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h new file mode 100644 index 000000000..9bde9a41b --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h @@ -0,0 +1,708 @@ +/* + * Bitstream filters public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_BSF_H +#define AVCODEC_BSF_H + +#include "libavutil/dict.h" +#include "libavutil/log.h" +#include "libavutil/rational.h" + +#include "codec_id.h" +#include "codec_par.h" +#include "packet.h" + +/** + * @defgroup lavc_bsf Bitstream filters + * @ingroup libavc + * + * Bitstream filters transform encoded media data without decoding it. This + * allows e.g. manipulating various header values. Bitstream filters operate on + * @ref AVPacket "AVPackets". + * + * The bitstream filtering API is centered around two structures: + * AVBitStreamFilter and AVBSFContext. The former represents a bitstream filter + * in abstract, the latter a specific filtering process. Obtain an + * AVBitStreamFilter using av_bsf_get_by_name() or av_bsf_iterate(), then pass + * it to av_bsf_alloc() to create an AVBSFContext. Fill in the user-settable + * AVBSFContext fields, as described in its documentation, then call + * av_bsf_init() to prepare the filter context for use. + * + * Submit packets for filtering using av_bsf_send_packet(), obtain filtered + * results with av_bsf_receive_packet(). When no more input packets will be + * sent, submit a NULL AVPacket to signal the end of the stream to the filter. + * av_bsf_receive_packet() will then return trailing packets, if any are + * produced by the filter. + * + * Finally, free the filter context with av_bsf_free(). + * @{ + */ + +/** + * The bitstream filter state. + * + * This struct must be allocated with av_bsf_alloc() and freed with + * av_bsf_free(). + * + * The fields in the struct will only be changed (by the caller or by the + * filter) as described in their documentation, and are to be considered + * immutable otherwise. + */ +typedef struct AVBSFContext { + /** + * A class for logging and AVOptions + */ + const AVClass *av_class; + + /** + * The bitstream filter this context is an instance of. + */ + const struct AVBitStreamFilter *filter; + + /** + * Opaque filter-specific private data. If filter->priv_class is non-NULL, + * this is an AVOptions-enabled struct. + */ + void *priv_data; + + /** + * Parameters of the input stream. This field is allocated in + * av_bsf_alloc(), it needs to be filled by the caller before + * av_bsf_init(). + */ + AVCodecParameters *par_in; + + /** + * Parameters of the output stream. This field is allocated in + * av_bsf_alloc(), it is set by the filter in av_bsf_init(). + */ + AVCodecParameters *par_out; + + /** + * The timebase used for the timestamps of the input packets. Set by the + * caller before av_bsf_init(). + */ + AVRational time_base_in; + + /** + * The timebase used for the timestamps of the output packets. Set by the + * filter in av_bsf_init(). + */ + AVRational time_base_out; +} AVBSFContext; + +typedef struct AVBitStreamFilter { + const char *name; + + /** + * A list of codec ids supported by the filter, terminated by + * AV_CODEC_ID_NONE. + * May be NULL, in that case the bitstream filter works with any codec id. + */ + const enum AVCodecID *codec_ids; + + /** + * A class for the private data, used to declare bitstream filter private + * AVOptions. This field is NULL for bitstream filters that do not declare + * any options. + * + * If this field is non-NULL, the first member of the filter private data + * must be a pointer to AVClass, which will be set by libavcodec generic + * code to this class. + */ + const AVClass *priv_class; +} AVBitStreamFilter; + +/** + * @return a bitstream filter with the specified name or NULL if no such + * bitstream filter exists. + */ +const AVBitStreamFilter *av_bsf_get_by_name(const char *name); + +/** + * Iterate over all registered bitstream filters. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered bitstream filter or NULL when the iteration is + * finished + */ +const AVBitStreamFilter *av_bsf_iterate(void **opaque); + +/** + * Allocate a context for a given bitstream filter. The caller must fill in the + * context parameters as described in the documentation and then call + * av_bsf_init() before sending any data to the filter. + * + * @param filter the filter for which to allocate an instance. + * @param[out] ctx a pointer into which the pointer to the newly-allocated context + * will be written. It must be freed with av_bsf_free() after the + * filtering is done. + * + * @return 0 on success, a negative AVERROR code on failure + */ +int av_bsf_alloc(const AVBitStreamFilter *filter, AVBSFContext **ctx); + +/** + * Prepare the filter for use, after all the parameters and options have been + * set. + * + * @param ctx a AVBSFContext previously allocated with av_bsf_alloc() + */ +int av_bsf_init(AVBSFContext *ctx); + +/** + * Submit a packet for filtering. + * + * After sending each packet, the filter must be completely drained by calling + * av_bsf_receive_packet() repeatedly until it returns AVERROR(EAGAIN) or + * AVERROR_EOF. + * + * @param ctx an initialized AVBSFContext + * @param pkt the packet to filter. The bitstream filter will take ownership of + * the packet and reset the contents of pkt. pkt is not touched if an error occurs. + * If pkt is empty (i.e. NULL, or pkt->data is NULL and pkt->side_data_elems zero), + * it signals the end of the stream (i.e. no more non-empty packets will be sent; + * sending more empty packets does nothing) and will cause the filter to output + * any packets it may have buffered internally. + * + * @return + * - 0 on success. + * - AVERROR(EAGAIN) if packets need to be retrieved from the filter (using + * av_bsf_receive_packet()) before new input can be consumed. + * - Another negative AVERROR value if an error occurs. + */ +int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Retrieve a filtered packet. + * + * @param ctx an initialized AVBSFContext + * @param[out] pkt this struct will be filled with the contents of the filtered + * packet. It is owned by the caller and must be freed using + * av_packet_unref() when it is no longer needed. + * This parameter should be "clean" (i.e. freshly allocated + * with av_packet_alloc() or unreffed with av_packet_unref()) + * when this function is called. If this function returns + * successfully, the contents of pkt will be completely + * overwritten by the returned data. On failure, pkt is not + * touched. + * + * @return + * - 0 on success. + * - AVERROR(EAGAIN) if more packets need to be sent to the filter (using + * av_bsf_send_packet()) to get more output. + * - AVERROR_EOF if there will be no further output from the filter. + * - Another negative AVERROR value if an error occurs. + * + * @note one input packet may result in several output packets, so after sending + * a packet with av_bsf_send_packet(), this function needs to be called + * repeatedly until it stops returning 0. It is also possible for a filter to + * output fewer packets than were sent to it, so this function may return + * AVERROR(EAGAIN) immediately after a successful av_bsf_send_packet() call. + */ +int av_bsf_receive_packet(AVBSFContext *ctx, AVPacket *pkt); + +/** + * Reset the internal bitstream filter state. Should be called e.g. when seeking. + */ +void av_bsf_flush(AVBSFContext *ctx); + +/** + * Free a bitstream filter context and everything associated with it; write NULL + * into the supplied pointer. + */ +void av_bsf_free(AVBSFContext **ctx); + +/** + * Get the AVClass for AVBSFContext. It can be used in combination with + * AV_OPT_SEARCH_FAKE_OBJ for examining options. + * + * @see av_opt_find(). + */ +const AVClass *av_bsf_get_class(void); + +/** + * Structure for chain/list of bitstream filters. + * Empty list can be allocated by av_bsf_list_alloc(). + */ +typedef struct AVBSFList AVBSFList; + +/** + * Allocate empty list of bitstream filters. + * The list must be later freed by av_bsf_list_free() + * or finalized by av_bsf_list_finalize(). + * + * @return Pointer to @ref AVBSFList on success, NULL in case of failure + */ +AVBSFList *av_bsf_list_alloc(void); + +/** + * Free list of bitstream filters. + * + * @param lst Pointer to pointer returned by av_bsf_list_alloc() + */ +void av_bsf_list_free(AVBSFList **lst); + +/** + * Append bitstream filter to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf Filter context to be appended + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf); + +/** + * Construct new bitstream filter context given it's name and options + * and append it to the list of bitstream filters. + * + * @param lst List to append to + * @param bsf_name Name of the bitstream filter + * @param options Options for the bitstream filter, can be set to NULL + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary **options); +/** + * Finalize list of bitstream filters. + * + * This function will transform @ref AVBSFList to single @ref AVBSFContext, + * so the whole chain of bitstream filters can be treated as single filter + * freshly allocated by av_bsf_alloc(). + * If the call is successful, @ref AVBSFList structure is freed and lst + * will be set to NULL. In case of failure, caller is responsible for + * freeing the structure by av_bsf_list_free() + * + * @param lst Filter list structure to be transformed + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf); + +/** + * Parse string describing list of bitstream filters and create single + * @ref AVBSFContext describing the whole chain of bitstream filters. + * Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext freshly + * allocated by av_bsf_alloc(). + * + * @param str String describing chain of bitstream filters in format + * `bsf1[=opt1=val1:opt2=val2][,bsf2]` + * @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure + * representing the chain of bitstream filters + * + * @return >=0 on success, negative AVERROR in case of failure + */ +int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf); + +/** + * Get null/pass-through bitstream filter. + * + * @param[out] bsf Pointer to be set to new instance of pass-through bitstream filter + * + * @return + */ +int av_bsf_get_null_filter(AVBSFContext **bsf); + +/** + * @defgroup lavc_bsfgraph Bitstream filter graph + * Experimental graph-based API for bitstream filters. + * @{ + */ + +/** + * A link between two filters. This contains pointers to the source and + * destination filters between which this link exists, and the indexes of + * the pads involved. + */ +typedef struct AVBitStreamFilterLink AVBitStreamFilterLink; + +/** + * A filter pad used for either input or output. + */ +typedef struct AVBitStreamFilterPad AVBitStreamFilterPad; + +/** An instance of a filter */ +typedef struct AVBitStreamFilterContext { + /** + * A class for logging and AVOptions + */ + const AVClass *av_class; + + /** + * The bitstream filter this context is an instance of. + */ + const struct AVBitStreamFilter *filter; + + /** + * name of this filter instance + */ + char *name; + + AVBitStreamFilterPad *input_pads; ///< array of input pads + AVBitStreamFilterLink **inputs; ///< array of pointers to input links + unsigned nb_inputs; ///< number of input pads + + AVBitStreamFilterPad *output_pads; ///< array of output pads + AVBitStreamFilterLink **outputs; ///< array of pointers to output links + unsigned nb_outputs; ///< number of output pads + + /** + * Opaque filter-specific private data. If filter->priv_class is non-NULL, + * this is an AVOptions-enabled struct. + */ + void *priv_data; + + /** + * filtergraph this filter belongs to + */ + struct AVBitStreamFilterGraph *graph; +} AVBitStreamFilterContext; + +/** + * The number of the filter inputs is not determined just by the filter's static + * inputs. The filter might add additional inputs during initialization depending + * on the options supplied to it. + */ +#define AV_BSF_FLAG_DYNAMIC_INPUTS (1 << 0) +/** + * The number of the filter outputs is not determined just by the filter's static + * outputs. The filter might add additional outputs during initialization depending + * on the options supplied to it. + */ +#define AV_BSF_FLAG_DYNAMIC_OUTPUTS (1 << 1) +/** + * The filter is a "metadata" filter - it does not modify the packet data in any + * way. It may only affect the metadata (i.e. those fields copied by + * av_packet_copy_props()). + * + * More precisely, this means that the data of any packet output by the filter + * must be exactly equal to some packet that is received on one of its inputs. + * Furthermore, all packets produced on a given output must correspond to packet + * received on the same input and their order must be unchanged. + * Note that the filter may still drop or duplicate the frames. + */ +#define AV_BSF_FLAG_METADATA_ONLY (1 << 2) + +/** + * Get the name of an AVBitStreamFilterPad. + * + * @param pads an array of AVBitStreamFilterPads + * @param pad_idx index of the pad in the array; it is the caller's + * responsibility to ensure the index is valid + * + * @return name of the pad_idx'th pad in pads + */ +const char *av_bsf_pad_get_name(const AVBitStreamFilterPad *pads, int pad_idx); + +/** + * Get the codec ids supported by an AVBitStreamFilterPad. + * + * @param pads an array of AVBitStreamFilterPads + * @param pad_idx index of the pad in the array; it is the caller's + * responsibility to ensure the index is valid + * + * @return an array of AVCodecID terminated by AV_CODEC_ID_NONE, or NULL + * if the pad has no codec id constrains. + */ +const enum AVCodecID *av_bsf_pad_get_codec_ids(const AVBitStreamFilterPad *pads, int pad_idx); + +/** + * Link two filters together. + * + * @param src the source filter + * @param srcpad index of the output pad on the source filter + * @param dst the destination filter + * @param dstpad index of the input pad on the destination filter + * @return zero on success + */ +int av_bsf_link(AVBitStreamFilterContext *src, unsigned srcpad, + AVBitStreamFilterContext *dst, unsigned dstpad); + +/** + * Initialize a filter with the supplied parameters. + * + * @param ctx uninitialized filter context to initialize + * @param args Options to initialize the filter with. This must be a + * ':'-separated list of options in the 'key=value' form. + * May be NULL if the options have been set directly using the + * AVOptions API or there are no options that need to be set. + * @return 0 on success, a negative AVERROR on failure + */ +int av_bsf_init_str(AVBitStreamFilterContext *ctx, const char *args); + +/** + * Initialize a filter with the supplied dictionary of options. + * + * @param ctx uninitialized filter context to initialize + * @param options An AVDictionary filled with options for this filter. On + * return this parameter will be destroyed and replaced with + * a dict containing options that were not found. This dictionary + * must be freed by the caller. + * May be NULL, then this function is equivalent to + * av_bsf_init_str() with the second parameter set to NULL. + * @return 0 on success, a negative AVERROR on failure + * + * @note This function and av_bsf_init_str() do essentially the same thing, + * the difference is in manner in which the options are passed. It is up to the + * calling code to choose whichever is more preferable. The two functions also + * behave differently when some of the provided options are not declared as + * supported by the filter. In such a case, av_bsf_init_str() will fail, but + * this function will leave those extra options in the options AVDictionary and + * continue as usual. + */ +int av_bsf_init_dict(AVBitStreamFilterContext *ctx, AVDictionary **options); + +typedef struct AVBitStreamFilterGraph { + const AVClass *av_class; + + AVBitStreamFilterContext **filters; + + unsigned nb_filters; + + /** + * Sets the maximum number of buffered packets in the filtergraph combined. + * + * Zero means no limit. This field must be set before calling + * av_bsf_graph_config(). + */ + unsigned max_buffered_packets; +} AVBitStreamFilterGraph; + +/** + * Allocate a filter graph. + * + * @return the allocated filter graph on success or NULL. + */ +AVBitStreamFilterGraph *av_bsf_graph_alloc(void); + +/** + * Create a new filter instance in a filter graph. + * + * @param[out] filt_ctx A pointer into which the pointer to the newly-allocated context + * will be written on success. May be NULL. Note that it is also + * retrievable directly through AVBitStreamFilterGraph.filters or + * with @ref av_bsf_graph_get_filter(). + * @param[in] filter the filter to create an instance of + * @param[in] name Name to give to the new instance (will be copied to + * AVBitStreamFilterContext.name). This may be used by the caller to + * identify different filters, libavcodec itself assigns no semantics + * to this parameter. May be NULL. + * @param[in] graph graph in which the new filter will be used + * + * @note On failure and if filt_ctx is not NULL, *filt_ctx will be set to NULL. + * @return a negative AVERROR error code in case of failure, a non negative value otherwise + */ +int av_bsf_graph_alloc_filter(AVBitStreamFilterContext **filt_ctx, + const AVBitStreamFilter *filter, + const char *name, + AVBitStreamFilterGraph *graph); + +/** + * A convenience wrapper that allocates and initializes a filter in a single + * step. The filter instance is created from the filter filt and inited with the + * parameter args. + * + * @param[out] filt_ctx A pointer into which the pointer to the newly-allocated context + * will be written on success. May be NULL. Note that it is also + * retrievable directly through AVBitStreamFilterGraph.filters or + * with @ref av_bsf_graph_get_filter(). + * @param[in] name the instance name to give to the created filter instance + * @param[in] graph_ctx the filter graph + * @return a negative AVERROR error code in case of failure, a non negative value otherwise + * + * @note On failure and if filt_ctx is not NULL, *filt_ctx will be set to NULL. + * @warning Since the filter is initialized after this function successfully + * returns, you MUST NOT set any further options on it. If you need to + * do that, call ::av_bsf_graph_alloc_filter(), followed by setting + * the options, followed by ::av_bsf_init_dict() instead of this + * function. + */ +int av_bsf_graph_create_filter(AVBitStreamFilterContext **filt_ctx, + const AVBitStreamFilter *filt, + const char *name, AVDictionary **options, + AVBitStreamFilterGraph *graph_ctx); + +/** + * Get a filter instance identified by instance name from graph. + * + * @param graph filter graph to search through. + * @param name filter instance name (should be unique in the graph). + * @return the pointer to the found filter instance or NULL if it + * cannot be found. + */ +AVBitStreamFilterContext *av_bsf_graph_get_filter(AVBitStreamFilterGraph *graph, const char *name); + +/** + * Check validity and configure all the links and formats in the graph. + * + * @param graphctx the filter graph + * @param log_ctx context used for logging + * @return >= 0 in case of success, a negative AVERROR code otherwise + */ +int av_bsf_graph_config(AVBitStreamFilterGraph *graphctx, void *log_ctx); + +/** + * Get the index of the source filter in the filtergraph that reported needing + * input more urgently. + * + * @return the index value of a source filter in the filtergraph, or AVERROR(EOF) + * if no source is accepting more packets. + */ +int av_bsf_graph_source_needs_input(const AVBitStreamFilterGraph *graph); + +/** + * Free a graph, destroy its links, and set *graph to NULL. + * If *graph is NULL, do nothing. + */ +void av_bsf_graph_free(AVBitStreamFilterGraph **graph); + +/** + * @defgroup lavc_bsfgraph_source Packet source API + * + * The source filter is there to connect filter graphs to applications + * They have a single output, connected to the graph, and no input. + * Packets must be fed to it using av_bsf_source_add_packet(). + * @{ + */ + +enum { + /** + * Immediately push the packet to the output. + */ + AV_BSF_SOURCE_FLAG_PUSH = 1 << 0, + + /** + * Keep a reference to the packet. + */ + AV_BSF_SOURCE_FLAG_KEEP_REF = 1 << 1, +}; + +/** + * Initialize the source filter with the provided parameters. + * This function may be called multiple times, the later calls override the + * previous ones. Some of the parameters may also be set through AVOptions, then + * whatever method is used last takes precedence. + * + * @param ctx an instance of the source filter + * @param param the stream parameters. The packet later passed to this filter + * must conform to those parameters. All the allocated fields in + * param remain owned by the caller, libavcodec will make internal + * copies or references when necessary. + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_bsf_source_parameters_set(AVBitStreamFilterContext *ctx, const AVCodecParameters *par); + +/** + * Add a packet to the buffer source. + * + * By default, this function will take ownership of the reference(s) and reset + * the packet. This can be controlled using the flags. + * + * If this function returns an error, the input packet is not touched. + * + * @param buffer_src pointer to a source filter context + * @param packet a packet, or NULL to mark EOF + * @param flags a combination of AV_BSF_FLAG_* + * @return >= 0 in case of success, a negative AVERROR code + * in case of failure + */ +av_warn_unused_result +int av_bsf_source_add_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags); + +/** + * Returns 0 or a negative AVERROR code. Currently, this will only ever + * return AVERROR(EOF), to indicate that the buffer source has been closed, + * either as a result of av_bsf_source_close(), or because the downstream + * filter is no longer accepting new data. + */ +int av_bsf_source_get_status(AVBitStreamFilterContext *ctx); + +/** + * Close the source after EOF. + * + * This is similar to passing NULL to av_bsf_source_add_packet() + * except it takes the timestamp of the EOF, i.e. the timestamp of the end + * of the last packet. + */ +int av_bsf_source_close(AVBitStreamFilterContext *ctx, int64_t pts, unsigned flags); + +/** + * @} + */ + +/** + * @defgroup lavc_bsfgraph_sink Packet sink API + * @{ + * + * The sink filter is there to connect filter graphs to applications + * They have a single input, connected to the graph, and no output. + * Packets must be extracted using av_bsf_sink_get_packet(). + */ + +enum { + /** + * Tell av_buffersink_get_buffer_ref() to read video/samples buffer + * reference, but not remove it from the buffer. This is useful if you + * need only to read a video/samples buffer, without to fetch it. + */ + AV_BSF_SINK_FLAG_PEEK = 1 << 0, + + /** + * Tell av_bsf_sink_get_packet() not to request a packet from its input. + * If a packet is already buffered, it is read (and removed from the buffer), + * but if no packet is present, return AVERROR(EAGAIN). + */ + AV_BSF_SINK_FLAG_NO_REQUEST = 1 << 1, +}; + +/** + * Get a packet with filtered data from sink and put it in packet. + * + * @param ctx pointer to a sink filter context. + * @param packet pointer to an allocated packet that will be filled with data. + * The data must be freed using av_packet_unref() / av_packet_free() + * @param flags a combination of AV_BSF_SINK_FLAG_* flags + * + * @retval AVERROR(EAGAIN) output could not be produced. + * if AV_BSF_SINK_FLAG_NO_REQUEST was not set, + * @ref av_bsf_graph_needs_input can be called to + * know which source needs input more urgently. + * @retval >= 0 success + * @retval "another negative error code" legitimate error + */ +int av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags); + +AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx); +const AVCodecParameters *av_bsf_sink_get_parameters(const AVBitStreamFilterContext *ctx); + +/** + * @} + * + * @} + * + * @} + */ + +#endif // AVCODEC_BSF_H diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h new file mode 100644 index 000000000..0966d2e61 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h @@ -0,0 +1,345 @@ +/* + * AVCodec public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CODEC_H +#define AVCODEC_CODEC_H + +#include + +#include "libavutil/avutil.h" +#include "libavutil/hwcontext.h" +#include "libavutil/log.h" +#include "libavutil/pixfmt.h" + +#include "libavcodec/codec_id.h" + +/** + * @addtogroup lavc_core + * @{ + */ + +/** + * Decoder can use draw_horiz_band callback. + */ +#define AV_CODEC_CAP_DRAW_HORIZ_BAND (1 << 0) +/** + * Codec uses get_buffer() or get_encode_buffer() for allocating buffers and + * supports custom allocators. + * If not set, it might not use get_buffer() or get_encode_buffer() at all, or + * use operations that assume the buffer was allocated by + * avcodec_default_get_buffer2 or avcodec_default_get_encode_buffer. + */ +#define AV_CODEC_CAP_DR1 (1 << 1) +/** + * Encoder or decoder requires flushing with NULL input at the end in order to + * give the complete and correct output. + * + * NOTE: If this flag is not set, the codec is guaranteed to never be fed with + * with NULL data. The user can still send NULL data to the public encode + * or decode function, but libavcodec will not pass it along to the codec + * unless this flag is set. + * + * Decoders: + * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, + * avpkt->size=0 at the end to get the delayed data until the decoder no longer + * returns frames. + * + * Encoders: + * The encoder needs to be fed with NULL data at the end of encoding until the + * encoder no longer returns data. + * + * NOTE: For encoders implementing the AVCodec.encode2() function, setting this + * flag also means that the encoder must set the pts and duration for + * each output packet. If this flag is not set, the pts and duration will + * be determined by libavcodec from the input frame. + */ +#define AV_CODEC_CAP_DELAY (1 << 5) +/** + * Codec can be fed a final frame with a smaller size. + * This can be used to prevent truncation of the last audio samples. + */ +#define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) + +/** + * Codec is experimental and is thus avoided in favor of non experimental + * encoders + */ +#define AV_CODEC_CAP_EXPERIMENTAL (1 << 9) +/** + * Codec should fill in channel configuration and samplerate instead of container + */ +#define AV_CODEC_CAP_CHANNEL_CONF (1 << 10) +/** + * Codec supports frame-level multithreading. + */ +#define AV_CODEC_CAP_FRAME_THREADS (1 << 12) +/** + * Codec supports slice-based (or partition-based) multithreading. + */ +#define AV_CODEC_CAP_SLICE_THREADS (1 << 13) +/** + * Codec supports changed parameters at any point. + */ +#define AV_CODEC_CAP_PARAM_CHANGE (1 << 14) +/** + * Codec supports multithreading through a method other than slice- or + * frame-level multithreading. Typically this marks wrappers around + * multithreading-capable external libraries. + */ +#define AV_CODEC_CAP_OTHER_THREADS (1 << 15) +/** + * Audio encoder supports receiving a different number of samples in each call. + */ +#define AV_CODEC_CAP_VARIABLE_FRAME_SIZE (1 << 16) +/** + * Decoder is not a preferred choice for probing. + * This indicates that the decoder is not a good choice for probing. + * It could for example be an expensive to spin up hardware decoder, + * or it could simply not provide a lot of useful information about + * the stream. + * A decoder marked with this flag should only be used as last resort + * choice for probing. + */ +#define AV_CODEC_CAP_AVOID_PROBING (1 << 17) + +/** + * Codec is backed by a hardware implementation. Typically used to + * identify a non-hwaccel hardware decoder. For information about hwaccels, use + * avcodec_get_hw_config() instead. + */ +#define AV_CODEC_CAP_HARDWARE (1 << 18) + +/** + * Codec is potentially backed by a hardware implementation, but not + * necessarily. This is used instead of AV_CODEC_CAP_HARDWARE, if the + * implementation provides some sort of internal fallback. + */ +#define AV_CODEC_CAP_HYBRID (1 << 19) + +/** + * This encoder can reorder user opaque values from input AVFrames and return + * them with corresponding output packets. + * @see AV_CODEC_FLAG_COPY_OPAQUE + */ +#define AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE (1 << 20) + +/** + * This encoder can be flushed using avcodec_flush_buffers(). If this flag is + * not set, the encoder must be closed and reopened to ensure that no frames + * remain pending. + */ +#define AV_CODEC_CAP_ENCODER_FLUSH (1 << 21) + +/** + * The encoder is able to output reconstructed frame data, i.e. raw frames that + * would be produced by decoding the encoded bitstream. + * + * Reconstructed frame output is enabled by the AV_CODEC_FLAG_RECON_FRAME flag. + */ +#define AV_CODEC_CAP_ENCODER_RECON_FRAME (1 << 22) + +/** + * AVProfile. + */ +typedef struct AVProfile { + int profile; + const char *name; ///< short name for the profile +} AVProfile; + +/** + * AVCodec. + */ +typedef struct AVCodec { + /** + * Name of the codec implementation. + * The name is globally unique among encoders and among decoders (but an + * encoder and a decoder can share the same name). + * This is the primary way to find a codec from the user perspective. + */ + const char *name; + /** + * Descriptive name for the codec, meant to be more human readable than name. + * You should use the NULL_IF_CONFIG_SMALL() macro to define it. + */ + const char *long_name; + enum AVMediaType type; + enum AVCodecID id; + /** + * Codec capabilities. + * see AV_CODEC_CAP_* + */ + int capabilities; + uint8_t max_lowres; ///< maximum value for lowres supported by the decoder + + const AVClass *priv_class; ///< AVClass for the private context + const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN} + + /** + * Group name of the codec implementation. + * This is a short symbolic name of the wrapper backing this codec. A + * wrapper uses some kind of external implementation for the codec, such + * as an external library, or a codec implementation provided by the OS or + * the hardware. + * If this field is NULL, this is a builtin, libavcodec native codec. + * If non-NULL, this will be the suffix in AVCodec.name in most cases + * (usually AVCodec.name will be of the form "_"). + */ + const char *wrapper_name; +} AVCodec; + +/** + * Iterate over all registered codecs. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec or NULL when the iteration is + * finished + */ +const AVCodec *av_codec_iterate(void **opaque); + +/** + * Find a registered decoder with a matching codec ID. + * + * @param id AVCodecID of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +const AVCodec *avcodec_find_decoder(enum AVCodecID id); + +/** + * Find a registered decoder with the specified name. + * + * @param name name of the requested decoder + * @return A decoder if one was found, NULL otherwise. + */ +const AVCodec *avcodec_find_decoder_by_name(const char *name); + +/** + * Find a registered encoder with a matching codec ID. + * + * @param id AVCodecID of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +const AVCodec *avcodec_find_encoder(enum AVCodecID id); + +/** + * Find a registered encoder with the specified name. + * + * @param name name of the requested encoder + * @return An encoder if one was found, NULL otherwise. + */ +const AVCodec *avcodec_find_encoder_by_name(const char *name); +/** + * @return a non-zero number if codec is an encoder, zero otherwise + */ +int av_codec_is_encoder(const AVCodec *codec); + +/** + * @return a non-zero number if codec is a decoder, zero otherwise + */ +int av_codec_is_decoder(const AVCodec *codec); + +/** + * Return a name for the specified profile, if available. + * + * @param codec the codec that is searched for the given profile + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + */ +const char *av_get_profile_name(const AVCodec *codec, int profile); + +enum { + /** + * The codec supports this format via the hw_device_ctx interface. + * + * When selecting this format, AVCodecContext.hw_device_ctx should + * have been set to a device of the specified type before calling + * avcodec_open2(). + */ + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX = 0x01, + /** + * The codec supports this format via the hw_frames_ctx interface. + * + * When selecting this format for a decoder, + * AVCodecContext.hw_frames_ctx should be set to a suitable frames + * context inside the get_format() callback. The frames context + * must have been created on a device of the specified type. + * + * When selecting this format for an encoder, + * AVCodecContext.hw_frames_ctx should be set to the context which + * will be used for the input frames before calling avcodec_open2(). + */ + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX = 0x02, + /** + * The codec supports this format by some internal method. + * + * This format can be selected without any additional configuration - + * no device or frames context is required. + */ + AV_CODEC_HW_CONFIG_METHOD_INTERNAL = 0x04, + /** + * The codec supports this format by some ad-hoc method. + * + * Additional settings and/or function calls are required. See the + * codec-specific documentation for details. (Methods requiring + * this sort of configuration are deprecated and others should be + * used in preference.) + */ + AV_CODEC_HW_CONFIG_METHOD_AD_HOC = 0x08, +}; + +typedef struct AVCodecHWConfig { + /** + * For decoders, a hardware pixel format which that decoder may be + * able to decode to if suitable hardware is available. + * + * For encoders, a pixel format which the encoder may be able to + * accept. If set to AV_PIX_FMT_NONE, this applies to all pixel + * formats supported by the codec. + */ + enum AVPixelFormat pix_fmt; + /** + * Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible + * setup methods which can be used with this configuration. + */ + int methods; + /** + * The device type associated with the configuration. + * + * Must be set for AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX and + * AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, otherwise unused. + */ + enum AVHWDeviceType device_type; +} AVCodecHWConfig; + +/** + * Retrieve supported hardware configurations for a codec. + * + * Values of index from zero to some maximum return the indexed configuration + * descriptor; all other values return NULL. If the codec does not support + * any hardware configurations then it will always return NULL. + */ +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index); + +/** + * @} + */ + +#endif /* AVCODEC_CODEC_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h new file mode 100644 index 000000000..1186433c9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h @@ -0,0 +1,142 @@ +/* + * Codec descriptors public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CODEC_DESC_H +#define AVCODEC_CODEC_DESC_H + +#include "libavutil/avutil.h" + +#include "codec_id.h" + +/** + * @addtogroup lavc_core + * @{ + */ + +/** + * This struct describes the properties of a single codec described by an + * AVCodecID. + * @see avcodec_descriptor_get() + */ +typedef struct AVCodecDescriptor { + enum AVCodecID id; + enum AVMediaType type; + /** + * Name of the codec described by this descriptor. It is non-empty and + * unique for each codec descriptor. It should contain alphanumeric + * characters and '_' only. + */ + const char *name; + /** + * A more descriptive name for this codec. May be NULL. + */ + const char *long_name; + /** + * Codec properties, a combination of AV_CODEC_PROP_* flags. + */ + int props; + /** + * MIME type(s) associated with the codec. + * May be NULL; if not, a NULL-terminated array of MIME types. + * The first item is always non-NULL and is the preferred MIME type. + */ + const char *const *mime_types; + /** + * If non-NULL, an array of profiles recognized for this codec. + * Terminated with AV_PROFILE_UNKNOWN. + */ + const struct AVProfile *profiles; +} AVCodecDescriptor; + +/** + * Codec uses only intra compression. + * Video and audio codecs only. + */ +#define AV_CODEC_PROP_INTRA_ONLY (1 << 0) +/** + * Codec supports lossy compression. Audio and video codecs only. + * @note a codec may support both lossy and lossless + * compression modes + */ +#define AV_CODEC_PROP_LOSSY (1 << 1) +/** + * Codec supports lossless compression. Audio and video codecs only. + */ +#define AV_CODEC_PROP_LOSSLESS (1 << 2) +/** + * Codec supports frame reordering. That is, the coded order (the order in which + * the encoded packets are output by the encoders / stored / input to the + * decoders) may be different from the presentation order of the corresponding + * frames. + * + * For codecs that do not have this property set, PTS and DTS should always be + * equal. + */ +#define AV_CODEC_PROP_REORDER (1 << 3) + +/** + * Video codec supports separate coding of fields in interlaced frames. + */ +#define AV_CODEC_PROP_FIELDS (1 << 4) + +/** + * Video codec contains enhancement information meant to be applied to other + * existing frames, and can't generate usable image data on its own. + * A standalone decoder is unlikely to be available for it and should not + * be expected. + */ +#define AV_CODEC_PROP_ENHANCEMENT (1 << 5) + +/** + * Subtitle codec is bitmap based + * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. + */ +#define AV_CODEC_PROP_BITMAP_SUB (1 << 16) +/** + * Subtitle codec is text based. + * Decoded AVSubtitle data can be read from the AVSubtitleRect->ass field. + */ +#define AV_CODEC_PROP_TEXT_SUB (1 << 17) + +/** + * @return descriptor for given codec ID or NULL if no descriptor exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id); + +/** + * Iterate over all codec descriptors known to libavcodec. + * + * @param prev previous descriptor. NULL to get the first descriptor. + * + * @return next descriptor or NULL after the last descriptor + */ +const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev); + +/** + * @return codec descriptor with the given name or NULL if no such descriptor + * exists. + */ +const AVCodecDescriptor *avcodec_descriptor_get_by_name(const char *name); + +/** + * @} + */ + +#endif // AVCODEC_CODEC_DESC_H diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h new file mode 100644 index 000000000..7cafac610 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h @@ -0,0 +1,688 @@ +/* + * Codec IDs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CODEC_ID_H +#define AVCODEC_CODEC_ID_H + +#include "libavutil/avutil.h" +#include "libavutil/samplefmt.h" + +/** + * @addtogroup lavc_core + * @{ + */ + +/** + * Identify the syntax and semantics of the bitstream. + * The principle is roughly: + * Two decoders with the same ID can decode the same streams. + * Two encoders with the same ID can encode compatible streams. + * There may be slight deviations from the principle due to implementation + * details. + * + * If you add a codec ID to this list, add it so that + * 1. no value of an existing codec ID changes (that would break ABI), + * 2. it is as close as possible to similar codecs + * + * After adding new codec IDs, do not forget to add an entry to the codec + * descriptor list and bump libavcodec minor version. + */ +enum AVCodecID { + AV_CODEC_ID_NONE, + + /* video codecs */ + AV_CODEC_ID_MPEG1VIDEO, + AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding + AV_CODEC_ID_H261, + AV_CODEC_ID_H263, + AV_CODEC_ID_RV10, + AV_CODEC_ID_RV20, + AV_CODEC_ID_MJPEG, + AV_CODEC_ID_MJPEGB, + AV_CODEC_ID_LJPEG, + AV_CODEC_ID_SP5X, + AV_CODEC_ID_JPEGLS, + AV_CODEC_ID_MPEG4, + AV_CODEC_ID_RAWVIDEO, + AV_CODEC_ID_MSMPEG4V1, + AV_CODEC_ID_MSMPEG4V2, + AV_CODEC_ID_MSMPEG4V3, + AV_CODEC_ID_WMV1, + AV_CODEC_ID_WMV2, + AV_CODEC_ID_H263P, + AV_CODEC_ID_H263I, + AV_CODEC_ID_FLV1, + AV_CODEC_ID_SVQ1, + AV_CODEC_ID_SVQ3, + AV_CODEC_ID_DVVIDEO, + AV_CODEC_ID_HUFFYUV, + AV_CODEC_ID_CYUV, + AV_CODEC_ID_H264, + AV_CODEC_ID_INDEO3, + AV_CODEC_ID_VP3, + AV_CODEC_ID_THEORA, + AV_CODEC_ID_ASV1, + AV_CODEC_ID_ASV2, + AV_CODEC_ID_FFV1, + AV_CODEC_ID_4XM, + AV_CODEC_ID_VCR1, + AV_CODEC_ID_CLJR, + AV_CODEC_ID_MDEC, + AV_CODEC_ID_ROQ, + AV_CODEC_ID_INTERPLAY_VIDEO, + AV_CODEC_ID_XAN_WC3, + AV_CODEC_ID_XAN_WC4, + AV_CODEC_ID_RPZA, + AV_CODEC_ID_CINEPAK, + AV_CODEC_ID_WS_VQA, + AV_CODEC_ID_MSRLE, + AV_CODEC_ID_MSVIDEO1, + AV_CODEC_ID_IDCIN, + AV_CODEC_ID_8BPS, + AV_CODEC_ID_SMC, + AV_CODEC_ID_FLIC, + AV_CODEC_ID_TRUEMOTION1, + AV_CODEC_ID_VMDVIDEO, + AV_CODEC_ID_MSZH, + AV_CODEC_ID_ZLIB, + AV_CODEC_ID_QTRLE, + AV_CODEC_ID_TSCC, + AV_CODEC_ID_ULTI, + AV_CODEC_ID_QDRAW, + AV_CODEC_ID_VIXL, + AV_CODEC_ID_QPEG, + AV_CODEC_ID_PNG, + AV_CODEC_ID_PPM, + AV_CODEC_ID_PBM, + AV_CODEC_ID_PGM, + AV_CODEC_ID_PGMYUV, + AV_CODEC_ID_PAM, + AV_CODEC_ID_FFVHUFF, + AV_CODEC_ID_RV30, + AV_CODEC_ID_RV40, + AV_CODEC_ID_VC1, + AV_CODEC_ID_WMV3, + AV_CODEC_ID_LOCO, + AV_CODEC_ID_WNV1, + AV_CODEC_ID_AASC, + AV_CODEC_ID_INDEO2, + AV_CODEC_ID_FRAPS, + AV_CODEC_ID_TRUEMOTION2, + AV_CODEC_ID_BMP, + AV_CODEC_ID_CSCD, + AV_CODEC_ID_MMVIDEO, + AV_CODEC_ID_ZMBV, + AV_CODEC_ID_AVS, + AV_CODEC_ID_SMACKVIDEO, + AV_CODEC_ID_NUV, + AV_CODEC_ID_KMVC, + AV_CODEC_ID_FLASHSV, + AV_CODEC_ID_CAVS, + AV_CODEC_ID_JPEG2000, + AV_CODEC_ID_VMNC, + AV_CODEC_ID_VP5, + AV_CODEC_ID_VP6, + AV_CODEC_ID_VP6F, + AV_CODEC_ID_TARGA, + AV_CODEC_ID_DSICINVIDEO, + AV_CODEC_ID_TIERTEXSEQVIDEO, + AV_CODEC_ID_TIFF, + AV_CODEC_ID_GIF, + AV_CODEC_ID_DXA, + AV_CODEC_ID_DNXHD, + AV_CODEC_ID_THP, + AV_CODEC_ID_SGI, + AV_CODEC_ID_C93, + AV_CODEC_ID_BETHSOFTVID, + AV_CODEC_ID_PTX, + AV_CODEC_ID_TXD, + AV_CODEC_ID_VP6A, + AV_CODEC_ID_AMV, + AV_CODEC_ID_VB, + AV_CODEC_ID_PCX, + AV_CODEC_ID_SUNRAST, + AV_CODEC_ID_INDEO4, + AV_CODEC_ID_INDEO5, + AV_CODEC_ID_MIMIC, + AV_CODEC_ID_RL2, + AV_CODEC_ID_ESCAPE124, + AV_CODEC_ID_DIRAC, + AV_CODEC_ID_BFI, + AV_CODEC_ID_CMV, + AV_CODEC_ID_MOTIONPIXELS, + AV_CODEC_ID_TGV, + AV_CODEC_ID_TGQ, + AV_CODEC_ID_TQI, + AV_CODEC_ID_AURA, + AV_CODEC_ID_AURA2, + AV_CODEC_ID_V210X, + AV_CODEC_ID_TMV, + AV_CODEC_ID_V210, + AV_CODEC_ID_DPX, + AV_CODEC_ID_MAD, + AV_CODEC_ID_FRWU, + AV_CODEC_ID_FLASHSV2, + AV_CODEC_ID_CDGRAPHICS, + AV_CODEC_ID_R210, + AV_CODEC_ID_ANM, + AV_CODEC_ID_BINKVIDEO, + AV_CODEC_ID_IFF_ILBM, +#define AV_CODEC_ID_IFF_BYTERUN1 AV_CODEC_ID_IFF_ILBM + AV_CODEC_ID_KGV1, + AV_CODEC_ID_YOP, + AV_CODEC_ID_VP8, + AV_CODEC_ID_PICTOR, + AV_CODEC_ID_ANSI, + AV_CODEC_ID_A64_MULTI, + AV_CODEC_ID_A64_MULTI5, + AV_CODEC_ID_R10K, + AV_CODEC_ID_MXPEG, + AV_CODEC_ID_LAGARITH, + AV_CODEC_ID_PRORES, + AV_CODEC_ID_JV, + AV_CODEC_ID_DFA, + AV_CODEC_ID_WMV3IMAGE, + AV_CODEC_ID_VC1IMAGE, + AV_CODEC_ID_UTVIDEO, + AV_CODEC_ID_BMV_VIDEO, + AV_CODEC_ID_VBLE, + AV_CODEC_ID_DXTORY, + AV_CODEC_ID_XWD, + AV_CODEC_ID_CDXL, + AV_CODEC_ID_XBM, + AV_CODEC_ID_ZEROCODEC, + AV_CODEC_ID_MSS1, + AV_CODEC_ID_MSA1, + AV_CODEC_ID_TSCC2, + AV_CODEC_ID_MTS2, + AV_CODEC_ID_CLLC, + AV_CODEC_ID_MSS2, + AV_CODEC_ID_VP9, + AV_CODEC_ID_AIC, + AV_CODEC_ID_ESCAPE130, + AV_CODEC_ID_G2M, + AV_CODEC_ID_WEBP, + AV_CODEC_ID_HNM4_VIDEO, + AV_CODEC_ID_HEVC, +#define AV_CODEC_ID_H265 AV_CODEC_ID_HEVC + AV_CODEC_ID_FIC, + AV_CODEC_ID_ALIAS_PIX, + AV_CODEC_ID_BRENDER_PIX, + AV_CODEC_ID_PAF_VIDEO, + AV_CODEC_ID_EXR, + AV_CODEC_ID_VP7, + AV_CODEC_ID_SANM, + AV_CODEC_ID_SGIRLE, + AV_CODEC_ID_MVC1, + AV_CODEC_ID_MVC2, + AV_CODEC_ID_HQX, + AV_CODEC_ID_TDSC, + AV_CODEC_ID_HQ_HQA, + AV_CODEC_ID_HAP, + AV_CODEC_ID_DDS, + AV_CODEC_ID_DXV, + AV_CODEC_ID_SCREENPRESSO, + AV_CODEC_ID_RSCC, + AV_CODEC_ID_AVS2, + AV_CODEC_ID_PGX, + AV_CODEC_ID_AVS3, + AV_CODEC_ID_MSP2, + AV_CODEC_ID_VVC, +#define AV_CODEC_ID_H266 AV_CODEC_ID_VVC + AV_CODEC_ID_Y41P, + AV_CODEC_ID_AVRP, + AV_CODEC_ID_012V, + AV_CODEC_ID_AVUI, + AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_YUV4, + AV_CODEC_ID_AVRN, + AV_CODEC_ID_CPIA, + AV_CODEC_ID_XFACE, + AV_CODEC_ID_SNOW, + AV_CODEC_ID_SMVJPEG, + AV_CODEC_ID_APNG, + AV_CODEC_ID_DAALA, + AV_CODEC_ID_CFHD, + AV_CODEC_ID_TRUEMOTION2RT, + AV_CODEC_ID_M101, + AV_CODEC_ID_MAGICYUV, + AV_CODEC_ID_SHEERVIDEO, + AV_CODEC_ID_YLC, + AV_CODEC_ID_PSD, + AV_CODEC_ID_PIXLET, + AV_CODEC_ID_SPEEDHQ, + AV_CODEC_ID_FMVC, + AV_CODEC_ID_SCPR, + AV_CODEC_ID_CLEARVIDEO, + AV_CODEC_ID_XPM, + AV_CODEC_ID_AV1, + AV_CODEC_ID_BITPACKED, + AV_CODEC_ID_MSCC, + AV_CODEC_ID_SRGC, + AV_CODEC_ID_SVG, + AV_CODEC_ID_GDV, + AV_CODEC_ID_FITS, + AV_CODEC_ID_IMM4, + AV_CODEC_ID_PROSUMER, + AV_CODEC_ID_MWSC, + AV_CODEC_ID_WCMV, + AV_CODEC_ID_RASC, + AV_CODEC_ID_HYMT, + AV_CODEC_ID_ARBC, + AV_CODEC_ID_AGM, + AV_CODEC_ID_LSCR, + AV_CODEC_ID_VP4, + AV_CODEC_ID_IMM5, + AV_CODEC_ID_MVDV, + AV_CODEC_ID_MVHA, + AV_CODEC_ID_CDTOONS, + AV_CODEC_ID_MV30, + AV_CODEC_ID_NOTCHLC, + AV_CODEC_ID_PFM, + AV_CODEC_ID_MOBICLIP, + AV_CODEC_ID_PHOTOCD, + AV_CODEC_ID_IPU, + AV_CODEC_ID_ARGO, + AV_CODEC_ID_CRI, + AV_CODEC_ID_SIMBIOSIS_IMX, + AV_CODEC_ID_SGA_VIDEO, + AV_CODEC_ID_GEM, + AV_CODEC_ID_VBN, + AV_CODEC_ID_JPEGXL, + AV_CODEC_ID_QOI, + AV_CODEC_ID_PHM, + AV_CODEC_ID_RADIANCE_HDR, + AV_CODEC_ID_WBMP, + AV_CODEC_ID_MEDIA100, + AV_CODEC_ID_VQC, + AV_CODEC_ID_PDV, + AV_CODEC_ID_EVC, + AV_CODEC_ID_RTV1, + AV_CODEC_ID_VMIX, + AV_CODEC_ID_LEAD, + AV_CODEC_ID_DNXUC, + AV_CODEC_ID_RV60, + AV_CODEC_ID_JPEGXL_ANIM, + AV_CODEC_ID_APV, + AV_CODEC_ID_PRORES_RAW, + AV_CODEC_ID_JPEGXS, + AV_CODEC_ID_WEBP_ANIM, + + /* various PCM "codecs" */ + AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs + AV_CODEC_ID_PCM_S16LE = 0x10000, + AV_CODEC_ID_PCM_S16BE, + AV_CODEC_ID_PCM_U16LE, + AV_CODEC_ID_PCM_U16BE, + AV_CODEC_ID_PCM_S8, + AV_CODEC_ID_PCM_U8, + AV_CODEC_ID_PCM_MULAW, + AV_CODEC_ID_PCM_ALAW, + AV_CODEC_ID_PCM_S32LE, + AV_CODEC_ID_PCM_S32BE, + AV_CODEC_ID_PCM_U32LE, + AV_CODEC_ID_PCM_U32BE, + AV_CODEC_ID_PCM_S24LE, + AV_CODEC_ID_PCM_S24BE, + AV_CODEC_ID_PCM_U24LE, + AV_CODEC_ID_PCM_U24BE, + AV_CODEC_ID_PCM_S24DAUD, + AV_CODEC_ID_PCM_ZORK, + AV_CODEC_ID_PCM_S16LE_PLANAR, + AV_CODEC_ID_PCM_DVD, + AV_CODEC_ID_PCM_F32BE, + AV_CODEC_ID_PCM_F32LE, + AV_CODEC_ID_PCM_F64BE, + AV_CODEC_ID_PCM_F64LE, + AV_CODEC_ID_PCM_BLURAY, + AV_CODEC_ID_PCM_LXF, + AV_CODEC_ID_S302M, + AV_CODEC_ID_PCM_S8_PLANAR, + AV_CODEC_ID_PCM_S24LE_PLANAR, + AV_CODEC_ID_PCM_S32LE_PLANAR, + AV_CODEC_ID_PCM_S16BE_PLANAR, + AV_CODEC_ID_PCM_S64LE, + AV_CODEC_ID_PCM_S64BE, + AV_CODEC_ID_PCM_F16LE, + AV_CODEC_ID_PCM_F24LE, + AV_CODEC_ID_PCM_VIDC, + AV_CODEC_ID_PCM_SGA, + AV_CODEC_ID_PCM_DVDA, + + /* various ADPCM codecs */ + AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, + AV_CODEC_ID_ADPCM_IMA_WAV, + AV_CODEC_ID_ADPCM_IMA_DK3, + AV_CODEC_ID_ADPCM_IMA_DK4, + AV_CODEC_ID_ADPCM_IMA_WS, + AV_CODEC_ID_ADPCM_IMA_SMJPEG, + AV_CODEC_ID_ADPCM_MS, + AV_CODEC_ID_ADPCM_4XM, + AV_CODEC_ID_ADPCM_XA, + AV_CODEC_ID_ADPCM_ADX, + AV_CODEC_ID_ADPCM_EA, + AV_CODEC_ID_ADPCM_G726, + AV_CODEC_ID_ADPCM_CT, + AV_CODEC_ID_ADPCM_SWF, + AV_CODEC_ID_ADPCM_YAMAHA, + AV_CODEC_ID_ADPCM_SBPRO_4, + AV_CODEC_ID_ADPCM_SBPRO_3, + AV_CODEC_ID_ADPCM_SBPRO_2, + AV_CODEC_ID_ADPCM_THP, + AV_CODEC_ID_ADPCM_IMA_AMV, + AV_CODEC_ID_ADPCM_EA_R1, + AV_CODEC_ID_ADPCM_EA_R3, + AV_CODEC_ID_ADPCM_EA_R2, + AV_CODEC_ID_ADPCM_IMA_EA_SEAD, + AV_CODEC_ID_ADPCM_IMA_EA_EACS, + AV_CODEC_ID_ADPCM_EA_XAS, + AV_CODEC_ID_ADPCM_EA_MAXIS_XA, + AV_CODEC_ID_ADPCM_IMA_ISS, + AV_CODEC_ID_ADPCM_G722, + AV_CODEC_ID_ADPCM_IMA_APC, + AV_CODEC_ID_ADPCM_VIMA, + AV_CODEC_ID_ADPCM_AFC, + AV_CODEC_ID_ADPCM_IMA_OKI, + AV_CODEC_ID_ADPCM_DTK, + AV_CODEC_ID_ADPCM_IMA_RAD, + AV_CODEC_ID_ADPCM_G726LE, + AV_CODEC_ID_ADPCM_THP_LE, + AV_CODEC_ID_ADPCM_PSX, + AV_CODEC_ID_ADPCM_AICA, + AV_CODEC_ID_ADPCM_IMA_DAT4, + AV_CODEC_ID_ADPCM_MTAF, + AV_CODEC_ID_ADPCM_AGM, + AV_CODEC_ID_ADPCM_ARGO, + AV_CODEC_ID_ADPCM_IMA_SSI, + AV_CODEC_ID_ADPCM_ZORK, + AV_CODEC_ID_ADPCM_IMA_APM, + AV_CODEC_ID_ADPCM_IMA_ALP, + AV_CODEC_ID_ADPCM_IMA_MTF, + AV_CODEC_ID_ADPCM_IMA_CUNNING, + AV_CODEC_ID_ADPCM_IMA_MOFLEX, + AV_CODEC_ID_ADPCM_IMA_ACORN, + AV_CODEC_ID_ADPCM_XMD, + AV_CODEC_ID_ADPCM_IMA_XBOX, + AV_CODEC_ID_ADPCM_SANYO, + AV_CODEC_ID_ADPCM_IMA_HVQM4, + AV_CODEC_ID_ADPCM_IMA_PDA, + AV_CODEC_ID_ADPCM_N64, + AV_CODEC_ID_ADPCM_IMA_HVQM2, + AV_CODEC_ID_ADPCM_IMA_MAGIX, + AV_CODEC_ID_ADPCM_PSXC, + AV_CODEC_ID_ADPCM_CIRCUS, + AV_CODEC_ID_ADPCM_IMA_ESCAPE, + + /* AMR */ + AV_CODEC_ID_AMR_NB = 0x12000, + AV_CODEC_ID_AMR_WB, + + /* RealAudio codecs*/ + AV_CODEC_ID_RA_144 = 0x13000, + AV_CODEC_ID_RA_288, + + /* various DPCM codecs */ + AV_CODEC_ID_ROQ_DPCM = 0x14000, + AV_CODEC_ID_INTERPLAY_DPCM, + AV_CODEC_ID_XAN_DPCM, + AV_CODEC_ID_SOL_DPCM, + AV_CODEC_ID_SDX2_DPCM, + AV_CODEC_ID_GREMLIN_DPCM, + AV_CODEC_ID_DERF_DPCM, + AV_CODEC_ID_WADY_DPCM, + AV_CODEC_ID_CBD2_DPCM, + + /* audio codecs */ + AV_CODEC_ID_MP2 = 0x15000, + AV_CODEC_ID_MP3, ///< preferred ID for decoding MPEG audio layer 1, 2 or 3 + AV_CODEC_ID_AAC, + AV_CODEC_ID_AC3, + AV_CODEC_ID_DTS, + AV_CODEC_ID_VORBIS, + AV_CODEC_ID_DVAUDIO, + AV_CODEC_ID_WMAV1, + AV_CODEC_ID_WMAV2, + AV_CODEC_ID_MACE3, + AV_CODEC_ID_MACE6, + AV_CODEC_ID_VMDAUDIO, + AV_CODEC_ID_FLAC, + AV_CODEC_ID_MP3ADU, + AV_CODEC_ID_MP3ON4, + AV_CODEC_ID_SHORTEN, + AV_CODEC_ID_ALAC, + AV_CODEC_ID_WESTWOOD_SND1, + AV_CODEC_ID_GSM, ///< as in Berlin toast format + AV_CODEC_ID_QDM2, + AV_CODEC_ID_COOK, + AV_CODEC_ID_TRUESPEECH, + AV_CODEC_ID_TTA, + AV_CODEC_ID_SMACKAUDIO, + AV_CODEC_ID_QCELP, + AV_CODEC_ID_WAVPACK, + AV_CODEC_ID_DSICINAUDIO, + AV_CODEC_ID_IMC, + AV_CODEC_ID_MUSEPACK7, + AV_CODEC_ID_MLP, + AV_CODEC_ID_GSM_MS, /* as found in WAV */ + AV_CODEC_ID_ATRAC3, + AV_CODEC_ID_APE, + AV_CODEC_ID_NELLYMOSER, + AV_CODEC_ID_MUSEPACK8, + AV_CODEC_ID_SPEEX, + AV_CODEC_ID_WMAVOICE, + AV_CODEC_ID_WMAPRO, + AV_CODEC_ID_WMALOSSLESS, + AV_CODEC_ID_ATRAC3P, + AV_CODEC_ID_EAC3, + AV_CODEC_ID_SIPR, + AV_CODEC_ID_MP1, + AV_CODEC_ID_TWINVQ, + AV_CODEC_ID_TRUEHD, + AV_CODEC_ID_MP4ALS, + AV_CODEC_ID_ATRAC1, + AV_CODEC_ID_BINKAUDIO_RDFT, + AV_CODEC_ID_BINKAUDIO_DCT, + AV_CODEC_ID_AAC_LATM, + AV_CODEC_ID_QDMC, + AV_CODEC_ID_CELT, + AV_CODEC_ID_G723_1, + AV_CODEC_ID_G729, + AV_CODEC_ID_8SVX_EXP, + AV_CODEC_ID_8SVX_FIB, + AV_CODEC_ID_BMV_AUDIO, + AV_CODEC_ID_RALF, + AV_CODEC_ID_IAC, + AV_CODEC_ID_ILBC, + AV_CODEC_ID_OPUS, + AV_CODEC_ID_COMFORT_NOISE, + AV_CODEC_ID_TAK, + AV_CODEC_ID_METASOUND, + AV_CODEC_ID_PAF_AUDIO, + AV_CODEC_ID_ON2AVC, + AV_CODEC_ID_DSS_SP, + AV_CODEC_ID_CODEC2, + AV_CODEC_ID_FFWAVESYNTH, + AV_CODEC_ID_SONIC, + AV_CODEC_ID_SONIC_LS, + AV_CODEC_ID_EVRC, + AV_CODEC_ID_SMV, + AV_CODEC_ID_DSD_LSBF, + AV_CODEC_ID_DSD_MSBF, + AV_CODEC_ID_DSD_LSBF_PLANAR, + AV_CODEC_ID_DSD_MSBF_PLANAR, + AV_CODEC_ID_4GV, + AV_CODEC_ID_INTERPLAY_ACM, + AV_CODEC_ID_XMA1, + AV_CODEC_ID_XMA2, + AV_CODEC_ID_DST, + AV_CODEC_ID_ATRAC3AL, + AV_CODEC_ID_ATRAC3PAL, + AV_CODEC_ID_DOLBY_E, + AV_CODEC_ID_APTX, + AV_CODEC_ID_APTX_HD, + AV_CODEC_ID_SBC, + AV_CODEC_ID_ATRAC9, + AV_CODEC_ID_HCOM, + AV_CODEC_ID_ACELP_KELVIN, + AV_CODEC_ID_MPEGH_3D_AUDIO, + AV_CODEC_ID_SIREN, + AV_CODEC_ID_HCA, + AV_CODEC_ID_FASTAUDIO, + AV_CODEC_ID_MSNSIREN, + AV_CODEC_ID_DFPWM, + AV_CODEC_ID_BONK, + AV_CODEC_ID_MISC4, + AV_CODEC_ID_APAC, + AV_CODEC_ID_FTR, + AV_CODEC_ID_WAVARC, + AV_CODEC_ID_RKA, + AV_CODEC_ID_AC4, + AV_CODEC_ID_OSQ, + AV_CODEC_ID_QOA, + AV_CODEC_ID_LC3, + AV_CODEC_ID_G728, + AV_CODEC_ID_AHX, + AV_CODEC_ID_APPLE_APAC, + + /* subtitle codecs */ + AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. + AV_CODEC_ID_DVD_SUBTITLE = 0x17000, + AV_CODEC_ID_DVB_SUBTITLE, + AV_CODEC_ID_TEXT, ///< raw UTF-8 text + AV_CODEC_ID_XSUB, + AV_CODEC_ID_SSA, + AV_CODEC_ID_MOV_TEXT, + AV_CODEC_ID_HDMV_PGS_SUBTITLE, + AV_CODEC_ID_DVB_TELETEXT, + AV_CODEC_ID_SRT, + AV_CODEC_ID_MICRODVD, + AV_CODEC_ID_EIA_608, + AV_CODEC_ID_JACOSUB, + AV_CODEC_ID_SAMI, + AV_CODEC_ID_REALTEXT, + AV_CODEC_ID_STL, + AV_CODEC_ID_SUBVIEWER1, + AV_CODEC_ID_SUBVIEWER, + AV_CODEC_ID_SUBRIP, + AV_CODEC_ID_WEBVTT, + AV_CODEC_ID_MPL2, + AV_CODEC_ID_VPLAYER, + AV_CODEC_ID_PJS, + AV_CODEC_ID_ASS, + AV_CODEC_ID_HDMV_TEXT_SUBTITLE, + AV_CODEC_ID_TTML, + AV_CODEC_ID_ARIB_CAPTION, + AV_CODEC_ID_IVTV_VBI, + + /* other specific kind of codecs (generally used for attachments) */ + AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. + AV_CODEC_ID_TTF = 0x18000, + + AV_CODEC_ID_SCTE_35, ///< Contain timestamp estimated through PCR of program stream. + AV_CODEC_ID_EPG, + AV_CODEC_ID_BINTEXT, + AV_CODEC_ID_XBIN, + AV_CODEC_ID_IDF, + AV_CODEC_ID_OTF, + AV_CODEC_ID_SMPTE_KLV, + AV_CODEC_ID_DVD_NAV, + AV_CODEC_ID_TIMED_ID3, + AV_CODEC_ID_BIN_DATA, + AV_CODEC_ID_SMPTE_2038, + AV_CODEC_ID_LCEVC, + AV_CODEC_ID_SMPTE_436M_ANC, + AV_CODEC_ID_ITUT_T35, + + + AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it + + AV_CODEC_ID_MPEG2TS = 0x20000, /**< _FAKE_ codec to indicate a raw MPEG-2 TS + * stream (only used by libavformat) */ + AV_CODEC_ID_MPEG4SYSTEMS = 0x20001, /**< _FAKE_ codec to indicate a MPEG-4 Systems + * stream (only used by libavformat) */ + AV_CODEC_ID_FFMETADATA = 0x21000, ///< Dummy codec for streams containing only metadata information. + AV_CODEC_ID_WRAPPED_AVFRAME = 0x21001, ///< Passthrough codec, AVFrames wrapped in AVPacket + /** + * Dummy null video codec, useful mainly for development and debugging. + * Null encoder/decoder discard all input and never return any output. + */ + AV_CODEC_ID_VNULL, + /** + * Dummy null audio codec, useful mainly for development and debugging. + * Null encoder/decoder discard all input and never return any output. + */ + AV_CODEC_ID_ANULL, +}; + +/** + * Get the type of the given codec. + */ +enum AVMediaType avcodec_get_type(enum AVCodecID codec_id); + +/** + * Get the name of a codec. + * @return a static string identifying the codec; never NULL + */ +const char *avcodec_get_name(enum AVCodecID id); + +/** + * Return codec bits per sample. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return codec bits per sample. + * Only return non-zero if the bits per sample is exactly correct, not an + * approximation. + * + * @param[in] codec_id the codec + * @return Number of bits per sample or zero if unknown for the given codec. + */ +int av_get_exact_bits_per_sample(enum AVCodecID codec_id); + +/** + * Return a name for the specified profile, if available. + * + * @param codec_id the ID of the codec to which the requested profile belongs + * @param profile the profile value for which a name is requested + * @return A name for the profile if found, NULL otherwise. + * + * @note unlike av_get_profile_name(), which searches a list of profiles + * supported by a specific decoder or encoder implementation, this + * function searches the list of profiles from the AVCodecDescriptor + */ +const char *avcodec_profile_name(enum AVCodecID codec_id, int profile); + +/** + * Return the PCM codec associated with a sample format. + * @param be endianness, 0 for little, 1 for big, + * -1 (or anything else) for native + * @return AV_CODEC_ID_PCM_* or AV_CODEC_ID_NONE + */ +enum AVCodecID av_get_pcm_codec(enum AVSampleFormat fmt, int be); + +/** + * @} + */ + +#endif // AVCODEC_CODEC_ID_H diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h new file mode 100644 index 000000000..d880e3a80 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h @@ -0,0 +1,302 @@ +/* + * Codec parameters public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CODEC_PAR_H +#define AVCODEC_CODEC_PAR_H + +#include + +#include "libavutil/avutil.h" +#include "libavutil/channel_layout.h" +#include "libavutil/rational.h" +#include "libavutil/pixfmt.h" + +#include "codec_id.h" +#include "defs.h" +#include "packet.h" + +/** + * @defgroup lavc_codec_params Codec parameters + * @ingroup lavc_core + * @{ + */ + +/** + * This struct describes the properties of an encoded stream. + * + * @note + * The `sizeof(AVCodecParameters)` is not a part of the public ABI, + * therefore this struct must be allocated with ::avcodec_parameters_alloc() + * and freed with ::avcodec_parameters_free(). + */ +typedef struct AVCodecParameters { + /** + * General type of the encoded data. + */ + enum AVMediaType codec_type; + /** + * Specific type of the encoded data (the codec used). + */ + enum AVCodecID codec_id; + /** + * Additional information about the codec (corresponds to the AVI FOURCC). + */ + uint32_t codec_tag; + + /** + * Extra binary data needed for initializing the decoder, codec-dependent. + * + * Must be allocated with ::av_malloc() and will be freed by + * ::avcodec_parameters_free(). The allocated size of extradata must be at + * least #extradata_size + ::AV_INPUT_BUFFER_PADDING_SIZE, with the padding + * bytes zeroed. + */ + uint8_t *extradata; + /** + * Size of the extradata content in bytes. + */ + int extradata_size; + + /** + * Additional data associated with the entire stream. + * + * Should be allocated with ::av_packet_side_data_new() or + * ::av_packet_side_data_add(), and will be freed by ::avcodec_parameters_free(). + */ + AVPacketSideData *coded_side_data; + + /** + * Amount of entries in #coded_side_data. + */ + int nb_coded_side_data; + + /** + * - Video: the pixel format, the value corresponds to enum ::AVPixelFormat. + * - Audio: the sample format, the value corresponds to enum ::AVSampleFormat. + */ + int format; + + /** + * The average bitrate of the encoded data (in bits per second). + */ + int64_t bit_rate; + + /** + * The number of bits per sample in the codedwords. + * + * This is basically the bitrate per sample. It is mandatory for a bunch of + * formats to actually decode them. It's the number of bits for one sample in + * the actual coded bitstream. + * + * This could be, for example, 4, for ADPCM. + * For PCM formats this matches #bits_per_raw_sample. + * + * Can be 0. + */ + int bits_per_coded_sample; + + /** + * The number of valid bits in each output sample. + * + * If the sample format has more bits, the least significant bits are additional + * padding bits, which are always 0. Use right shifts to reduce the sample + * to its actual size. + * + * For example, audio formats with 24-bit samples will have #bits_per_raw_sample + * set to 24, and ::format set to ::AV_SAMPLE_FMT_S32. To get the original sample, + * use: `(int32_t)sample >> 8`. + * + * For ADPCM, this might be 12 or 16, or similar. + * + * Can be 0. + */ + int bits_per_raw_sample; + + /** + * Codec-specific bitstream restrictions that the stream conforms to. + */ + int profile; + int level; + + /** + * The width of the video frame in pixels. + * + * Video only. + */ + int width; + + /** + * The height of the video frame in pixels. + * + * Video only. + */ + int height; + + /** + * The aspect ratio (width/height) which a single pixel + * should have when displayed. + * + * When the aspect ratio is unknown or undefined, the numerator should be + * set to 0 (the denominator may have any value). + * + * Video only. + */ + AVRational sample_aspect_ratio; + + /** + * Number of frames per second, for streams with constant frame + * durations. Should be set to `{ 0, 1 }` when some frames have differing + * durations or if the value is not known. + * + * @note This field corresponds to values that are stored in codec-level + * headers and is typically overridden by container/transport-layer + * timestamps, when available. It should thus be used only as a last resort, + * when no higher-level timing information is available. + * + * Video only. + */ + AVRational framerate; + + /** + * The order of the fields in interlaced video. + * + * Video only. + */ + enum AVFieldOrder field_order; + + /** + * Additional colorspace characteristics. + * + * Video only. + */ + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace color_space; + enum AVChromaLocation chroma_location; + + /** + * Number of delayed frames. + * + * Video only. + */ + int video_delay; + + /** + * The channel layout and number of channels. + * + * Audio only. + */ + AVChannelLayout ch_layout; + /** + * The number of audio samples per second. + * + * Audio only. + */ + int sample_rate; + /** + * The number of bytes per coded audio frame, required by some formats. + * + * Audio only. + * + * Corresponds to nBlockAlign in WAVEFORMATEX. + */ + int block_align; + /** + * Audio frame size, if known. Required by some formats to be static. + * + * Audio only. + */ + int frame_size; + + /** + * Number of padding audio samples at the start. + * + * The amount of padding (in samples) inserted by the encoder at + * the beginning of the audio. I.e. this number of leading decoded samples + * must be discarded to get the original audio without leading + * padding. + * + * Audio only. + */ + int initial_padding; + /** + * Number of padding audio samples at the end. + * + * The amount of padding (in samples) appended by the encoder to + * the end of the audio. I.e. this number of decoded samples must be + * discarded from the end of the stream to get the original + * audio without any trailing padding. + * + * Audio only. + */ + int trailing_padding; + /** + * Number of audio samples to skip after a discontinuity. + * + * Audio only. + */ + int seek_preroll; + + /** + * Video with alpha channel only. Alpha channel handling + */ + enum AVAlphaMode alpha_mode; +} AVCodecParameters; + +/** + * @relates AVCodecParameters + * @{ + */ + +/** + * Allocate a new AVCodecParameters and set its fields to default values + * (unknown/invalid/0). The returned struct must be freed with + * ::avcodec_parameters_free(). + */ +AVCodecParameters *avcodec_parameters_alloc(void); + +/** + * Free an AVCodecParameters instance and everything associated with it and + * write `NULL` to the supplied pointer. + */ +void avcodec_parameters_free(AVCodecParameters **par); + +/** + * Copy the contents of \p src to \p dst. Any allocated fields in dst are freed and + * replaced with newly allocated duplicates of the corresponding fields in src. + * + * @return >= 0 on success, a negative AVERROR code on failure. + */ +int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src); + +/** + * This function is the same as ::av_get_audio_frame_duration(), except it works + * with ::AVCodecParameters instead of an ::AVCodecContext. + */ +int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); + +/** @} */ + +/** + * @} + */ + +#endif // AVCODEC_CODEC_PAR_H diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/d3d11va.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/d3d11va.h new file mode 100644 index 000000000..27f40e551 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/d3d11va.h @@ -0,0 +1,109 @@ +/* + * Direct3D11 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * copyright (c) 2015 Steve Lhomme + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_D3D11VA_H +#define AVCODEC_D3D11VA_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_d3d11va + * Public libavcodec D3D11VA header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_d3d11va Direct3D11 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provides the necessary configurations and data + * to the Direct3D11 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + * + * Use av_d3d11va_alloc_context() exclusively to allocate an AVD3D11VAContext. + */ +typedef struct AVD3D11VAContext { + /** + * D3D11 decoder object + */ + ID3D11VideoDecoder *decoder; + + /** + * D3D11 VideoContext + */ + ID3D11VideoContext *video_context; + + /** + * D3D11 configuration used to create the decoder + */ + D3D11_VIDEO_DECODER_CONFIG *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + ID3D11VideoDecoderOutputView **surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; + + /** + * Mutex to access video_context + */ + HANDLE context_mutex; +} AVD3D11VAContext; + +/** + * Allocate an AVD3D11VAContext. + * + * @return Newly-allocated AVD3D11VAContext or NULL on failure. + */ +AVD3D11VAContext *av_d3d11va_alloc_context(void); + +/** + * @} + */ + +#endif /* AVCODEC_D3D11VA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h new file mode 100644 index 000000000..b13e983b1 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +/** + * @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.
+ * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dirac.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dirac.h new file mode 100644 index 000000000..8c348cdc0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dirac.h @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2007 Marco Gerards + * Copyright (C) 2009 David Conrad + * Copyright (C) 2011 Jordi Ortiz + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_DIRAC_H +#define AVCODEC_DIRAC_H + +/** + * @file + * Interface to Dirac Decoder/Encoder + * @author Marco Gerards + * @author David Conrad + * @author Jordi Ortiz + */ + +#include +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +/** + * The spec limits the number of wavelet decompositions to 4 for both + * level 1 (VC-2) and 128 (long-gop default). + * 5 decompositions is the maximum before >16-bit buffers are needed. + * Schroedinger allows this for DD 9,7 and 13,7 wavelets only, limiting + * the others to 4 decompositions (or 3 for the fidelity filter). + * + * We use this instead of MAX_DECOMPOSITIONS to save some memory. + */ +#define MAX_DWT_LEVELS 5 + +/** + * Parse code values: + * + * Dirac Specification -> + * 9.6.1 Table 9.1 + * + * VC-2 Specification -> + * 10.4.1 Table 10.1 + */ + +enum DiracParseCodes { + DIRAC_PCODE_SEQ_HEADER = 0x00, + DIRAC_PCODE_END_SEQ = 0x10, + DIRAC_PCODE_AUX = 0x20, + DIRAC_PCODE_PAD = 0x30, + DIRAC_PCODE_PICTURE_CODED = 0x08, + DIRAC_PCODE_PICTURE_RAW = 0x48, + DIRAC_PCODE_PICTURE_LOW_DEL = 0xC8, + DIRAC_PCODE_PICTURE_HQ = 0xE8, + DIRAC_PCODE_INTER_NOREF_CO1 = 0x0A, + DIRAC_PCODE_INTER_NOREF_CO2 = 0x09, + DIRAC_PCODE_INTER_REF_CO1 = 0x0D, + DIRAC_PCODE_INTER_REF_CO2 = 0x0E, + DIRAC_PCODE_INTRA_REF_CO = 0x0C, + DIRAC_PCODE_INTRA_REF_RAW = 0x4C, + DIRAC_PCODE_INTRA_REF_PICT = 0xCC, + DIRAC_PCODE_MAGIC = 0x42424344, +}; + +typedef struct DiracVersionInfo { + int major; + int minor; +} DiracVersionInfo; + +typedef struct AVDiracSeqHeader { + unsigned width; + unsigned height; + uint8_t chroma_format; ///< 0: 444 1: 422 2: 420 + + uint8_t interlaced; + uint8_t top_field_first; + + uint8_t frame_rate_index; ///< index into dirac_frame_rate[] + uint8_t aspect_ratio_index; ///< index into dirac_aspect_ratio[] + + uint16_t clean_width; + uint16_t clean_height; + uint16_t clean_left_offset; + uint16_t clean_right_offset; + + uint8_t pixel_range_index; ///< index into dirac_pixel_range_presets[] + uint8_t color_spec_index; ///< index into dirac_color_spec_presets[] + + int profile; + int level; + + AVRational framerate; + AVRational sample_aspect_ratio; + + enum AVPixelFormat pix_fmt; + enum AVColorRange color_range; + enum AVColorPrimaries color_primaries; + enum AVColorTransferCharacteristic color_trc; + enum AVColorSpace colorspace; + + DiracVersionInfo version; + int bit_depth; +} AVDiracSeqHeader; + +/** + * Parse a Dirac sequence header. + * + * @param dsh this function will allocate and fill an AVDiracSeqHeader struct + * and write it into this pointer. The caller must free it with + * av_free(). + * @param buf the data buffer + * @param buf_size the size of the data buffer in bytes + * @param log_ctx if non-NULL, this function will log errors here + * @return 0 on success, a negative AVERROR code on failure + */ +int av_dirac_parse_sequence_header(AVDiracSeqHeader **dsh, + const uint8_t *buf, size_t buf_size, + void *log_ctx); + +#endif /* AVCODEC_DIRAC_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dv_profile.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dv_profile.h new file mode 100644 index 000000000..4365f1b4b --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dv_profile.h @@ -0,0 +1,82 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_DV_PROFILE_H +#define AVCODEC_DV_PROFILE_H + +#include + +#include "libavutil/pixfmt.h" +#include "libavutil/rational.h" + +/* minimum number of bytes to read from a DV stream in order to + * determine the profile */ +#define DV_PROFILE_BYTES (6 * 80) /* 6 DIF blocks */ + + +/* + * AVDVProfile is used to express the differences between various + * DV flavors. For now it's primarily used for differentiating + * 525/60 and 625/50, but the plans are to use it for various + * DV specs as well (e.g. SMPTE314M vs. IEC 61834). + */ +typedef struct AVDVProfile { + int dsf; /* value of the dsf in the DV header */ + int video_stype; /* stype for VAUX source pack */ + int frame_size; /* total size of one frame in bytes */ + int difseg_size; /* number of DIF segments per DIF channel */ + int n_difchan; /* number of DIF channels per frame */ + AVRational time_base; /* 1/framerate */ + int ltc_divisor; /* FPS from the LTS standpoint */ + int height; /* picture height in pixels */ + int width; /* picture width in pixels */ + AVRational sar[2]; /* sample aspect ratios for 4:3 and 16:9 */ + enum AVPixelFormat pix_fmt; /* picture pixel format */ + int bpm; /* blocks per macroblock */ + const uint8_t *block_sizes; /* AC block sizes, in bits */ + int audio_stride; /* size of audio_shuffle table */ + int audio_min_samples[3]; /* min amount of audio samples */ + /* for 48kHz, 44.1kHz and 32kHz */ + int audio_samples_dist[5]; /* how many samples are supposed to be */ + /* in each frame in a 5 frames window */ + const uint8_t (*audio_shuffle)[9]; /* PCM shuffling table */ +} AVDVProfile; + +/** + * Get a DV profile for the provided compressed frame. + * + * @param sys the profile used for the previous frame, may be NULL + * @param frame the compressed data buffer + * @param buf_size size of the buffer in bytes + * @return the DV profile for the supplied data or NULL on failure + */ +const AVDVProfile *av_dv_frame_profile(const AVDVProfile *sys, + const uint8_t *frame, unsigned buf_size); + +/** + * Get a DV profile for the provided stream parameters. + */ +const AVDVProfile *av_dv_codec_profile(int width, int height, enum AVPixelFormat pix_fmt); + +/** + * Get a DV profile for the provided stream parameters. + * The frame rate is used as a best-effort parameter. + */ +const AVDVProfile *av_dv_codec_profile2(int width, int height, enum AVPixelFormat pix_fmt, AVRational frame_rate); + +#endif /* AVCODEC_DV_PROFILE_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dxva2.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dxva2.h new file mode 100644 index 000000000..bdec6112e --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/dxva2.h @@ -0,0 +1,90 @@ +/* + * DXVA2 HW acceleration + * + * copyright (c) 2009 Laurent Aimar + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_DXVA2_H +#define AVCODEC_DXVA2_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_dxva2 + * Public libavcodec DXVA2 header. + */ + +#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0602 +#undef _WIN32_WINNT +#define _WIN32_WINNT 0x0602 +#endif + +#include +#include +#include + +/** + * @defgroup lavc_codec_hwaccel_dxva2 DXVA2 + * @ingroup lavc_codec_hwaccel + * + * @{ + */ + +/** + * This structure is used to provides the necessary configurations and data + * to the DXVA2 FFmpeg HWAccel implementation. + * + * The application must make it available as AVCodecContext.hwaccel_context. + */ +struct dxva_context { + /** + * DXVA2 decoder object + */ + IDirectXVideoDecoder *decoder; + + /** + * DXVA2 configuration used to create the decoder + */ + const DXVA2_ConfigPictureDecode *cfg; + + /** + * The number of surface in the surface array + */ + unsigned surface_count; + + /** + * The array of Direct3D surfaces used to create the decoder + */ + LPDIRECT3DSURFACE9 *surface; + + /** + * A bit field configuring the workarounds needed for using the decoder + */ + uint64_t workaround; + + /** + * Private to the FFmpeg AVHWAccel implementation + */ + unsigned report_id; +}; + +/** + * @} + */ + +#endif /* AVCODEC_DXVA2_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h new file mode 100644 index 000000000..a23083368 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h @@ -0,0 +1,242 @@ +/* + * EXIF metadata parser + * Copyright (c) 2013 Thilo Borgmann + * Copyright (c) 2024-2025 Leo Izen + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * EXIF metadata parser + * @author Thilo Borgmann + * @author Leo Izen + */ + +#ifndef AVCODEC_EXIF_H +#define AVCODEC_EXIF_H + +#include +#include + +#include "libavutil/buffer.h" +#include "libavutil/dict.h" +#include "libavutil/rational.h" + +/** Data type identifiers for TIFF tags */ +enum AVTiffDataType { + AV_TIFF_BYTE = 1, + AV_TIFF_STRING, + AV_TIFF_SHORT, + AV_TIFF_LONG, + AV_TIFF_RATIONAL, + AV_TIFF_SBYTE, + AV_TIFF_UNDEFINED, + AV_TIFF_SSHORT, + AV_TIFF_SLONG, + AV_TIFF_SRATIONAL, + AV_TIFF_FLOAT, + AV_TIFF_DOUBLE, + AV_TIFF_IFD, +}; + +enum AVExifHeaderMode { + /** + * The TIFF header starts with 0x49492a00, or 0x4d4d002a. + * This one is used internally by FFmpeg. + */ + AV_EXIF_TIFF_HEADER, + /** skip the TIFF header, assume little endian */ + AV_EXIF_ASSUME_LE, + /** skip the TIFF header, assume big endian */ + AV_EXIF_ASSUME_BE, + /** The first four bytes point to the actual start, then it's AV_EXIF_TIFF_HEADER */ + AV_EXIF_T_OFF, + /** The first six bytes contain "Exif\0\0", then it's AV_EXIF_TIFF_HEADER */ + AV_EXIF_EXIF00, +}; + +typedef struct AVExifEntry AVExifEntry; + +typedef struct AVExifMetadata { + /* array of EXIF metadata entries */ + AVExifEntry *entries; + /* number of entries in this array */ + unsigned int count; + /* size of the buffer, used for av_fast_realloc */ + unsigned int size; +} AVExifMetadata; + +struct AVExifEntry { + uint16_t id; + enum AVTiffDataType type; + uint32_t count; + + /* + * These are for IFD-style MakerNote + * entries which occur after a fixed + * offset rather than at the start of + * the entry. The ifd_lead field contains + * the leading bytes which typically + * identify the type of MakerNote. + */ + uint32_t ifd_offset; + uint8_t *ifd_lead; + + /* + * An array of entries of size count + * Unless it's an IFD, in which case + * it's not an array and count = 1 + */ + union { + void *ptr; + int64_t *sint; + uint64_t *uint; + double *dbl; + char *str; + uint8_t *ubytes; + int8_t *sbytes; + AVRational *rat; + AVExifMetadata ifd; + } value; +}; + +/** + * Retrieves the tag name associated with the provided tag ID. + * If the tag ID is unknown, NULL is returned. + * + * For example, av_exif_get_tag_name(0x112) returns "Orientation". + */ +const char *av_exif_get_tag_name(uint16_t id); + +/** + * Retrieves the tag ID associated with the provided tag string name. + * If the tag name is unknown, a negative number is returned. Otherwise + * it always fits inside a uint16_t integer. + * + * For example, av_exif_get_tag_id("Orientation") returns 274 (0x0112). + */ +int32_t av_exif_get_tag_id(const char *name); + +/** + * Add an entry to the provided EXIF metadata struct. If one already exists with the provided + * ID, it will set the existing one to have the other information provided. Otherwise, it + * will allocate a new entry. + * + * This function reallocates ifd->entries using av_fast_realloc and allocates (using av_malloc) + * a new value member of the entry, then copies the contents of value into that buffer. + */ +int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, + uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value); + +/** + * Also check subdirectories. + */ +#define AV_EXIF_FLAG_RECURSIVE (1 << 0) + +/** + * Get an entry with the tagged ID from the EXIF metadata struct. A pointer to the entry + * will be written into *value. + * + * If the entry was present and returned successfully, a positive number is returned. + * + * The positive number is equal to 1 plus the offset at which the entry was found. If the + * entry was found at the top level, this will be in the range of 1 to the number of entries + * in the IFD (inclusive). If the entry was found in a sub-IFD, then it will be a number greater + * than the number of entries in the top-level IFD. + * + * If the entry was not found, *value is left untouched and zero is returned. + * If an error occurred, a negative AVERROR is returned. + */ +int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value); + +/** + * Remove an entry from the provided EXIF metadata struct. + * + * If the entry was present and removed successfully, a positive number is returned. + * + * The positive number is equal to 1 plus the offset at which the entry was found. If the + * entry was found at the top level, this will be in the range of 1 to the number of entries + * in the IFD (inclusive). If the entry was found in a sub-IFD, then it will be a number greater + * than the number of entries in the top-level IFD. This refers to the state of the IFD before + * the entry was removed, e.g. if the last entry is removed, a 1 is returned, but the IFD has + * no entries anymore. + * + * If the entry was not found, zero is returned and the IFD is left untouched. + * If an error occurred, a negative AVERROR is returned. + */ +int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags); + +/** + * Decodes the EXIF data provided in the buffer and writes it into the + * struct *ifd. If this function succeeds, the IFD is owned by the caller + * and must be cleared after use by calling av_exif_free(); If this function + * fails and returns a negative value, it will call av_exif_free(ifd) before + * returning. + */ +int av_exif_parse_buffer(void *logctx, const uint8_t *data, size_t size, + AVExifMetadata *ifd, enum AVExifHeaderMode header_mode); + +/** + * Allocates a buffer using av_malloc of an appropriate size and writes the + * EXIF data represented by ifd into that buffer. + * + * Upon error, *buffer will be NULL. The buffer becomes owned by the caller upon + * success. The *buffer argument must be NULL before calling. + */ +int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode); + +/** + * Frees all resources associated with the given EXIF metadata struct. + * Does not free the pointer passed itself, in case it is stack-allocated. + * The pointer passed to this function must be freed by the caller, + * if it is heap-allocated. Passing NULL is permitted. + */ +void av_exif_free(AVExifMetadata *ifd); + +/** + * Recursively reads all tags from the IFD and stores them in the + * provided metadata dictionary. + */ +int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata); + +/** + * Allocates a duplicate of the provided EXIF metadata struct. The caller owns + * the duplicate and must free it with av_exif_free. Returns NULL if the duplication + * process failed. + */ +AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd); + +/** + * Convert a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX + * into an orientation constant used by EXIF's orientation tag. + * + * Returns an EXIF orientation between 1 and 8 (inclusive) depending + * on the rotation and flip factors. Returns 0 if the matrix is singular. + */ +int av_exif_matrix_to_orientation(const int32_t *matrix); + +/** + * Convert an orientation constant used by EXIF's orientation tag + * into a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX. + * + * Returns 0 on success and negative if the orientation is invalid, + * i.e. not between 1 and 8 (inclusive). + */ +int av_exif_orientation_to_matrix(int32_t *matrix, int orientation); + +#endif /* AVCODEC_EXIF_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/jni.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/jni.h new file mode 100644 index 000000000..955cd2809 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/jni.h @@ -0,0 +1,67 @@ +/* + * JNI public API functions + * + * Copyright (c) 2015-2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_JNI_H +#define AVCODEC_JNI_H + +/* + * Manually set a Java virtual machine which will be used to retrieve the JNI + * environment. Once a Java VM is set it cannot be changed afterwards, meaning + * you can call multiple times av_jni_set_java_vm with the same Java VM pointer + * however it will error out if you try to set a different Java VM. + * + * @param vm Java virtual machine + * @param log_ctx context used for logging, can be NULL + * @return 0 on success, < 0 otherwise + */ +int av_jni_set_java_vm(void *vm, void *log_ctx); + +/* + * Get the Java virtual machine which has been set with av_jni_set_java_vm. + * + * @param vm Java virtual machine + * @return a pointer to the Java virtual machine + */ +void *av_jni_get_java_vm(void *log_ctx); + +/* + * Set the Android application context which will be used to retrieve the Android + * content resolver to handle content uris. + * + * This function is only available on Android. + * + * @param app_ctx global JNI reference to the Android application context + * @return 0 on success, < 0 otherwise + */ +int av_jni_set_android_app_ctx(void *app_ctx, void *log_ctx); + +/* + * Get the Android application context that has been set with + * av_jni_set_android_app_ctx. + * + * This function is only available on Android. + * + * @return a pointer the the Android application context + */ +void *av_jni_get_android_app_ctx(void); + +#endif /* AVCODEC_JNI_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/mediacodec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/mediacodec.h new file mode 100644 index 000000000..4e9b56a61 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/mediacodec.h @@ -0,0 +1,103 @@ +/* + * Android MediaCodec public API + * + * Copyright (c) 2016 Matthieu Bouron + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_MEDIACODEC_H +#define AVCODEC_MEDIACODEC_H + +#include "libavcodec/avcodec.h" + +/** + * This structure holds a reference to a android/view/Surface object that will + * be used as output by the decoder. + * + */ +typedef struct AVMediaCodecContext { + + /** + * android/view/Surface object reference. + */ + void *surface; + +} AVMediaCodecContext; + +/** + * Allocate and initialize a MediaCodec context. + * + * When decoding with MediaCodec is finished, the caller must free the + * MediaCodec context with av_mediacodec_default_free. + * + * @return a pointer to a newly allocated AVMediaCodecContext on success, NULL otherwise + */ +AVMediaCodecContext *av_mediacodec_alloc_context(void); + +/** + * Convenience function that sets up the MediaCodec context. + * + * @param avctx codec context + * @param ctx MediaCodec context to initialize + * @param surface reference to an android/view/Surface + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_default_init(AVCodecContext *avctx, AVMediaCodecContext *ctx, void *surface); + +/** + * This function must be called to free the MediaCodec context initialized with + * av_mediacodec_default_init(). + * + * @param avctx codec context + */ +void av_mediacodec_default_free(AVCodecContext *avctx); + +/** + * Opaque structure representing a MediaCodec buffer to render. + */ +typedef struct MediaCodecBuffer AVMediaCodecBuffer; + +/** + * Release a MediaCodec buffer and render it to the surface that is associated + * with the decoder. This function should only be called once on a given + * buffer, once released the underlying buffer returns to the codec, thus + * subsequent calls to this function will have no effect. + * + * @param buffer the buffer to render + * @param render 1 to release and render the buffer to the surface or 0 to + * discard the buffer + * @return 0 on success, < 0 otherwise + */ +int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render); + +/** + * Release a MediaCodec buffer and render it at the given time to the surface + * that is associated with the decoder. The timestamp must be within one second + * of the current `java/lang/System#nanoTime()` (which is implemented using + * `CLOCK_MONOTONIC` on Android). See the Android MediaCodec documentation + * of [`android/media/MediaCodec#releaseOutputBuffer(int,long)`][0] for more details. + * + * @param buffer the buffer to render + * @param time timestamp in nanoseconds of when to render the buffer + * @return 0 on success, < 0 otherwise + * + * [0]: https://developer.android.com/reference/android/media/MediaCodec#releaseOutputBuffer(int,%20long) + */ +int av_mediacodec_render_buffer_at_time(AVMediaCodecBuffer *buffer, int64_t time); + +#endif /* AVCODEC_MEDIACODEC_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h new file mode 100644 index 000000000..00774a703 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h @@ -0,0 +1,950 @@ +/* + * AVPacket public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_PACKET_H +#define AVCODEC_PACKET_H + +#include +#include + +#include "libavutil/attributes.h" +#include "libavutil/buffer.h" +#include "libavutil/dict.h" +#include "libavutil/rational.h" +#include "libavutil/version.h" + +#include "libavcodec/version_major.h" + +/** + * @defgroup lavc_packet_side_data AVPacketSideData + * + * Types and functions for working with AVPacketSideData. + * @{ + */ +enum AVPacketSideDataType { + /** + * An AV_PKT_DATA_PALETTE side data packet contains exactly AVPALETTE_SIZE + * bytes worth of palette. This side data signals that a new palette is + * present. + */ + AV_PKT_DATA_PALETTE, + + /** + * The AV_PKT_DATA_NEW_EXTRADATA is used to notify the codec or the format + * that the extradata buffer was changed and the receiving side should + * act upon it appropriately. The new extradata is embedded in the side + * data buffer and should be immediately used for processing the current + * frame or packet. + */ + AV_PKT_DATA_NEW_EXTRADATA, + + /** + * An AV_PKT_DATA_PARAM_CHANGE side data packet is laid out as follows: + * @code + * u32le param_flags + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE) + * s32le sample_rate + * if (param_flags & AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS) + * s32le width + * s32le height + * @endcode + */ + AV_PKT_DATA_PARAM_CHANGE, + + /** + * An AV_PKT_DATA_H263_MB_INFO side data packet contains a number of + * structures with info about macroblocks relevant to splitting the + * packet into smaller packets on macroblock edges (e.g. as for RFC 2190). + * That is, it does not necessarily contain info about all macroblocks, + * as long as the distance between macroblocks in the info is smaller + * than the target payload size. + * Each MB info structure is 12 bytes, and is laid out as follows: + * @code + * u32le bit offset from the start of the packet + * u8 current quantizer at the start of the macroblock + * u8 GOB number + * u16le macroblock address within the GOB + * u8 horizontal MV predictor + * u8 vertical MV predictor + * u8 horizontal MV predictor for block number 3 + * u8 vertical MV predictor for block number 3 + * @endcode + */ + AV_PKT_DATA_H263_MB_INFO, + + /** + * This side data should be associated with an audio stream and contains + * ReplayGain information in form of the AVReplayGain struct. + */ + AV_PKT_DATA_REPLAYGAIN, + + /** + * This side data contains a 3x3 transformation matrix describing an affine + * transformation that needs to be applied to the decoded video frames for + * correct presentation. + * + * See libavutil/display.h for a detailed description of the data. + */ + AV_PKT_DATA_DISPLAYMATRIX, + + /** + * This side data should be associated with a video stream and contains + * Stereoscopic 3D information in form of the AVStereo3D struct. + */ + AV_PKT_DATA_STEREO3D, + + /** + * This side data should be associated with an audio stream and corresponds + * to enum AVAudioServiceType. + */ + AV_PKT_DATA_AUDIO_SERVICE_TYPE, + + /** + * This side data contains quality related information from the encoder. + * @code + * u32le quality factor of the compressed frame. Allowed range is between 1 (good) and FF_LAMBDA_MAX (bad). + * u8 picture type + * u8 error count + * u16 reserved + * u64le[error count] sum of squared differences between encoder in and output + * @endcode + */ + AV_PKT_DATA_QUALITY_STATS, + + /** + * This side data contains an integer value representing the stream index + * of a "fallback" track. A fallback track indicates an alternate + * track to use when the current track can not be decoded for some reason. + * e.g. no decoder available for codec. + */ + AV_PKT_DATA_FALLBACK_TRACK, + + /** + * This side data corresponds to the AVCPBProperties struct. + */ + AV_PKT_DATA_CPB_PROPERTIES, + + /** + * Recommends skipping the specified number of 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_PKT_DATA_SKIP_SAMPLES, + + /** + * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that + * the packet may contain "dual mono" audio specific to Japanese DTV + * and if it is true, recommends only the selected channel to be used. + * @code + * u8 selected channels (0=main/left, 1=sub/right, 2=both) + * @endcode + */ + AV_PKT_DATA_JP_DUALMONO, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. + */ + AV_PKT_DATA_STRINGS_METADATA, + + /** + * Subtitle event position + * @code + * u32le x1 + * u32le y1 + * u32le x2 + * u32le y2 + * @endcode + */ + AV_PKT_DATA_SUBTITLE_POSITION, + + /** + * Data found in BlockAdditional element of matroska container. There is + * no end marker for the data, so it is required to rely on the side data + * size to recognize the end. 8 byte id (as found in BlockAddId) followed + * by data. + */ + AV_PKT_DATA_MATROSKA_BLOCKADDITIONAL, + + /** + * The optional first identifier line of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_IDENTIFIER, + + /** + * The optional settings (rendering instructions) that immediately + * follow the timestamp specifier of a WebVTT cue. + */ + AV_PKT_DATA_WEBVTT_SETTINGS, + + /** + * A list of zero terminated key/value strings. There is no end marker for + * the list, so it is required to rely on the side data size to stop. This + * side data includes updated metadata which appeared in the stream. + */ + AV_PKT_DATA_METADATA_UPDATE, + + /** + * MPEGTS stream ID as uint8_t, this is required to pass the stream ID + * information from the demuxer to the corresponding muxer. + */ + AV_PKT_DATA_MPEGTS_STREAM_ID, + + /** + * Mastering display metadata (based on SMPTE-2086:2014). This metadata + * should be associated with a video stream and contains data in the form + * of the AVMasteringDisplayMetadata struct. + */ + AV_PKT_DATA_MASTERING_DISPLAY_METADATA, + + /** + * This side data should be associated with a video stream and corresponds + * to the AVSphericalMapping structure. + */ + AV_PKT_DATA_SPHERICAL, + + /** + * Content light level (based on CTA-861.3). This metadata should be + * associated with a video stream and contains data in the form of the + * AVContentLightMetadata struct. + */ + AV_PKT_DATA_CONTENT_LIGHT_LEVEL, + + /** + * ATSC A53 Part 4 Closed Captions. This metadata should be associated with + * a video stream. A53 CC bitstream is stored as uint8_t in AVPacketSideData.data. + * The number of bytes of CC data is AVPacketSideData.size. + */ + AV_PKT_DATA_A53_CC, + + /** + * This side data is encryption initialization data. + * The format is not part of ABI, use av_encryption_init_info_* methods to + * access. + */ + AV_PKT_DATA_ENCRYPTION_INIT_INFO, + + /** + * This side data contains encryption info for how to decrypt the packet. + * The format is not part of ABI, use av_encryption_info_* methods to access. + */ + AV_PKT_DATA_ENCRYPTION_INFO, + + /** + * Active Format Description data consisting of a single byte as specified + * in ETSI TS 101 154 using AVActiveFormatDescription enum. + */ + AV_PKT_DATA_AFD, + + /** + * Producer Reference Time data corresponding to the AVProducerReferenceTime struct, + * usually exported by some encoders (on demand through the prft flag set in the + * AVCodecContext export_side_data field). + */ + AV_PKT_DATA_PRFT, + + /** + * ICC profile data consisting of an opaque octet buffer following the + * format described by ISO 15076-1. + */ + AV_PKT_DATA_ICC_PROFILE, + + /** + * DOVI configuration + * ref: + * dolby-vision-bitstreams-within-the-iso-base-media-file-format-v2.1.2, section 2.2 + * dolby-vision-bitstreams-in-mpeg-2-transport-stream-multiplex-v1.2, section 3.3 + * Tags are stored in struct AVDOVIDecoderConfigurationRecord. + */ + AV_PKT_DATA_DOVI_CONF, + + /** + * Timecode which conforms to SMPTE ST 12-1:2014. 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_PKT_DATA_S12M_TIMECODE, + + /** + * HDR10+ dynamic metadata associated with a video frame. The metadata is in + * the form of the AVDynamicHDRPlus struct and contains + * information for color volume transform - application 4 of + * SMPTE 2094-40:2016 standard. + */ + AV_PKT_DATA_DYNAMIC_HDR10_PLUS, + + /** + * IAMF Mix Gain Parameter Data associated with the audio frame. This metadata + * is in the form of the AVIAMFParamDefinition struct and contains information + * defined in sections 3.6.1 and 3.8.1 of the Immersive Audio Model and + * Formats standard. + */ + AV_PKT_DATA_IAMF_MIX_GAIN_PARAM, + + /** + * IAMF Demixing Info Parameter Data associated with the audio frame. This + * metadata is in the form of the AVIAMFParamDefinition struct and contains + * information defined in sections 3.6.1 and 3.8.2 of the Immersive Audio Model + * and Formats standard. + */ + AV_PKT_DATA_IAMF_DEMIXING_INFO_PARAM, + + /** + * IAMF Recon Gain Info Parameter Data associated with the audio frame. This + * metadata is in the form of the AVIAMFParamDefinition struct and contains + * information defined in sections 3.6.1 and 3.8.3 of the Immersive Audio Model + * and Formats standard. + */ + AV_PKT_DATA_IAMF_RECON_GAIN_INFO_PARAM, + + /** + * Ambient viewing environment metadata, as defined by H.274. This metadata + * should be associated with a video stream and contains data in the form + * of the AVAmbientViewingEnvironment struct. + */ + AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT, + + /** + * The number of pixels to discard from the top/bottom/left/right border of the + * decoded frame to obtain the sub-rectangle intended for presentation. + * + * @code + * u32le crop_top + * u32le crop_bottom + * u32le crop_left + * u32le crop_right + * @endcode + */ + AV_PKT_DATA_FRAME_CROPPING, + + /** + * Raw LCEVC payload data, as a uint8_t array, with NAL emulation + * bytes intact. + */ + AV_PKT_DATA_LCEVC, + + /** + * 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_PKT_DATA_3D_REFERENCE_DISPLAYS, + + /** + * Contains the last received RTCP SR (Sender Report) information + * in the form of the AVRTCPSenderReport struct. + */ + AV_PKT_DATA_RTCP_SR, + + /** + * 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_PKT_DATA_EXIF, + + /** + * HDR dynamic metadata associated with a video frame. The payload is an + * AVDynamicHDRSmpte2094App5 type and contains information for color volume + * transform as specified in the SMPTE 2094-50 standard. + */ + AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5, + + /** + * Dolby Vision enhancement-layer HEVC decoder configuration. + * Parsed from the @c hvcE box in ISOM-based containers or the + * corresponding BlockAdditionMapping in Matroska. The data is a raw + * HEVCDecoderConfigurationRecord as defined in ISO 14496-15. + */ + AV_PKT_DATA_HEVC_CONF, + + /** + * The number of side data types. + * This is not part of the public API/ABI in the sense that it may + * change when new side data types are added. + * This must stay the last enum value. + * If its value becomes huge, some code using it + * needs to be updated as it assumes it to be smaller than other limits. + */ + AV_PKT_DATA_NB +}; + +/** + * This structure stores auxiliary information for decoding, presenting, or + * otherwise processing the coded stream. It is typically exported by demuxers + * and encoders and can be fed to decoders and muxers either in a per packet + * basis, or as global side data (applying to the entire coded stream). + * + * Global side data is handled as follows: + * - During demuxing, it may be exported through + * @ref AVCodecParameters.coded_side_data "AVStream's codec parameters", which can + * then be passed as input to decoders through the + * @ref AVCodecContext.coded_side_data "decoder context's side data", for + * initialization. + * - For muxing, it can be fed through @ref AVCodecParameters.coded_side_data + * "AVStream's codec parameters", typically the output of encoders through + * the @ref AVCodecContext.coded_side_data "encoder context's side data", for + * initialization. + * + * Packet specific side data is handled as follows: + * - During demuxing, it may be exported through @ref AVPacket.side_data + * "AVPacket's side data", which can then be passed as input to decoders. + * - For muxing, it can be fed through @ref AVPacket.side_data "AVPacket's + * side data", typically the output of encoders. + * + * Different modules may accept or export different types of side data + * depending on media type and codec. Refer to @ref AVPacketSideDataType for a + * list of defined types and where they may be found or used. + */ +typedef struct AVPacketSideData { + uint8_t *data; + size_t size; + enum AVPacketSideDataType type; +} AVPacketSideData; + +/** + * Allocate a new packet side data. + * + * @param sd pointer to an array of side data to which the side data should + * be added. *sd may be NULL, in which case the array will be + * initialized. + * @param nb_sd pointer to an integer containing the number of entries in + * the array. The integer value will be increased by 1 on success. + * @param type side data type + * @param size desired side data size + * @param flags currently unused. Must be zero + * + * @return pointer to freshly allocated side data on success, or NULL otherwise. + */ +AVPacketSideData *av_packet_side_data_new(AVPacketSideData **psd, int *pnb_sd, + enum AVPacketSideDataType type, + size_t size, int flags); + +/** + * Wrap existing data as packet side data. + * + * @param sd pointer to an array of side data to which the side data should + * be added. *sd may be NULL, in which case the array will be + * initialized + * @param nb_sd pointer to an integer containing the number of entries in + * the array. The integer value will be increased by 1 on success. + * @param type side data type + * @param data a data array. It must be allocated with the av_malloc() family + * of functions. The ownership of the data is transferred to the + * side data array on success + * @param size size of the data array + * @param flags currently unused. Must be zero + * + * @return pointer to freshly allocated side data on success, or NULL otherwise + * On failure, the side data array is unchanged and the data remains + * owned by the caller. + */ +AVPacketSideData *av_packet_side_data_add(AVPacketSideData **sd, int *nb_sd, + enum AVPacketSideDataType type, + void *data, size_t size, int flags); + +/** + * Get side information from a side data array. + * + * @param sd the array from which the side data should be fetched + * @param nb_sd value containing the number of entries in the array. + * @param type desired side information type + * + * @return pointer to side data if present or NULL otherwise + */ +const AVPacketSideData *av_packet_side_data_get(const AVPacketSideData *sd, + int nb_sd, + enum AVPacketSideDataType type); + +/** + * Remove side data of the given type from a side data array. + * + * @param sd the array from which the side data should be removed + * @param nb_sd pointer to an integer containing the number of entries in + * the array. Will be reduced by the amount of entries removed + * upon return + * @param type side information type + */ +void av_packet_side_data_remove(AVPacketSideData *sd, int *nb_sd, + enum AVPacketSideDataType type); + +/** + * Convenience function to free all the side data stored in an array, and + * the array itself. + * + * @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_packet_side_data_free(AVPacketSideData **sd, int *nb_sd); + +struct AVFrameSideData; + +/** + * Add a new packet side data entry to an array based on existing frame + * side data, if a matching type exists for packet side data. + * + * @param flags Currently unused. Must be 0. + * @retval >= 0 Success + * @retval AVERROR(EINVAL) The frame side data type does not have a matching + * packet side data type. + * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or + * similar. + */ +int av_packet_side_data_from_frame(AVPacketSideData **sd, int *nb_sd, + const struct AVFrameSideData *src, unsigned int flags); +/** + * Add a new frame side data entry to an array based on existing packet + * side data, if a matching type exists for frame side data. + * + * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, + * or 0. + * @retval >= 0 Success + * @retval AVERROR(EINVAL) The packet side data type does not have a matching + * frame side data type. + * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or + * similar. + */ +int av_packet_side_data_to_frame(struct AVFrameSideData ***sd, int *nb_sd, + const AVPacketSideData *src, unsigned int flags); + +const char *av_packet_side_data_name(enum AVPacketSideDataType type); + +/** + * @} + */ + +/** + * @defgroup lavc_packet AVPacket + * + * Types and functions for working with AVPacket. + * @{ + */ + +/** + * This structure stores compressed data. It is typically exported by demuxers + * and then passed as input to decoders, or received as output from encoders and + * then passed to muxers. + * + * For video, it should typically contain one compressed frame. For audio it may + * contain several compressed frames. Encoders are allowed to output empty + * packets, with no compressed data, containing only side data + * (e.g. to update some stream parameters at the end of encoding). + * + * The semantics of data ownership depends on the buf field. + * If it is set, the packet data is dynamically allocated and is + * valid indefinitely until a call to av_packet_unref() reduces the + * reference count to 0. + * + * If the buf field is not set av_packet_ref() would make a copy instead + * of increasing the reference count. + * + * The side data is always allocated with av_malloc(), copied by + * av_packet_ref() and freed by av_packet_unref(). + * + * sizeof(AVPacket) being a part of the public ABI is deprecated. once + * av_init_packet() is removed, new packets will only be able to be allocated + * with av_packet_alloc(), and new fields may be added to the end of the struct + * with a minor bump. + * + * @see av_packet_alloc + * @see av_packet_ref + * @see av_packet_unref + */ +typedef struct AVPacket { + /** + * A reference to the reference-counted buffer where the packet data is + * stored. + * May be NULL, then the packet data is not reference-counted. + */ + AVBufferRef *buf; + /** + * Presentation timestamp in AVStream->time_base units; the time at which + * the decompressed packet will be presented to the user. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + * pts MUST be larger or equal to dts as presentation cannot happen before + * decompression, unless one wants to view hex dumps. Some formats misuse + * the terms dts and pts/cts to mean something different. Such timestamps + * must be converted to true pts/dts before they are stored in AVPacket. + */ + int64_t pts; + /** + * Decompression timestamp in AVStream->time_base units; the time at which + * the packet is decompressed. + * Can be AV_NOPTS_VALUE if it is not stored in the file. + */ + int64_t dts; + uint8_t *data; + int size; + int stream_index; + /** + * A combination of AV_PKT_FLAG values + */ + int flags; + /** + * Additional packet data that can be provided by the container. + * Packet can contain several types of side information. + */ + AVPacketSideData *side_data; + int side_data_elems; + + /** + * Duration of this packet in AVStream->time_base units, 0 if unknown. + * Equals next_pts - this_pts in presentation order. + */ + int64_t duration; + + int64_t pos; ///< byte position in stream, -1 if unknown + + /** + * for some private data of the user + */ + void *opaque; + + /** + * AVBufferRef for free use by the API user. FFmpeg will never check the + * contents of the buffer ref. FFmpeg calls av_buffer_unref() on it when + * the packet is unreferenced. av_packet_copy_props() calls create a new + * reference with av_buffer_ref() for the target packet's opaque_ref field. + * + * This is unrelated to the opaque field, although it serves a similar + * purpose. + */ + AVBufferRef *opaque_ref; + + /** + * Time base of the packet's timestamps. + * In the future, this field may be set on packets output by encoders or + * demuxers, but its value will be by default ignored on input to decoders + * or muxers. + */ + AVRational time_base; +} AVPacket; + +#define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe +#define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted +/** + * Flag is used to discard packets which are required to maintain valid + * decoder state but are not required for output and should be dropped + * after decoding. + **/ +#define AV_PKT_FLAG_DISCARD 0x0004 +/** + * The packet comes from a trusted source. + * + * Otherwise-unsafe constructs such as arbitrary pointers to data + * outside the packet may be followed. + */ +#define AV_PKT_FLAG_TRUSTED 0x0008 +/** + * Flag is used to indicate packets that contain frames that can + * be discarded by the decoder. I.e. Non-reference frames. + */ +#define AV_PKT_FLAG_DISPOSABLE 0x0010 + +enum AVSideDataParamChangeFlags { + AV_SIDE_DATA_PARAM_CHANGE_SAMPLE_RATE = 0x0004, + AV_SIDE_DATA_PARAM_CHANGE_DIMENSIONS = 0x0008, +}; + +/** + * Allocate an AVPacket and set its fields to default values. The resulting + * struct must be freed using av_packet_free(). + * + * @return An AVPacket filled with default values or NULL on failure. + * + * @note this only allocates the AVPacket itself, not the data buffers. Those + * must be allocated through other means such as av_new_packet. + * + * @see av_new_packet + */ +AVPacket *av_packet_alloc(void); + +/** + * Create a new packet that references the same data as src. + * + * This is a shortcut for av_packet_alloc()+av_packet_ref(). + * + * @return newly created AVPacket on success, NULL on error. + * + * @see av_packet_alloc + * @see av_packet_ref + */ +AVPacket *av_packet_clone(const AVPacket *src); + +/** + * Free the packet, if the packet is reference counted, it will be + * unreferenced first. + * + * @param pkt packet to be freed. The pointer will be set to NULL. + * @note passing NULL is a no-op. + */ +void av_packet_free(AVPacket **pkt); + +#if FF_API_INIT_PACKET +/** + * Initialize optional fields of a packet with default values. + * + * Note, this does not touch the data and size members, which have to be + * initialized separately. + * + * @param pkt packet + * + * @see av_packet_alloc + * @see av_packet_unref + * + * @deprecated This function is deprecated. Once it's removed, + sizeof(AVPacket) will not be a part of the ABI anymore. + */ +attribute_deprecated +void av_init_packet(AVPacket *pkt); +#endif + +/** + * Allocate the payload of a packet and initialize its fields with + * default values. + * + * @param pkt packet + * @param size wanted payload size + * @return 0 if OK, AVERROR_xxx otherwise + */ +int av_new_packet(AVPacket *pkt, int size); + +/** + * Reduce packet size, correctly zeroing padding + * + * @param pkt packet + * @param size new size + */ +void av_shrink_packet(AVPacket *pkt, int size); + +/** + * Increase packet size, correctly zeroing padding + * + * @param pkt packet + * @param grow_by number of bytes by which to increase the size of the packet + */ +int av_grow_packet(AVPacket *pkt, int grow_by); + +/** + * Initialize a reference-counted packet from av_malloc()ed data. + * + * @param pkt packet to be initialized. This function will set the data, size, + * and buf fields, all others are left untouched. + * @param data Data allocated by av_malloc() to be used as packet data. If this + * function returns successfully, the data is owned by the underlying AVBuffer. + * The caller may not access the data through other means. + * @param size size of data in bytes, without the padding. I.e. the full buffer + * size is assumed to be size + AV_INPUT_BUFFER_PADDING_SIZE. + * + * @return 0 on success, a negative AVERROR on error + */ +int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); + +/** + * Allocate new information of a packet. + * + * @param pkt packet + * @param type side information type + * @param size side information size + * @return pointer to fresh allocated data or NULL otherwise + */ +uint8_t* av_packet_new_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + size_t size); + +/** + * Wrap an existing array as a packet side data. + * + * @param pkt packet + * @param type side information type + * @param data the side data array. It must be allocated with the av_malloc() + * family of functions. The ownership of the data is transferred to + * pkt. + * @param size side information size + * @return a non-negative number on success, a negative AVERROR code on + * failure. On failure, the packet is unchanged and the data remains + * owned by the caller. + */ +int av_packet_add_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + uint8_t *data, size_t size); + +/** + * Shrink the already allocated side data buffer + * + * @param pkt packet + * @param type side information type + * @param size new side information size + * @return 0 on success, < 0 on failure + */ +int av_packet_shrink_side_data(AVPacket *pkt, enum AVPacketSideDataType type, + size_t size); + +/** + * Get side information from packet. + * + * @param pkt packet + * @param type desired side information type + * @param size If supplied, *size will be set to the size of the side data + * or to zero if the desired side data is not present. + * @return pointer to data if present or NULL otherwise + */ +uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType type, + size_t *size); + +/** + * Pack a dictionary for use in side_data. + * + * @param dict The dictionary to pack. + * @param size pointer to store the size of the returned data + * @return pointer to data if successful, NULL otherwise + */ +uint8_t *av_packet_pack_dictionary(const AVDictionary *dict, size_t *size); +/** + * Unpack a dictionary from side_data. + * + * @param data data from side_data + * @param size size of the data + * @param dict the metadata storage dictionary + * @return 0 on success, < 0 on failure + */ +int av_packet_unpack_dictionary(const uint8_t *data, size_t size, + AVDictionary **dict); + +/** + * Convenience function to free all the side data stored. + * All the other fields stay untouched. + * + * @param pkt packet + */ +void av_packet_free_side_data(AVPacket *pkt); + +/** + * Setup a new reference to the data described by a given packet + * + * If src is reference-counted, setup dst as a new reference to the + * buffer in src. Otherwise allocate a new buffer in dst and copy the + * data from src into it. + * + * All the other fields are copied from src. + * + * @see av_packet_unref + * + * @param dst Destination packet. Will be completely overwritten. + * @param src Source packet + * + * @return 0 on success, a negative AVERROR on error. On error, dst + * will be blank (as if returned by av_packet_alloc()). + */ +int av_packet_ref(AVPacket *dst, const AVPacket *src); + +/** + * Wipe the packet. + * + * Unreference the buffer referenced by the packet and reset the + * remaining packet fields to their default values. + * + * @param pkt The packet to be unreferenced. + */ +void av_packet_unref(AVPacket *pkt); + +/** + * Move every field in src to dst and reset src. + * + * @see av_packet_unref + * + * @param src Source packet, will be reset + * @param dst Destination packet + */ +void av_packet_move_ref(AVPacket *dst, AVPacket *src); + +/** + * Copy only "properties" fields from src to dst. + * + * Properties for the purpose of this function are all the fields + * beside those related to the packet data (buf, data, size) + * + * @param dst Destination packet + * @param src Source packet + * + * @return 0 on success AVERROR on failure. + */ +int av_packet_copy_props(AVPacket *dst, const AVPacket *src); + +/** + * Ensure the data described by a given packet is reference counted. + * + * @note This function does not ensure that the reference will be writable. + * Use av_packet_make_writable instead for that purpose. + * + * @see av_packet_ref + * @see av_packet_make_writable + * + * @param pkt packet whose data should be made reference counted. + * + * @return 0 on success, a negative AVERROR on error. On failure, the + * packet is unchanged. + */ +int av_packet_make_refcounted(AVPacket *pkt); + +/** + * Create a writable reference for the data described by a given packet, + * avoiding data copy if possible. + * + * @param pkt Packet whose data should be made writable. + * + * @return 0 on success, a negative AVERROR on failure. On failure, the + * packet is unchanged. + */ +int av_packet_make_writable(AVPacket *pkt); + +/** + * Convert valid timing fields (timestamps / durations) in a packet from one + * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be + * ignored. + * + * @param pkt packet on which the conversion will be performed + * @param tb_src source timebase, in which the timing fields in pkt are + * expressed + * @param tb_dst destination timebase, to which the timing fields will be + * converted + */ +void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); + +/** + * Allocate an AVContainerFifo instance for AVPacket. + * + * @param flags currently unused + */ +struct AVContainerFifo *av_container_fifo_alloc_avpacket(unsigned flags); + +/** + * @} + */ + +#endif // AVCODEC_PACKET_H diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/qsv.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/qsv.h new file mode 100644 index 000000000..c156b08d0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/qsv.h @@ -0,0 +1,109 @@ +/* + * Intel MediaSDK QSV public API + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_QSV_H +#define AVCODEC_QSV_H + +#include + +#include "libavutil/buffer.h" + +/** + * This struct is used for communicating QSV parameters between libavcodec and + * the caller. It is managed by the caller and must be assigned to + * AVCodecContext.hwaccel_context. + * - decoding: hwaccel_context must be set on return from the get_format() + * callback + * - encoding: hwaccel_context must be set before avcodec_open2() + */ +typedef struct AVQSVContext { + /** + * If non-NULL, the session to use for encoding or decoding. + * Otherwise, libavcodec will try to create an internal session. + */ + mfxSession session; + + /** + * The IO pattern to use. + */ + int iopattern; + + /** + * Extra buffers to pass to encoder or decoder initialization. + */ + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; + + /** + * Encoding only. If this field is set to non-zero by the caller, libavcodec + * will create an mfxExtOpaqueSurfaceAlloc extended buffer and pass it to + * the encoder initialization. This only makes sense if iopattern is also + * set to MFX_IOPATTERN_IN_OPAQUE_MEMORY. + * + * The number of allocated opaque surfaces will be the sum of the number + * required by the encoder and the user-provided value nb_opaque_surfaces. + * The array of the opaque surfaces will be exported to the caller through + * the opaque_surfaces field. + * + * The caller must set this field to zero for oneVPL (MFX_VERSION >= 2.0) + */ + int opaque_alloc; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. Before + * calling avcodec_open2(), the caller should set this field to the number + * of extra opaque surfaces to allocate beyond what is required by the + * encoder. + * + * On return from avcodec_open2(), this field will be set by libavcodec to + * the total number of allocated opaque surfaces. + */ + int nb_opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be used by libavcodec to export the + * array of the allocated opaque surfaces to the caller, so they can be + * passed to other parts of the pipeline. + * + * The buffer reference exported here is owned and managed by libavcodec, + * the callers should make their own reference with av_buffer_ref() and free + * it with av_buffer_unref() when it is no longer needed. + * + * The buffer data is an nb_opaque_surfaces-sized array of mfxFrameSurface1. + */ + AVBufferRef *opaque_surfaces; + + /** + * Encoding only, and only if opaque_alloc is set to non-zero. On return + * from avcodec_open2(), this field will be set to the surface type used in + * the opaque allocation request. + */ + int opaque_alloc_type; +} AVQSVContext; + +/** + * Allocate a new context. + * + * It must be freed by the caller with av_free(). + */ +AVQSVContext *av_qsv_alloc_context(void); + +#endif /* AVCODEC_QSV_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h new file mode 100644 index 000000000..9c0e2a5a0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h @@ -0,0 +1,254 @@ +/* + * MXF SMPTE-436M VBI/ANC parsing functions + * Copyright (c) 2025 Jacob Lifshay + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_SMPTE_436M_H +#define AVCODEC_SMPTE_436M_H + +#include + +/** + * Iterator over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data + */ +typedef struct AVSmpte436mAncIterator { + uint16_t anc_packets_left; + int size_left; + const uint8_t *data_left; +} AVSmpte436mAncIterator; + +/** + * Wrapping Type from Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mWrappingType +{ + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME = 1, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1 = 2, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2 = 3, + AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME = 4, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME = 0x11, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1 = 0x12, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2 = 0x13, + AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME = 0x14, + /** not a real wrapping type, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_WRAPPING_TYPE_MAX = 0xFF, +} AVSmpte436mWrappingType; + +/** + * Payload Sample Coding from Table 4 (page 10) and Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef enum AVSmpte436mPayloadSampleCoding +{ + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA = 1, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF = 2, + /** only used for VBI */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF = 3, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA = 4, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF = 5, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF = 6, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA = 7, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF = 8, + /** used for VBI and ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF = 9, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR = 10, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR = 11, + /** only used for ANC */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR = 12, + /** not a real sample coding, just here to guarantee the enum is big enough */ + AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_MAX = 0xFF, +} AVSmpte436mPayloadSampleCoding; + +/** the payload capacity of AVSmpte291mAnc8bit (and of AVSmpte291mAnc10bit when that gets added) */ +#define AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY 0xFF + +/** + * An ANC packet with an 8-bit payload. + * This can be decoded from AVSmpte436mCodedAnc::payload. + * + * Note: Some ANC packets need a 10-bit payload, if stored in this struct, + * the most-significant 2 bits of each sample are discarded. + */ +typedef struct AVSmpte291mAnc8bit { + uint8_t did; + uint8_t sdid_or_dbn; + uint8_t data_count; + uint8_t payload[AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY]; + uint8_t checksum; +} AVSmpte291mAnc8bit; + +/** max number of samples that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY \ + (AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY + 4) /* 4 for did, sdid_or_dbn, data_count, and checksum */ +/** max number of bytes that can be stored in the payload of AVSmpte436mCodedAnc */ +#define AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY (((AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY + 2) / 3) * 4) + +/** + * An encoded ANC packet within a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * The repeated section of Table 7 (page 13) of: + * https://pub.smpte.org/latest/st436/s436m-2006.pdf + */ +typedef struct AVSmpte436mCodedAnc { + uint16_t line_number; + AVSmpte436mWrappingType wrapping_type; + AVSmpte436mPayloadSampleCoding payload_sample_coding; + uint16_t payload_sample_count; + uint32_t payload_array_length; + /** the payload, has size payload_array_length. + * can be decoded into AVSmpte291mAnc8bit + */ + uint8_t payload[AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY]; +} AVSmpte436mCodedAnc; + +/** + * Validate a AVSmpte436mCodedAnc structure. Doesn't check if the payload is valid. + * @param[in] anc ANC packet to validate + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc); + +/** + * Encode ANC packets into a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param[in] size the size of out. ignored if out is NULL. + * @param[out] out Output bytes. Doesn't write anything if out is NULL. + * @return the number of bytes written on success, AVERROR codes otherwise. + * If out is NULL, returns the number of bytes it would have written. + */ +int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +struct AVPacket; + +/** + * Append more ANC packets to a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] anc_packet_count number of ANC packets to encode + * @param[in] anc_packets the ANC packets to encode + * @param pkt the AVPacket to append to. + * it must either be size 0 or contain valid SMPTE_436M_ANC data. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_append(struct AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); + +/** + * Set up iteration over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. + * @param[in] buf Pointer to the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[in] buf_size Size of the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. + * @param[out] iter Pointer to the iterator. + * @return 0 on success, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size); + +/** + * Get the next ANC packet from the iterator, advancing the iterator. + * @param[in,out] iter Pointer to the iterator. + * @param[out] anc The returned ANC packet. + * @return 0 on success, AVERROR_EOF when the iterator has reached the end, AVERROR codes otherwise. + */ +int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc); + +/** + * Get the minimum number of bytes needed to store a AVSmpte436mCodedAnc payload. + * @param sample_coding the payload sample coding + * @param sample_count the number of samples stored in the payload + * @return returns the minimum number of bytes needed, on error returns < 0. + * always <= SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY + */ +int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count); + +/** + * Decode a AVSmpte436mCodedAnc payload into AVSmpte291mAnc8bit + * @param[in] sample_coding the payload sample coding + * @param[in] sample_count the number of samples stored in the payload + * @param[in] payload the bytes storing the payload, + * the needed size can be obtained from + avpriv_smpte_436m_coded_anc_payload_size + * @param[in] log_ctx context pointer for av_log + * @param[out] out The decoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, + AVSmpte436mPayloadSampleCoding sample_coding, + uint16_t sample_count, + const uint8_t *payload, + void *log_ctx); + +/** + * Fill in the correct checksum for a AVSmpte291mAnc8bit + * @param[in,out] anc The ANC packet. + */ +void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc); + +/** + * Compute the sample count needed to encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc payload + * @param[in] anc The ANC packet. + * @param[in] sample_coding The sample coding. + * @param[in] log_ctx context pointer for av_log + * @return returns the sample count on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, + AVSmpte436mPayloadSampleCoding sample_coding, + void *log_ctx); + +/** + * Encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc + * @param[in] line_number the line number the ANC packet is on + * @param[in] wrapping_type the wrapping type + * @param[in] sample_coding the payload sample coding + * @param[in] payload the ANC packet to encode. + * @param[in] log_ctx context pointer for av_log + * @param[out] out The encoded ANC packet. + * @return returns 0 on success, otherwise < 0. + */ +int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, + uint16_t line_number, + AVSmpte436mWrappingType wrapping_type, + AVSmpte436mPayloadSampleCoding sample_coding, + const AVSmpte291mAnc8bit *payload, + void *log_ctx); + +/** AVSmpte291mAnc8bit::did when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_DID_CTA_708 0x61 + +/** AVSmpte291mAnc8bit::sdid_or_dbn when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ +#define AV_SMPTE_291M_ANC_SDID_CTA_708 0x1 + +/** + * Try to decode an ANC packet into EIA-608/CTA-708 data (AV_CODEC_ID_EIA_608). This + * @param[in] anc The ANC packet. + * @param[in] log_ctx Context pointer for av_log + * @param[out] cc_data the buffer to store the extracted EIA-608/CTA-708 data, + * you can pass NULL to not store the data. + * the required size is 3 * cc_count bytes. + * SMPTE_291M_ANC_PAYLOAD_CAPACITY is always enough size. + * @return returns cc_count (>= 0) on success, AVERROR(EAGAIN) if it wasn't a CTA-708 ANC packet, < 0 on error. + */ +int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx); + +#endif /* AVCODEC_SMPTE_436M_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h new file mode 100644 index 000000000..da77c5dae --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h @@ -0,0 +1,138 @@ +/* + * The Video Decode and Presentation API for UNIX (VDPAU) is used for + * hardware-accelerated decoding of MPEG-1/2, H.264 and VC-1. + * + * Copyright (C) 2008 NVIDIA + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VDPAU_H +#define AVCODEC_VDPAU_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_vdpau + * Public libavcodec VDPAU header. + */ + + +/** + * @defgroup lavc_codec_hwaccel_vdpau VDPAU Decoder and Renderer + * @ingroup lavc_codec_hwaccel + * + * VDPAU hardware acceleration has two modules + * - VDPAU decoding + * - VDPAU presentation + * + * The VDPAU decoding module parses all headers using FFmpeg + * parsing mechanisms and uses VDPAU for the actual decoding. + * + * As per the current implementation, the actual decoding + * and rendering (API calls) are done as part of the VDPAU + * presentation (vo_vdpau.c) module. + * + * @{ + */ + +#include + +#include "libavutil/avconfig.h" +#include "libavutil/attributes.h" + +#include "avcodec.h" + +struct AVCodecContext; +struct AVFrame; + +typedef int (*AVVDPAU_Render2)(struct AVCodecContext *, struct AVFrame *, + const VdpPictureInfo *, uint32_t, + const VdpBitstreamBuffer *); + +/** + * This structure is used to share data between the libavcodec library and + * the client video application. + * This structure will be allocated and stored in AVCodecContext.hwaccel_context + * by av_vdpau_bind_context(). Members can be set by the user once + * during initialization or through each AVCodecContext.get_buffer() + * function call. In any case, they must be valid prior to calling + * decoding functions. + * + * The size of this structure is not a part of the public ABI and must not + * be used outside of libavcodec. + */ +typedef struct AVVDPAUContext { + /** + * VDPAU decoder handle + * + * Set by user. + */ + VdpDecoder decoder; + + /** + * VDPAU decoder render callback + * + * Set by the user. + */ + VdpDecoderRender *render; + + AVVDPAU_Render2 render2; +} AVVDPAUContext; + +/** + * Associate a VDPAU device with a codec context for hardware acceleration. + * This function is meant to be called from the get_format() codec callback, + * or earlier. It can also be called after avcodec_flush_buffers() to change + * the underlying VDPAU device mid-stream (e.g. to recover from non-transparent + * display preemption). + * + * @note get_format() must return AV_PIX_FMT_VDPAU if this function completes + * successfully. + * + * @param avctx decoding context whose get_format() callback is invoked + * @param device VDPAU device handle to use for hardware acceleration + * @param get_proc_address VDPAU device driver + * @param flags zero of more OR'd AV_HWACCEL_FLAG_* flags + * + * @return 0 on success, an AVERROR code on failure. + */ +int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, + VdpGetProcAddress *get_proc_address, unsigned flags); + +/** + * Gets the parameters to create an adequate VDPAU video surface for the codec + * context using VDPAU hardware decoding acceleration. + * + * @note Behavior is undefined if the context was not successfully bound to a + * VDPAU device using av_vdpau_bind_context(). + * + * @param avctx the codec context being used for decoding the stream + * @param type storage space for the VDPAU video surface chroma type + * (or NULL to ignore) + * @param width storage space for the VDPAU video surface pixel width + * (or NULL to ignore) + * @param height storage space for the VDPAU video surface pixel height + * (or NULL to ignore) + * + * @return 0 on success, a negative AVERROR code on failure. + */ +int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, + uint32_t *width, uint32_t *height); + +/** @} */ + +#endif /* AVCODEC_VDPAU_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h new file mode 100644 index 000000000..7acb261bb --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.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 AVCODEC_VERSION_H +#define AVCODEC_VERSION_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#include "libavutil/version.h" + +#include "version_major.h" + +#define LIBAVCODEC_VERSION_MINOR 7 +#define LIBAVCODEC_VERSION_MICRO 100 + +#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_VERSION AV_VERSION(LIBAVCODEC_VERSION_MAJOR, \ + LIBAVCODEC_VERSION_MINOR, \ + LIBAVCODEC_VERSION_MICRO) +#define LIBAVCODEC_BUILD LIBAVCODEC_VERSION_INT + +#define LIBAVCODEC_IDENT "Lavc" AV_STRINGIFY(LIBAVCODEC_VERSION) + +#endif /* AVCODEC_VERSION_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h new file mode 100644 index 000000000..166646eb6 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.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 AVCODEC_VERSION_MAJOR_H +#define AVCODEC_VERSION_MAJOR_H + +/** + * @file + * @ingroup libavc + * Libavcodec version macros. + */ + +#define LIBAVCODEC_VERSION_MAJOR 63 + +/** + * 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_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 64) + +#define FF_API_INTRA_DC_PRECISION (LIBAVCODEC_VERSION_MAJOR < 64) +#define FF_API_MJPEG_EXTERN_HUFF (LIBAVCODEC_VERSION_MAJOR < 64) + +#endif /* AVCODEC_VERSION_MAJOR_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/videotoolbox.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/videotoolbox.h new file mode 100644 index 000000000..d68d76e40 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/videotoolbox.h @@ -0,0 +1,85 @@ +/* + * Videotoolbox hardware acceleration + * + * copyright (c) 2012 Sebastien Zwickert + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VIDEOTOOLBOX_H +#define AVCODEC_VIDEOTOOLBOX_H + +/** + * @file + * @ingroup lavc_codec_hwaccel_videotoolbox + * Public libavcodec Videotoolbox header. + */ + +/** + * @defgroup lavc_codec_hwaccel_videotoolbox VideoToolbox Decoder + * @ingroup lavc_codec_hwaccel + * + * Hardware accelerated decoding using VideoToolbox on Apple Platforms + * + * @{ + */ + +#include + +#define Picture QuickdrawPicture +#include +#undef Picture + +#include "libavcodec/avcodec.h" + +#include "libavutil/attributes.h" + +/** + * This struct holds all the information that needs to be passed + * between the caller and libavcodec for initializing Videotoolbox decoding. + * Its size is not a part of the public ABI, it must be allocated with + * av_videotoolbox_alloc_context() and freed with av_free(). + */ +typedef struct AVVideotoolboxContext { + /** + * Videotoolbox decompression session object. + */ + VTDecompressionSessionRef session; + + /** + * CVPixelBuffer Format Type that Videotoolbox will use for decoded frames. + * set by the caller. If this is set to 0, then no specific format is + * requested from the decoder, and its native format is output. + */ + OSType cv_pix_fmt_type; + + /** + * CoreMedia Format Description that Videotoolbox will use to create the decompression session. + */ + CMVideoFormatDescriptionRef cm_fmt_desc; + + /** + * CoreMedia codec type that Videotoolbox will use to create the decompression session. + */ + int cm_codec_type; +} AVVideotoolboxContext; + +/** + * @} + */ + +#endif /* AVCODEC_VIDEOTOOLBOX_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vorbis_parser.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vorbis_parser.h new file mode 100644 index 000000000..789932ac4 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vorbis_parser.h @@ -0,0 +1,74 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 public API for Vorbis parsing + * + * Determines the duration for each packet. + */ + +#ifndef AVCODEC_VORBIS_PARSER_H +#define AVCODEC_VORBIS_PARSER_H + +#include + +typedef struct AVVorbisParseContext AVVorbisParseContext; + +/** + * Allocate and initialize the Vorbis parser using headers in the extradata. + */ +AVVorbisParseContext *av_vorbis_parse_init(const uint8_t *extradata, + int extradata_size); + +/** + * Free the parser and everything associated with it. + */ +void av_vorbis_parse_free(AVVorbisParseContext **s); + +#define VORBIS_FLAG_HEADER 0x00000001 +#define VORBIS_FLAG_COMMENT 0x00000002 +#define VORBIS_FLAG_SETUP 0x00000004 + +/** + * Get the duration for a Vorbis packet. + * + * If @p flags is @c NULL, + * special frames are considered invalid. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + * @param flags flags for special frames + */ +int av_vorbis_parse_frame_flags(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size, int *flags); + +/** + * Get the duration for a Vorbis packet. + * + * @param s Vorbis parser context + * @param buf buffer containing a Vorbis frame + * @param buf_size size of the buffer + */ +int av_vorbis_parse_frame(AVVorbisParseContext *s, const uint8_t *buf, + int buf_size); + +void av_vorbis_parse_reset(AVVorbisParseContext *s); + +#endif /* AVCODEC_VORBIS_PARSER_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/adler32.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/adler32.h new file mode 100644 index 000000000..232d07f5f --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes.h new file mode 100644 index 000000000..4e7347368 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes.h @@ -0,0 +1,69 @@ +/* + * copyright (c) 2007 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_AES_H +#define AVUTIL_AES_H + +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes_ctr.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes_ctr.h new file mode 100644 index 000000000..d98c07122 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/aes_ctr.h @@ -0,0 +1,99 @@ +/* + * AES-CTR cipher + * Copyright (c) 2015 Eran Kornblau + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ambient_viewing_environment.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ambient_viewing_environment.h new file mode 100644 index 000000000..e5e4ac217 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ambient_viewing_environment.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 Jan Ekström + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h new file mode 100644 index 000000000..cd4c4338c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h @@ -0,0 +1,235 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @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 + +#if AV_HAS_STD_ATTRIBUTE(fallthrough) +# define av_fallthrough [[fallthrough]] +#elif AV_HAS_ATTRIBUTE(fallthrough) +# define av_fallthrough __attribute__((fallthrough)) +#else +# define av_fallthrough do {} while(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(__clang__ )) || AV_HAS_ATTRIBUTE(flatten) +# 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 +#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 + +#endif /* AVUTIL_ATTRIBUTES_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/audio_fifo.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/audio_fifo.h new file mode 100644 index 000000000..fa5f59a2b --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/audio_fifo.h @@ -0,0 +1,187 @@ +/* + * Audio FIFO + * Copyright (c) 2012 Justin Ruggles + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h new file mode 100644 index 000000000..e316a3c90 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h @@ -0,0 +1,125 @@ +/* + * copyright (c) 2010 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 + */ + +/** + * @file + * simple assert() macros that are a bit more flexible than ISO C assert(). + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_AVASSERT_H +#define AVUTIL_AVASSERT_H + +#include +#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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avconfig.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avconfig.h new file mode 100644 index 000000000..c289fbb55 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 1 +#endif /* AVUTIL_AVCONFIG_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h new file mode 100644 index 000000000..17f7b03db --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h new file mode 100644 index 000000000..003a63b7b --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h @@ -0,0 +1,340 @@ +/* + * copyright (c) 2006 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_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 + * LIBRARYNAME_VERSION_{MAJOR,MINOR,MICRO} 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< + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/blowfish.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/blowfish.h new file mode 100644 index 000000000..9e289a40d --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bprint.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bprint.h new file mode 100644 index 000000000..4ac857056 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h new file mode 100644 index 000000000..c1e6591ce --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h @@ -0,0 +1,105 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @file + * byte swapping routines + */ + +#ifndef AVUTIL_BSWAP_H +#define AVUTIL_BSWAP_H + +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/buffer.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/buffer.h new file mode 100644 index 000000000..e1ef5b7f0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/camellia.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/camellia.h new file mode 100644 index 000000000..96787102e --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cast5.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cast5.h new file mode 100644 index 000000000..ad5b347e6 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h new file mode 100644 index 000000000..5ad2d5ed9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2006 Michael Niedermayer + * 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 +#include + +#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 `` between AV_CHAN_AMBISONIC_BASE and + * AV_CHAN_AMBISONIC_END (inclusive), the ACN index of the channel `` is + * ` = - 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h new file mode 100644 index 000000000..cba78c5fd --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h @@ -0,0 +1,578 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @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 +#include +#include +#include +#include +#include +#include +#include + +#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<=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<> 31 & ((1U<= 2 + if (p > 31) abort(); +#endif + return a & ((1U << p) - 1); +} + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h new file mode 100644 index 000000000..ff9249311 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h new file mode 100644 index 000000000..c41686344 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h @@ -0,0 +1,152 @@ +/* + * 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 +#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_PMULL (1 <<17) +#define AV_CPU_FLAG_EOR3 (1 <<18) + +#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) +#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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/crc.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/crc.h new file mode 100644 index 000000000..7f59812a1 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/crc.h @@ -0,0 +1,102 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @file + * @ingroup lavu_crc32 + * Public header for CRC hash function implementation. + */ + +#ifndef AVUTIL_CRC_H +#define AVUTIL_CRC_H + +#include +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h new file mode 100644 index 000000000..9d75ccbb6 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015 Kevin Wheatley + * Copyright (c) 2016 Ronald S. Bultje + * Copyright (c) 2023 Leo Izen + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * @author Leo Izen + * @author Kevin Wheatley + */ + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/des.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/des.h new file mode 100644 index 000000000..3a3e6fa47 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/detection_bbox.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/detection_bbox.h new file mode 100644 index 000000000..011988052 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h new file mode 100644 index 000000000..93c7cbf12 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/display.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/display.h new file mode 100644 index 000000000..50f2b44ca --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/display.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2014 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h new file mode 100644 index 000000000..c102bf384 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2020 Vacing Fang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h new file mode 100644 index 000000000..cc0eafe94 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2014 Tim Walker + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 "avassert.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); + +/** + * This structure describes optional metadata relevant to a downmix procedure + * in the form of a remixing matrix allocated as an array of AVDownmixCoeff. + * Must be allocated with @ref av_downmix_matrix_alloc. + * + * sizeof(AVDownmixMatrix) is not a part of the ABI and new fields may be + * added to it. + */ +typedef struct AVDownmixMatrix { + /** + * Type of downmix the coeffs will produce. + * Output channel count is derived from this value. + */ + enum AVDownmixType downmix_type; + + /** + * Input channel count. + */ + int in_ch_count; + + /** + * Amount of coefficients in the matrix. + */ + unsigned int nb_coeffs; + + /** + * Offset in bytes from the beginning of this structure at which the array + * of coefficients starts. + */ + size_t coeffs_offset; +} AVDownmixMatrix; + +/** + * Data type for storing coefficients, which are allocated as a part of + * AVDownmixMatrix and should be retrieved with @ref av_downmix_matrix_coeff. + */ +typedef double AVDownmixCoeff; + +/** + * Get a pointer to the coeff that represents the weight of input channel + * {@code in} in output channel {@code out}. + * in must be between 0 and @ref AVDownmixMatrix.in_ch_count "in_ch_count" - 1. + * out must be between 0 and the implicit output channel count from + * @ref AVDownmixMatrix.downmix_type "downmix_type" - 1. + */ +static av_always_inline AVDownmixCoeff* +av_downmix_matrix_coeff(AVDownmixMatrix *dm, unsigned int out, unsigned int in) +{ + AVDownmixCoeff *coeff = (AVDownmixCoeff *)((uint8_t *)dm + dm->coeffs_offset); + return &coeff[in + dm->in_ch_count * out]; +} + +/** + * Allocates memory for AVDownmixMatrix of the given type, plus an array of + * {@code in_ch_count} times the implicit output channel count from {@code type} + * of AVDownmixCoeff 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. + */ +AVDownmixMatrix *av_downmix_matrix_alloc(enum AVDownmixType type, + int in_ch_count, size_t *out_size); + +/** + * @} + */ + +/** + * @} + */ + +#endif /* AVUTIL_DOWNMIX_INFO_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/encryption_info.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/encryption_info.h new file mode 100644 index 000000000..8fe7ebfe4 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/error.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/error.h new file mode 100644 index 000000000..1efa86c4c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/eval.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/eval.h new file mode 100644 index 000000000..0d3eaeb3f --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/eval.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2002 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 + */ + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/executor.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/executor.h new file mode 100644 index 000000000..0eb21c10c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h new file mode 100644 index 000000000..b9446dabd --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 "N-125978-g95c43d7df7-20260806" +#endif /* AVUTIL_FFVERSION_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/fifo.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/fifo.h new file mode 100644 index 000000000..f2206c35f --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/file.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/file.h new file mode 100644 index 000000000..fced17010 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h new file mode 100644 index 000000000..2915611c9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h new file mode 100644 index 000000000..e8cc765e5 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h @@ -0,0 +1,1221 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include + +#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, + + /** + * Exchangeable image file format metadata. The payload is a buffer containing + * EXIF metadata, starting with either 49 49 2a 00, or 4d 4d 00 2a. These four + * bytes signify the endianness, and occur as the first part of the TIFF header. + */ + AV_FRAME_DATA_EXIF, + + /** + * HDR dynamic metadata associated with a video frame. The payload is + * an AVDynamicHDRSmpte2094App5 type and contains information for color + * volume transform as specified in the SMPTE 2094-50 standard. + */ + AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5, + + /** + * IAMF Mix Gain Parameter Data associated with the audio frame. This metadata + * is in the form of the AVIAMFParamDefinition struct and contains information + * defined in sections 3.6.1 and 3.8.1 of the Immersive Audio Model and + * Formats standard. + */ + AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM, + + /** + * IAMF Demixing Info Parameter Data associated with the audio frame. This + * metadata is in the form of the AVIAMFParamDefinition struct and contains + * information defined in sections 3.6.1 and 3.8.2 of the Immersive Audio Model + * and Formats standard. + */ + AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM, + + /** + * IAMF Recon Gain Info Parameter Data associated with the audio frame. This + * metadata is in the form of the AVIAMFParamDefinition struct and contains + * information defined in sections 3.6.1 and 3.8.3 of the Immersive Audio Model + * and Formats standard. + */ + AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM, + + /** + * Color information from a RAW camera codecs, needed to correctly process + * the video data. The payload is an AVRawColorParams struct defined in + * libavutil/raw_color_params.h. + */ + AV_FRAME_DATA_RAW_COLOR_PARAMS, + + /** + * Metadata relevant to a downmix procedure in the form of a remixig matrix. + * The data is the AVDownmixMatrix struct defined in libavutil/downmix_info.h. + */ + AV_FRAME_DATA_DOWNMIX_MATRIX, +}; + +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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hash.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hash.h new file mode 100644 index 000000000..94151ded7 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hash.h @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h new file mode 100644 index 000000000..a051ac747 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h @@ -0,0 +1,480 @@ +/* + * Copyright (c) 2018 Mohammad Izadi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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); + +/** + * This struct represents dynamic metadata for color volume transform as + * specified in the SMPTE 2094-50 standard. + * + * To be used as payload of a AVFrameSideData or AVPacketSideData with the + * appropriate type. + * + * @note The struct should be allocated with + * av_dynamic_smpte2094_app5_alloc() and its size is not a part of + * the public ABI. + */ +typedef struct AVDynamicHDRSmpte2094App5 { + /** + * Section C.2.1. smpte_st_2094_50_application_info() + */ + uint8_t application_version; + uint8_t minimum_application_version; + + /** + * Section C.2.2 smpte_st_2094_50_color_volume_transform() + */ + uint8_t has_custom_hdr_reference_white_flag; + uint8_t has_adaptive_tone_map_flag; + uint16_t hdr_reference_white; + + /** + * Section C.2.3 smpte_st_2094_50_adaptive_tone_map() + */ + uint16_t baseline_hdr_headroom; + uint8_t use_reference_white_tone_mapping_flag; + uint8_t num_alternate_images; + uint8_t gain_application_space_chromaticities_flag; + uint8_t has_common_component_mix_params_flag; + uint8_t has_common_curve_params_flag; + uint16_t gain_application_space_chromaticities[8]; + uint16_t alternate_hdr_headrooms[4]; + + /** + * Section C.2.4 smpte_st_2094_50_component_mixing() + */ + uint8_t component_mixing_type[4]; + uint8_t has_component_mixing_coefficient_flag[4][6]; + uint16_t component_mixing_coefficient[4][6]; + + /** + * Section C.2.5 smpte_st_2094_50_gain_curve() + */ + uint8_t gain_curve_num_control_points_minus_1[4]; + uint8_t gain_curve_use_pchip_slope_flag[4]; + uint16_t gain_curve_control_points_x[4][32]; + uint16_t gain_curve_control_points_y[4][32]; + uint16_t gain_curve_control_points_theta[4][32]; +} AVDynamicHDRSmpte2094App5; + +/** + * Allocate an AVDynamicHDRSmpte2094App5 structure and set its fields to + * default values. The resulting struct can be freed using av_freep(). + * + * @return An AVDynamicHDRSmpte2094App5 filled with default values or NULL + * on failure. + */ +AVDynamicHDRSmpte2094App5* av_dynamic_hdr_smpte2094_app5_alloc(size_t* size); + +/** + * Allocate a complete AVDynamicHDRSmpte2094App5 and add it to the frame. + * + * @param frame The frame which side data is added to. + * + * @return The AVDynamicHDRSmpte2094App5 structure to be filled by caller or + * NULL on failure. + */ +AVDynamicHDRSmpte2094App5* av_dynamic_hdr_smpte2094_app5_create_side_data(AVFrame* frame); + +/** + * Parse the user data formatted as ITU-T T.35 message to AVDynamicHDRSmpte2094App5. + * + * @param s A pointer containing the decoded AVDynamicHDRSmpte2094App5 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_smpte2094_app5_from_t35(AVDynamicHDRSmpte2094App5* s, const uint8_t* data, + size_t size); + +/** + * Serialize dynamic SMPTE-2094-50 metadata to a ITU-T T.35 message. Excluding + * the country_code, provider_code and provider_oriented_code. + * + * @param s A pointer containing the AVDynamicHDRSmpte2094App5 data. + * @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_smpte2094_app5_to_t35(const AVDynamicHDRSmpte2094App5* s, uint8_t** data, + size_t* size); + +#endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h new file mode 100644 index 000000000..d45b4a0f6 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2021 Limin Wang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hmac.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hmac.h new file mode 100644 index 000000000..ca4da6a68 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h new file mode 100644 index 000000000..29374cf0a --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h new file mode 100644 index 000000000..918eec97b --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h @@ -0,0 +1,58 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_AMF_H +#define AVUTIL_HWCONTEXT_AMF_H + +#include "pixfmt.h" +#include "hwcontext.h" +#include +#include +#include +#include +#include +#include "libavutil/mastering_display_metadata.h" + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVAMFDeviceContext { + void * library; + AMFFactory *factory; + void *trace_writer; + + int64_t version; ///< version of AMF runtime + AMFContext *context; + AMF_MEMORY_TYPE memory_type; + + void (*lock)(void *lock_ctx); + void (*unlock)(void *lock_ctx); + void *lock_ctx; +} AVAMFDeviceContext; + +enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt); +enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt); + +enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM av_amf_get_color_profile(enum AVColorRange color_range, enum AVColorSpace color_space); +int av_amf_display_mastering_meta_to_hdrmeta(const AVMasteringDisplayMetadata *display_meta, AMFHDRMetadata *hdrmeta); +int av_amf_light_metadata_to_hdrmeta(const AVContentLightMetadata *light_meta, AMFHDRMetadata *hdrmeta); +int av_amf_extract_hdr_metadata(const AVFrame *frame, AMFHDRMetadata *hdrmeta); +int av_amf_attach_hdr_metadata(AVFrame *frame, const AMFHDRMetadata *hdrmeta); + +#endif /* AVUTIL_HWCONTEXT_AMF_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h new file mode 100644 index 000000000..38e536979 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h @@ -0,0 +1,146 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_CUDA_H +#define AVUTIL_HWCONTEXT_CUDA_H + +#ifndef CUDA_VERSION +#include +#endif + +#include + +#include "pixfmt.h" + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_CUDA. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a CUdeviceptr. + */ + +typedef struct AVCUDADeviceContextInternal AVCUDADeviceContextInternal; + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVCUDADeviceContext { + CUcontext cuda_ctx; + CUstream stream; + AVCUDADeviceContextInternal *internal; +} AVCUDADeviceContext; + +/** + * CUDA frame descriptor for pool allocation of AV_PIX_FMT_CUARRAY frames. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + * + * This has no use outside of custom allocation, and AVFrame AVBufferRef do not + * necessarily point to an instance of this struct. + */ +typedef struct AVCUDAArrayFrameDescriptor { + /** + * The CUarray containing the frame data. + * + * Normally stored in AVFrame.data[0]. + */ + CUarray array; + + /** + * The index into AVCUDAFramesContext.cuarray_surfaces, or 0 if not applicable. + * + * Normally stored in AVFrame.data[1] (cast from intptr_t). + */ + intptr_t index; +} AVCUDAArrayFrameDescriptor; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVCUDAFramesContext { + /** + * CUDA_ARRAY3D_DESCRIPTOR CUarrays will be initialized with. + * Mostly used to provide external Flags. + * + * Width, Height and Format only honored if != 0. + * Filled with default parameters from the FramesContext otherwise. + * + * Only applicable for AV_PIX_FMT_CUARRAY. + */ + CUDA_ARRAY3D_DESCRIPTOR cuarray_desc; + + /** + * If >0, pre-allocate a fixed pool of surfaces. + * The surfaces will be available via cuarray_surfaces after init. + * Size of the pool cannot be changed afterwards. + * + * Only applicable for AV_PIX_FMT_CUARRAY. + */ + int cuarray_num_surfaces; + + /** + * If cuarray_num_surfaces is >0, this contains the array of pre-allocated surfaces. + * + * Only applicable for AV_PIX_FMT_CUARRAY. + */ + CUarray *cuarray_surfaces; +} AVCUDAFramesContext; + +/** + * CUDA hardware pipeline configuration details. + * + * Passed to av_hwdevice_get_hwframe_constraints() to query + * per-hw-format constraints. When provided, valid_sw_formats + * will be filtered to only those compatible with the specified + * hw_format. + */ +typedef struct AVCUDAHWConfig { + /** + * The hardware pixel format to query constraints for. + * Must be AV_PIX_FMT_CUDA or AV_PIX_FMT_CUARRAY. + */ + enum AVPixelFormat hw_format; +} AVCUDAHWConfig; + +/** + * @defgroup hwcontext_cuda Device context creation flags + * + * Flags for av_hwdevice_ctx_create. + * + * @{ + */ + +/** + * Use primary device context instead of creating a new one. + */ +#define AV_CUDA_USE_PRIMARY_CONTEXT (1 << 0) + +/** + * Use current device context instead of creating a new one. + */ +#define AV_CUDA_USE_CURRENT_CONTEXT (1 << 1) + +/** + * @} + */ + +#endif /* AVUTIL_HWCONTEXT_CUDA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h new file mode 100644 index 000000000..b87b1e8fa --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h @@ -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 + */ + +#ifndef AVUTIL_HWCONTEXT_D3D11VA_H +#define AVUTIL_HWCONTEXT_D3D11VA_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_D3D11VA. + * + * The default pool implementation will be fixed-size if initial_pool_size is + * set (and allocate elements from an array texture). Otherwise it will allocate + * individual textures. Be aware that decoding requires a single array texture. + * + * Using sw_format==AV_PIX_FMT_YUV420P has special semantics, and maps to + * DXGI_FORMAT_420_OPAQUE. av_hwframe_transfer_data() is not supported for + * this format. Refer to MSDN for details. + * + * av_hwdevice_ctx_create() for this device type supports a key named "debug" + * for the AVDictionary entry. If this is set to any value, the device creation + * code will try to load various supported D3D debugging layers. + */ + +#include +#include + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVD3D11VADeviceContext { + /** + * Device used for texture creation and access. This can also be used to + * set the libavcodec decoding device. + * + * Must be set by the user. This is the only mandatory field - the other + * device context fields are set from this and are available for convenience. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11Device *device; + + /** + * If unset, this will be set from the device field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11DeviceContext *device_context; + + /** + * If unset, this will be set from the device field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11VideoDevice *video_device; + + /** + * If unset, this will be set from the device_context field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D11VideoContext *video_context; + + /** + * Callbacks for locking. They protect accesses to device_context and + * video_context calls. They also protect access to the internal staging + * texture (for av_hwframe_transfer_data() calls). They do NOT protect + * access to hwcontext or decoder state in general. + * + * If unset on init, the hwcontext implementation will set them to use an + * internal mutex. + * + * The underlying lock must be recursive. lock_ctx is for free use by the + * locking implementation. + */ + void (*lock)(void *lock_ctx); + void (*unlock)(void *lock_ctx); + void *lock_ctx; + /** + * D3D11_TEXTURE2D_DESC.BindFlags to be applied to D3D11 resources allocated + * for frames using this device context. + * + * It applies globally to all AVD3D11VAFramesContext allocated from this device context. + */ + UINT BindFlags; + /** + * D3D11_TEXTURE2D_DESC.MiscFlags to be applied to D3D11 resources allocated + * for frames using this device context. + * + * It applies globally to all AVD3D11VAFramesContext allocated from this device context. + */ + UINT MiscFlags; +} AVD3D11VADeviceContext; + +/** + * D3D11 frame descriptor for pool allocation. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + * + * This has no use outside of custom allocation, and AVFrame AVBufferRef do not + * necessarily point to an instance of this struct. + */ +typedef struct AVD3D11FrameDescriptor { + /** + * The texture in which the frame is located. The reference count is + * managed by the AVBufferRef, and destroying the reference will release + * the interface. + * + * Normally stored in AVFrame.data[0]. + */ + ID3D11Texture2D *texture; + + /** + * The index into the array texture element representing the frame, or 0 + * if the texture is not an array texture. + * + * Normally stored in AVFrame.data[1] (cast from intptr_t). + */ + intptr_t index; +} AVD3D11FrameDescriptor; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVD3D11VAFramesContext { + /** + * The canonical texture used for pool allocation. If this is set to NULL + * on init, the hwframes implementation will allocate and set an array + * texture if initial_pool_size > 0. + * + * The only situation when the API user should set this is: + * - the user wants to do manual pool allocation (setting + * AVHWFramesContext.pool), instead of letting AVHWFramesContext + * allocate the pool + * - of an array texture + * - and wants it to use it for decoding + * - this has to be done before calling av_hwframe_ctx_init() + * + * Deallocating the AVHWFramesContext will always release this interface, + * and it does not matter whether it was user-allocated. + * + * This is in particular used by the libavcodec D3D11VA hwaccel, which + * requires a single array texture. It will create ID3D11VideoDecoderOutputView + * objects for each array texture element on decoder initialization. + */ + ID3D11Texture2D *texture; + + /** + * D3D11_TEXTURE2D_DESC.BindFlags used for texture creation. The user must + * at least set D3D11_BIND_DECODER if the frames context is to be used for + * video decoding. + * This field is ignored/invalid if a user-allocated texture is provided. + */ + UINT BindFlags; + + /** + * D3D11_TEXTURE2D_DESC.MiscFlags used for texture creation. + * This field is ignored/invalid if a user-allocated texture is provided. + */ + UINT MiscFlags; + + /** + * In case if texture structure member above is not NULL contains the same texture + * pointer for all elements and different indexes into the array texture. + * In case if texture structure member above is NULL, all elements contains + * pointers to separate non-array textures and 0 indexes. + * This field is ignored/invalid if a user-allocated texture is provided. + */ + AVD3D11FrameDescriptor *texture_infos; +} AVD3D11VAFramesContext; + +#endif /* AVUTIL_HWCONTEXT_D3D11VA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h new file mode 100644 index 000000000..adbec8817 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h @@ -0,0 +1,209 @@ +/* + * Direct3D 12 HW acceleration. + * + * copyright (c) 2022-2023 Wu Jianhua + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_D3D12VA_H +#define AVUTIL_HWCONTEXT_D3D12VA_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_D3D12VA. + * + * AVHWFramesContext.pool must contain AVBufferRefs whose + * data pointer points to an AVD3D12VAFrame struct. + */ +#include +#include +#include +#include +#include + +/** + * @brief This struct is allocated as AVHWDeviceContext.hwctx + * + */ +typedef struct AVD3D12VADeviceContext { + /** + * Device used for objects creation and access. This can also be + * used to set the libavcodec decoding device. + * + * Can be set by the user. This is the only mandatory field - the other + * device context fields are set from this and are available for convenience. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D12Device *device; + + /** + * If unset, this will be set from the device field on init. + * + * Deallocating the AVHWDeviceContext will always release this interface, + * and it does not matter whether it was user-allocated. + */ + ID3D12VideoDevice *video_device; + + /** + * Callbacks for locking. They protect access to the internal staging + * texture (for av_hwframe_transfer_data() calls). They do NOT protect + * access to hwcontext or decoder state in general. + * + * If unset on init, the hwcontext implementation will set them to use an + * internal mutex. + * + * The underlying lock must be recursive. lock_ctx is for free use by the + * locking implementation. + */ + void (*lock)(void *lock_ctx); + void (*unlock)(void *lock_ctx); + void *lock_ctx; + + /** + * Resource flags to be applied to D3D12 resources allocated + * for frames using this device context. + * + * If unset, this will be D3D12_RESOURCE_FLAG_NONE. + * + * It applies globally to all AVD3D12VAFramesContext allocated from this device context. + */ + D3D12_RESOURCE_FLAGS resource_flags; + + /** + * Heap flags to be applied to D3D12 resources allocated + * for frames using this device context. + * + * If unset, this will be D3D12_HEAP_FLAG_NONE. + * + * It applies globally to all AVD3D12VAFramesContext allocated from this device context. + */ + D3D12_HEAP_FLAGS heap_flags; +} AVD3D12VADeviceContext; + +/** + * @brief This struct is used to sync d3d12 execution + * + */ +typedef struct AVD3D12VASyncContext { + /** + * D3D12 fence object + */ + ID3D12Fence *fence; + + /** + * A handle to the event object that's raised when the fence + * reaches a certain value. + */ + HANDLE event; + + /** + * The fence value used for sync + */ + uint64_t fence_value; +} AVD3D12VASyncContext; + +/** + * Define the behaviours of frame allocation. + */ +typedef enum AVD3D12VAFrameFlags { + AV_D3D12VA_FRAME_FLAG_NONE = 0, + + /** + * Indicates that frame data should be allocated using a texture array resource. + */ + AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY = (1 << 1), +} AVD3D12VAFrameFlags; + +/** + * @brief D3D12VA frame descriptor for pool allocation. + * + */ +typedef struct AVD3D12VAFrame { + /** + * The texture in which the frame is located. The reference count is + * managed by the AVBufferRef, and destroying the reference will release + * the interface. + */ + ID3D12Resource *texture; + + /** + * Index of the subresource within the texture. + * + * In texture array mode, this specifies the array slice index. + * When texture array mode is not used, this value is always 0. + */ + int subresource_index; + + /** + * The sync context for the texture + * + * @see: https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-overview#directx-12-fences + */ + AVD3D12VASyncContext sync_ctx; + + /** + * A combination of AVD3D12VAFrameFlags. + * Set by AVD3D12VAFramesContext. + */ + AVD3D12VAFrameFlags flags; +} AVD3D12VAFrame; + +/** + * @brief This struct is allocated as AVHWFramesContext.hwctx + * + */ +typedef struct AVD3D12VAFramesContext { + /** + * DXGI_FORMAT format. MUST be compatible with the pixel format. + * If unset, will be automatically set. + */ + DXGI_FORMAT format; + + /** + * Options for working with resources. + * If unset, this will be D3D12_RESOURCE_FLAG_NONE. + * + * @see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_flags + */ + D3D12_RESOURCE_FLAGS resource_flags; + + /** + * Options for working with heaps allocation when creating resources. + * If unset, this will be D3D12_HEAP_FLAG_NONE. + * + * @see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_flags + */ + D3D12_HEAP_FLAGS heap_flags; + + /** + * In texture array mode, the D3D12 uses the same texture array (resource)for all + * pictures. + */ + ID3D12Resource *texture_array; + + /** + * A combination of AVD3D12VAFrameFlags. Unless AV_D3D12VA_FRAME_FLAG_NONE is set, + * autodetected flags will be OR'd based on the device and frame features during + * av_hwframe_ctx_init(). + */ + AVD3D12VAFrameFlags flags; +} AVD3D12VAFramesContext; + +#endif /* AVUTIL_HWCONTEXT_D3D12VA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_drm.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_drm.h new file mode 100644 index 000000000..42709f215 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_drm.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_DRM_H +#define AVUTIL_HWCONTEXT_DRM_H + +#include +#include + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_DRM. + * + * Internal frame allocation is not currently supported - all frames + * must be allocated by the user. Thus AVHWFramesContext is always + * NULL, though this may change if support for frame allocation is + * added in future. + */ + +enum { + /** + * The maximum number of layers/planes in a DRM frame. + */ + AV_DRM_MAX_PLANES = 4 +}; + +/** + * DRM object descriptor. + * + * Describes a single DRM object, addressing it as a PRIME file + * descriptor. + */ +typedef struct AVDRMObjectDescriptor { + /** + * DRM PRIME fd for the object. + */ + int fd; + /** + * Total size of the object. + * + * (This includes any parts not which do not contain image data.) + */ + size_t size; + /** + * Format modifier applied to the object (DRM_FORMAT_MOD_*). + * + * If the format modifier is unknown then this should be set to + * DRM_FORMAT_MOD_INVALID. + */ + uint64_t format_modifier; +} AVDRMObjectDescriptor; + +/** + * DRM plane descriptor. + * + * Describes a single plane of a layer, which is contained within + * a single object. + */ +typedef struct AVDRMPlaneDescriptor { + /** + * Index of the object containing this plane in the objects + * array of the enclosing frame descriptor. + */ + int object_index; + /** + * Offset within that object of this plane. + */ + ptrdiff_t offset; + /** + * Pitch (linesize) of this plane. + */ + ptrdiff_t pitch; +} AVDRMPlaneDescriptor; + +/** + * DRM layer descriptor. + * + * Describes a single layer within a frame. This has the structure + * defined by its format, and will contain one or more planes. + */ +typedef struct AVDRMLayerDescriptor { + /** + * Format of the layer (DRM_FORMAT_*). + */ + uint32_t format; + /** + * Number of planes in the layer. + * + * This must match the number of planes required by format. + */ + int nb_planes; + /** + * Array of planes in this layer. + */ + AVDRMPlaneDescriptor planes[AV_DRM_MAX_PLANES]; +} AVDRMLayerDescriptor; + +/** + * DRM frame descriptor. + * + * This is used as the data pointer for AV_PIX_FMT_DRM_PRIME frames. + * It is also used by user-allocated frame pools - allocating in + * AVHWFramesContext.pool must return AVBufferRefs which contain + * an object of this type. + * + * The fields of this structure should be set such it can be + * imported directly by EGL using the EGL_EXT_image_dma_buf_import + * and EGL_EXT_image_dma_buf_import_modifiers extensions. + * (Note that the exact layout of a particular format may vary between + * platforms - we only specify that the same platform should be able + * to import it.) + * + * The total number of planes must not exceed AV_DRM_MAX_PLANES, and + * the order of the planes by increasing layer index followed by + * increasing plane index must be the same as the order which would + * be used for the data pointers in the equivalent software format. + */ +typedef struct AVDRMFrameDescriptor { + /** + * Number of DRM objects making up this frame. + */ + int nb_objects; + /** + * Array of objects making up the frame. + */ + AVDRMObjectDescriptor objects[AV_DRM_MAX_PLANES]; + /** + * Number of layers in the frame. + */ + int nb_layers; + /** + * Array of layers in the frame. + */ + AVDRMLayerDescriptor layers[AV_DRM_MAX_PLANES]; +} AVDRMFrameDescriptor; + +/** + * DRM device. + * + * Allocated as AVHWDeviceContext.hwctx. + */ +typedef struct AVDRMDeviceContext { + /** + * File descriptor of DRM device. + * + * This is used as the device to create frames on, and may also be + * used in some derivation and mapping operations. + * + * If no device is required, set to -1. + */ + int fd; +} AVDRMDeviceContext; + +#endif /* AVUTIL_HWCONTEXT_DRM_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_dxva2.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_dxva2.h new file mode 100644 index 000000000..e1b79bc0d --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_dxva2.h @@ -0,0 +1,75 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_DXVA2_H +#define AVUTIL_HWCONTEXT_DXVA2_H + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_DXVA2. + * + * Only fixed-size pools are supported. + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a pointer to IDirect3DSurface9. + */ + +#include +#include + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVDXVA2DeviceContext { + IDirect3DDeviceManager9 *devmgr; +} AVDXVA2DeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVDXVA2FramesContext { + /** + * The surface type (e.g. DXVA2_VideoProcessorRenderTarget or + * DXVA2_VideoDecoderRenderTarget). Must be set by the caller. + */ + DWORD surface_type; + + /** + * The surface pool. When an external pool is not provided by the caller, + * this will be managed (allocated and filled on init, freed on uninit) by + * libavutil. + */ + IDirect3DSurface9 **surfaces; + int nb_surfaces; + + /** + * Certain drivers require the decoder to be destroyed before the surfaces. + * To allow internally managed pools to work properly in such cases, this + * field is provided. + * + * If it is non-NULL, libavutil will call IDirectXVideoDecoder_Release() on + * it just before the internal surface pool is freed. + * + * This is for convenience only. Some code uses other methods to manage the + * decoder reference. + */ + IDirectXVideoDecoder *decoder_to_release; +} AVDXVA2FramesContext; + +#endif /* AVUTIL_HWCONTEXT_DXVA2_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_mediacodec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_mediacodec.h new file mode 100644 index 000000000..fc0263cab --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_mediacodec.h @@ -0,0 +1,61 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_MEDIACODEC_H +#define AVUTIL_HWCONTEXT_MEDIACODEC_H + +/** + * MediaCodec details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVMediaCodecDeviceContext { + /** + * android/view/Surface handle, to be filled by the user. + * + * This is the default surface used by decoders on this device. + */ + void *surface; + + /** + * Pointer to ANativeWindow. + * + * It both surface and native_window is NULL, try to create it + * automatically if create_window is true and OS support + * createPersistentInputSurface. + * + * It can be used as output surface for decoder and input surface for + * encoder. + */ + void *native_window; + + /** + * Enable createPersistentInputSurface automatically. + * + * Disabled by default. + * + * It can be enabled by setting this flag directly, or by setting + * AVDictionary of av_hwdevice_ctx_create(), with "create_window" as key. + * The second method is useful for ffmpeg cmdline, e.g., we can enable it + * via: + * -init_hw_device mediacodec=mediacodec,create_window=1 + */ + int create_window; +} AVMediaCodecDeviceContext; + +#endif /* AVUTIL_HWCONTEXT_MEDIACODEC_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h new file mode 100644 index 000000000..2794f85b7 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h @@ -0,0 +1,34 @@ +/* + * This file is part of FFmpeg. + * + * Copyright (c) 2025 Zhao Zhili + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_OH_H +#define AVUTIL_HWCONTEXT_OH_H + +/** + * OpenHarmony codec device + */ +typedef struct AVOHCodecDeviceContext { + /** + * Pointer to OHNativeWindow + */ + void *native_window; +} AVOHCodecDeviceContext; + +#endif /* AVUTIL_HWCONTEXT_OH_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h new file mode 100644 index 000000000..22702300a --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h @@ -0,0 +1,100 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_OPENCL_H +#define AVUTIL_HWCONTEXT_OPENCL_H + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "frame.h" + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_OPENCL. + * + * Pools allocated internally are always dynamic, and are primarily intended + * to be used in OpenCL-only cases. If interoperation is required, it is + * typically required to allocate frames in the other API and then map the + * frames context to OpenCL with av_hwframe_ctx_create_derived(). + */ + +/** + * OpenCL frame descriptor for pool allocation. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + */ +typedef struct AVOpenCLFrameDescriptor { + /** + * Number of planes in the frame. + */ + int nb_planes; + /** + * OpenCL image2d objects for each plane of the frame. + */ + cl_mem planes[AV_NUM_DATA_POINTERS]; +} AVOpenCLFrameDescriptor; + +/** + * OpenCL device details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVOpenCLDeviceContext { + /** + * The primary device ID of the device. If multiple OpenCL devices + * are associated with the context then this is the one which will + * be used for all operations internal to FFmpeg. + */ + cl_device_id device_id; + /** + * The OpenCL context which will contain all operations and frames on + * this device. + */ + cl_context context; + /** + * The default command queue for this device, which will be used by all + * frames contexts which do not have their own command queue. If not + * initialised by the user, a default queue will be created on the + * primary device. + */ + cl_command_queue command_queue; +} AVOpenCLDeviceContext; + +/** + * OpenCL-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVOpenCLFramesContext { + /** + * The command queue used for internal asynchronous operations on this + * device (av_hwframe_transfer_data(), av_hwframe_map()). + * + * If this is not set, the command queue from the associated device is + * used instead. + */ + cl_command_queue command_queue; +} AVOpenCLFramesContext; + +#endif /* AVUTIL_HWCONTEXT_OPENCL_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h new file mode 100644 index 000000000..3c16a8ab9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h @@ -0,0 +1,86 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_QSV_H +#define AVUTIL_HWCONTEXT_QSV_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_QSV. + * + * AVHWFramesContext.pool must contain AVBufferRefs whose data pointer points + * to a mfxFrameSurface1 struct. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVQSVDeviceContext { + mfxSession session; + /** + * The mfxLoader handle used for mfxSession creation + * + * This field is only available for oneVPL user. For non-oneVPL user, this + * field must be set to NULL. + * + * Filled by the user before calling av_hwdevice_ctx_init() and should be + * cast to mfxLoader handle. Deallocating the AVHWDeviceContext will always + * release this interface. + */ + void *loader; +} AVQSVDeviceContext; + +/** + * This struct is allocated as AVHWFramesContext.hwctx + */ +typedef struct AVQSVFramesContext { + /** + * A pointer to a mfxFrameSurface1 struct + * + * It is available when nb_surfaces is non-zero. + */ + mfxFrameSurface1 *surfaces; + + /** + * Number of frames in the pool + * + * It is 0 for dynamic frame pools or AVHWFramesContext.initial_pool_size + * for fixed frame pools. + * + * Note only oneVPL GPU runtime 2.9+ can support dynamic frame pools + * on d3d11va or vaapi + */ + int nb_surfaces; + + /** + * A combination of MFX_MEMTYPE_* describing the frame pool. + */ + int frame_type; + + /** + * A pointer to a mfxFrameInfo struct + * + * It is available when nb_surfaces is 0, all buffers allocated from the + * pool have the same mfxFrameInfo. + */ + mfxFrameInfo *info; +} AVQSVFramesContext; + +#endif /* AVUTIL_HWCONTEXT_QSV_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h new file mode 100644 index 000000000..82e4194a9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h @@ -0,0 +1,117 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VAAPI_H +#define AVUTIL_HWCONTEXT_VAAPI_H + +#include + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_VAAPI. + * + * Dynamic frame pools are supported, but note that any pool used as a render + * target is required to be of fixed size in order to be usable as an + * argument to vaCreateContext(). + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to a VASurfaceID. + */ + +enum { + /** + * The quirks field has been set by the user and should not be detected + * automatically by av_hwdevice_ctx_init(). + */ + AV_VAAPI_DRIVER_QUIRK_USER_SET = (1 << 0), + /** + * The driver does not destroy parameter buffers when they are used by + * vaRenderPicture(). Additional code will be required to destroy them + * separately afterwards. + */ + AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS = (1 << 1), + + /** + * The driver does not support the VASurfaceAttribMemoryType attribute, + * so the surface allocation code will not try to use it. + */ + AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE = (1 << 2), + + /** + * The driver does not support surface attributes at all. + * The surface allocation code will never pass them to surface allocation, + * and the results of the vaQuerySurfaceAttributes() call will be faked. + */ + AV_VAAPI_DRIVER_QUIRK_SURFACE_ATTRIBUTES = (1 << 3), +}; + +/** + * VAAPI connection details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVAAPIDeviceContext { + /** + * The VADisplay handle, to be filled by the user. + */ + VADisplay display; + /** + * Driver quirks to apply - this is filled by av_hwdevice_ctx_init(), + * with reference to a table of known drivers, unless the + * AV_VAAPI_DRIVER_QUIRK_USER_SET bit is already present. The user + * may need to refer to this field when performing any later + * operations using VAAPI with the same VADisplay. + */ + unsigned int driver_quirks; +} AVVAAPIDeviceContext; + +/** + * VAAPI-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVVAAPIFramesContext { + /** + * Set by the user to apply surface attributes to all surfaces in + * the frame pool. If null, default settings are used. + */ + VASurfaceAttrib *attributes; + int nb_attributes; + /** + * The surfaces IDs of all surfaces in the pool after creation. + * Only valid if AVHWFramesContext.initial_pool_size was positive. + * These are intended to be used as the render_targets arguments to + * vaCreateContext(). + */ + VASurfaceID *surface_ids; + int nb_surfaces; +} AVVAAPIFramesContext; + +/** + * VAAPI hardware pipeline configuration details. + * + * Allocated with av_hwdevice_hwconfig_alloc(). + */ +typedef struct AVVAAPIHWConfig { + /** + * ID of a VAAPI pipeline configuration. + */ + VAConfigID config_id; +} AVVAAPIHWConfig; + +#endif /* AVUTIL_HWCONTEXT_VAAPI_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vdpau.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vdpau.h new file mode 100644 index 000000000..1b7ea1e44 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vdpau.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 AVUTIL_HWCONTEXT_VDPAU_H +#define AVUTIL_HWCONTEXT_VDPAU_H + +#include + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_VDPAU. + * + * This API supports dynamic frame pools. AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a VdpVideoSurface. + */ + +/** + * This struct is allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVVDPAUDeviceContext { + VdpDevice device; + VdpGetProcAddress *get_proc_address; +} AVVDPAUDeviceContext; + +/** + * AVHWFramesContext.hwctx is currently not used + */ + +#endif /* AVUTIL_HWCONTEXT_VDPAU_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_videotoolbox.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_videotoolbox.h new file mode 100644 index 000000000..d35cfbb6c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_videotoolbox.h @@ -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 + */ + +#ifndef AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H +#define AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H + +#include + +#include + +#include "frame.h" +#include "pixfmt.h" + +/** + * @file + * An API-specific header for AV_HWDEVICE_TYPE_VIDEOTOOLBOX. + * + * This API supports frame allocation using a native CVPixelBufferPool + * instead of an AVBufferPool. + * + * If the API user sets a custom pool, AVHWFramesContext.pool must return + * AVBufferRefs whose data pointer is a CVImageBufferRef or CVPixelBufferRef. + * Note that the underlying CVPixelBuffer could be retained by OS frameworks + * depending on application usage, so it is preferable to let CoreVideo manage + * the pool using the default implementation. + * + * Currently AVHWDeviceContext.hwctx are always NULL. + */ + +typedef struct AVVTFramesContext { + enum AVColorRange color_range; +} AVVTFramesContext; + +/** + * Convert a VideoToolbox (actually CoreVideo) format to AVPixelFormat. + * Returns AV_PIX_FMT_NONE if no known equivalent was found. + */ +enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt); + +/** + * Convert an AVPixelFormat to a VideoToolbox (actually CoreVideo) format. + * Returns 0 if no known equivalent was found. + */ +uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt); + +/** + * Same as av_map_videotoolbox_format_from_pixfmt function, but can map and + * return full range pixel formats via a flag. + */ +uint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range); + +/** + * Convert an AVChromaLocation to a VideoToolbox/CoreVideo chroma location string. + * Returns 0 if no known equivalent was found. + */ +CFStringRef av_map_videotoolbox_chroma_loc_from_av(enum AVChromaLocation loc); + +/** + * Convert an AVColorSpace to a VideoToolbox/CoreVideo color matrix string. + * Returns 0 if no known equivalent was found. + */ +CFStringRef av_map_videotoolbox_color_matrix_from_av(enum AVColorSpace space); + +/** + * Convert an AVColorPrimaries to a VideoToolbox/CoreVideo color primaries string. + * Returns 0 if no known equivalent was found. + */ +CFStringRef av_map_videotoolbox_color_primaries_from_av(enum AVColorPrimaries pri); + +/** + * Convert an AVColorTransferCharacteristic to a VideoToolbox/CoreVideo color transfer + * function string. + * Returns 0 if no known equivalent was found. + */ +CFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteristic trc); + +/** + * Set CVPixelBufferRef's metadata based on an AVFrame. + * + * Sets/unsets the CVPixelBuffer attachments to match as closely as possible the + * AVFrame metadata. To prevent inconsistent attachments, the attachments for properties + * that could not be matched or are unspecified in the given AVFrame are unset. So if + * any attachments already covered by AVFrame metadata need to be set to a specific + * value, this should happen after calling this function. + * + * Returns < 0 in case of an error. + */ +int av_vt_pixbuf_set_attachments(void *log_ctx, + CVPixelBufferRef pixbuf, const struct AVFrame *src); + +#endif /* AVUTIL_HWCONTEXT_VIDEOTOOLBOX_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h new file mode 100644 index 000000000..87c2a2d28 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h @@ -0,0 +1,355 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_VULKAN_H +#define AVUTIL_HWCONTEXT_VULKAN_H + +#if defined(_WIN32) && !defined(VK_USE_PLATFORM_WIN32_KHR) +#define VK_USE_PLATFORM_WIN32_KHR +#endif +#include + +#include "pixfmt.h" +#include "frame.h" +#include "hwcontext.h" + +typedef struct AVVkFrame AVVkFrame; + +typedef struct AVVulkanDeviceQueueFamily { + /* Queue family index */ + int idx; + /* Number of queues in the queue family in use */ + int num; + /* Queue family capabilities. Must be non-zero. + * Flags may be removed to indicate the queue family may not be used + * for a given purpose. */ + VkQueueFlagBits flags; + /* Vulkan implementations are allowed to list multiple video queues + * which differ in what they can encode or decode. */ + VkVideoCodecOperationFlagBitsKHR video_caps; +} AVVulkanDeviceQueueFamily; + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_VULKAN. + * + * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer set to an AVVkFrame. + */ + +/** + * Main Vulkan context, allocated as AVHWDeviceContext.hwctx. + * All of these can be set before init to change what the context uses + */ +typedef struct AVVulkanDeviceContext { + /** + * Custom memory allocator, else NULL + */ + const VkAllocationCallbacks *alloc; + + /** + * Pointer to a vkGetInstanceProcAddr loading function. + * If unset, will dynamically load and use libvulkan. + */ + PFN_vkGetInstanceProcAddr get_proc_addr; + + /** + * Vulkan instance. Must be at least version 1.3. + */ + VkInstance inst; + + /** + * Physical device + */ + VkPhysicalDevice phys_dev; + + /** + * Active device + */ + VkDevice act_dev; + + /** + * This structure should be set to the set of features that present and enabled + * during device creation. When a device is created by FFmpeg, it will default to + * enabling all that are present of the shaderImageGatherExtended, + * fragmentStoresAndAtomics, shaderInt64 and vertexPipelineStoresAndAtomics features. + */ + VkPhysicalDeviceFeatures2 device_features; + + /** + * Enabled instance extensions. + * If supplying your own device context, set this to an array of strings, with + * each entry containing the specified Vulkan extension string to enable. + * Duplicates are possible and accepted. + * If no extensions are enabled, set these fields to NULL, and 0 respectively. + * av_vk_get_optional_instance_extensions() can be used to enumerate extensions + * that FFmpeg may use if enabled. + */ + const char * const *enabled_inst_extensions; + int nb_enabled_inst_extensions; + + /** + * Enabled device extensions. By default, VK_KHR_external_memory_fd, + * VK_EXT_external_memory_dma_buf, VK_EXT_image_drm_format_modifier, + * VK_KHR_external_semaphore_fd and VK_EXT_external_memory_host are enabled if found. + * If supplying your own device context, these fields takes the same format as + * the above fields, with the same conditions that duplicates are possible + * and accepted, and that NULL and 0 respectively means no extensions are enabled. + * av_vk_get_optional_device_extensions() can be used to enumerate extensions + * that FFmpeg may use if enabled. + */ + const char * const *enabled_dev_extensions; + int nb_enabled_dev_extensions; + +#if FF_API_VULKAN_SYNC_QUEUES + /** + * Locks a queue, preventing other threads from submitting any command + * buffers to this queue. + * If set to NULL, will be set to lavu-internal functions that utilize a + * mutex. + * + * Deprecated: use VK_KHR_internally_synchronized_queues. + */ + attribute_deprecated + void (*lock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index); + + /** + * Similar to lock_queue(), unlocks a queue. Must only be called after locking. + * + * Deprecated: use VK_KHR_internally_synchronized_queues. + */ + attribute_deprecated + void (*unlock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index); +#endif + + /** + * Queue families used. Must be preferentially ordered. List may contain + * duplicates. + * + * For compatibility reasons, all the enabled queue families listed above + * (queue_family_(tx/comp/encode/decode)_index) must also be included in + * this list until they're removed after deprecation. + */ + AVVulkanDeviceQueueFamily qf[64]; + int nb_qf; + + /* Queue creation flags, for vkGetDeviceQueue2. */ + VkDeviceQueueCreateFlags queue_flags; +} AVVulkanDeviceContext; + +/** + * Defines the behaviour of frame allocation. + */ +typedef enum AVVkFrameFlags { + /* Unless this flag is set, autodetected flags will be OR'd based on the + * device and tiling during av_hwframe_ctx_init(). */ + AV_VK_FRAME_FLAG_NONE = (1ULL << 0), + + /* Disables multiplane images. + * This is required to export/import images from CUDA. */ + AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE = (1ULL << 2), +} AVVkFrameFlags; + +/** + * Allocated as AVHWFramesContext.hwctx, used to set pool-specific options + */ +typedef struct AVVulkanFramesContext { + /** + * Controls the tiling of allocated frames. + * If left as VK_IMAGE_TILING_OPTIMAL (0), will use optimal tiling. + * Can be set to VK_IMAGE_TILING_LINEAR to force linear images, + * or VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT to force DMABUF-backed + * images. + * @note Imported frames from other APIs ignore this. + */ + VkImageTiling tiling; + + /** + * Defines extra usage of output frames. If non-zero, all flags MUST be + * supported by the VkFormat. Regardless, frames will always have the + * following usage flags enabled, if supported by the format: + * - VK_IMAGE_USAGE_SAMPLED_BIT + * - VK_IMAGE_USAGE_STORAGE_BIT + * - VK_IMAGE_USAGE_TRANSFER_SRC_BIT + * - VK_IMAGE_USAGE_TRANSFER_DST_BIT + */ + VkImageUsageFlagBits usage; + + /** + * Extension data for image creation. + * If DRM tiling is used, a VkImageDrmFormatModifierListCreateInfoEXT structure + * can be added to specify the exact modifier to use. + * + * Additional structures may be added at av_hwframe_ctx_init() time, + * which will be freed automatically on uninit(), so users must only free + * any structures they've allocated themselves. + */ + void *create_pnext; + + /** + * Extension data for memory allocation. Must have as many entries as + * the number of planes of the sw_format. + * This will be chained to VkExportMemoryAllocateInfo, which is used + * to make all pool images exportable to other APIs if the necessary + * extensions are present in enabled_dev_extensions. + */ + void *alloc_pnext[AV_NUM_DATA_POINTERS]; + + /** + * A combination of AVVkFrameFlags. Unless AV_VK_FRAME_FLAG_NONE is set, + * autodetected flags will be OR'd based on the device and tiling during + * av_hwframe_ctx_init(). + */ + AVVkFrameFlags flags; + + /** + * Flags to set during image creation. If unset, defaults to + * VK_IMAGE_CREATE_ALIAS_BIT. + */ + VkImageCreateFlags img_flags; + + /** + * Vulkan format for each image. MUST be compatible with the pixel format. + * If unset, will be automatically set. + * There are at most two compatible formats for a frame - a multiplane + * format, and a single-plane multi-image format. + */ + VkFormat format[AV_NUM_DATA_POINTERS]; + + /** + * Number of layers each image will have. + */ + int nb_layers; + + /** + * Locks a frame, preventing other threads from changing frame properties. + * Users SHOULD only ever lock just before command submission in order + * to get accurate frame properties, and unlock immediately after command + * submission without waiting for it to finish. + * + * If unset, will be set to lavu-internal functions that utilize a mutex. + */ + void (*lock_frame)(struct AVHWFramesContext *fc, AVVkFrame *vkf); + + /** + * Similar to lock_frame(), unlocks a frame. Must only be called after locking. + */ + void (*unlock_frame)(struct AVHWFramesContext *fc, AVVkFrame *vkf); +} AVVulkanFramesContext; + +/* + * Frame structure. + * + * @note the size of this structure is not part of the ABI, to allocate + * you must use @av_vk_frame_alloc(). + */ +struct AVVkFrame { + /** + * Vulkan images to which the memory is bound to. + * May be one for multiplane formats, or multiple. + */ + VkImage img[AV_NUM_DATA_POINTERS]; + + /** + * Tiling for the frame. + */ + VkImageTiling tiling; + + /** + * Memory backing the images. Either one, or as many as there are planes + * in the sw_format. + * In case of having multiple VkImages, but one memory, the offset field + * will indicate the bound offset for each image. + */ + VkDeviceMemory mem[AV_NUM_DATA_POINTERS]; + size_t size[AV_NUM_DATA_POINTERS]; + + /** + * OR'd flags for all memory allocated + */ + VkMemoryPropertyFlagBits flags; + + /** + * Updated after every barrier. One per VkImage. + */ + VkAccessFlagBits2 access[AV_NUM_DATA_POINTERS]; + VkImageLayout layout[AV_NUM_DATA_POINTERS]; + + /** + * Synchronization timeline semaphores, one for each VkImage. + * Must not be freed manually. Must be waited on at every submission using + * the value in sem_value, and must be signalled at every submission, + * using an incremented value. + */ + VkSemaphore sem[AV_NUM_DATA_POINTERS]; + + /** + * Up to date semaphore value at which each image becomes accessible. + * One per VkImage. + * Clients must wait on this value when submitting a command queue, + * and increment it when signalling. + */ + uint64_t sem_value[AV_NUM_DATA_POINTERS]; + + /** + * Describes the binding offset of each image to the VkDeviceMemory. + * One per VkImage. + */ + ptrdiff_t offset[AV_NUM_DATA_POINTERS]; + + /** + * Queue family of the images. Must be VK_QUEUE_FAMILY_IGNORED if + * the image was allocated with the CONCURRENT concurrency option. + * One per VkImage. + */ + uint32_t queue_family[AV_NUM_DATA_POINTERS]; + + /** + * Internal data. Not to be accessed by users in any way. + */ + struct AVVkFrameInternal *internal; +}; + +/** + * Allocates a single AVVkFrame and initializes everything as 0. + * @note Must be freed via av_free() + */ +AVVkFrame *av_vk_frame_alloc(void); + +/** + * Returns the optimal per-plane Vulkan format for a given sw_format, + * one for each plane. + * Returns NULL on unsupported formats. + */ +const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p); + +/** + * Returns an array of optional Vulkan instance extensions that FFmpeg + * may use if enabled. + * @note Must be freed via av_free() + */ +const char **av_vk_get_optional_instance_extensions(int *count); + +/** + * Returns an array of optional Vulkan device extensions that FFmpeg + * may use if enabled. + * @note Must be freed via av_free() + */ +const char **av_vk_get_optional_device_extensions(int *count); + +#endif /* AVUTIL_HWCONTEXT_VULKAN_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h new file mode 100644 index 000000000..a755e7d68 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 Immersive Audio Model and Formats + */ + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/imgutils.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/imgutils.h new file mode 100644 index 000000000..123a9e5c0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intfloat.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intfloat.h new file mode 100644 index 000000000..fe3d7ec4a --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intreadwrite.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/intreadwrite.h new file mode 100644 index 000000000..ffd15a150 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h new file mode 100644 index 000000000..043d0ab34 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h new file mode 100644 index 000000000..4a111ca9a --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h @@ -0,0 +1,427 @@ +/* + * copyright (c) 2006 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_LOG_H +#define AVUTIL_LOG_H + +#include +#include "attributes.h" +#include "version.h" + +typedef enum { + AV_CLASS_CATEGORY_NA = 0, + AV_CLASS_CATEGORY_INPUT, + AV_CLASS_CATEGORY_OUTPUT, + AV_CLASS_CATEGORY_MUXER, + AV_CLASS_CATEGORY_DEMUXER, + AV_CLASS_CATEGORY_ENCODER, + AV_CLASS_CATEGORY_DECODER, + AV_CLASS_CATEGORY_FILTER, + AV_CLASS_CATEGORY_BITSTREAM_FILTER, + AV_CLASS_CATEGORY_SWSCALER, + AV_CLASS_CATEGORY_SWRESAMPLER, + AV_CLASS_CATEGORY_HWDEVICE, + AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT = 40, + AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT, + AV_CLASS_CATEGORY_DEVICE_OUTPUT, + AV_CLASS_CATEGORY_DEVICE_INPUT, + AV_CLASS_CATEGORY_NB ///< not part of ABI/API +}AVClassCategory; + +enum AVClassStateFlags { + /** + * Object initialization has finished and it is now in the 'runtime' stage. + * This affects e.g. what options can be set on the object (only + * AV_OPT_FLAG_RUNTIME_PARAM options can be set on initialized objects). + */ + AV_CLASS_STATE_INITIALIZED = (1 << 0), +}; + +#define AV_IS_INPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_INPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_INPUT)) + +#define AV_IS_OUTPUT_DEVICE(category) \ + (((category) == AV_CLASS_CATEGORY_DEVICE_VIDEO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_AUDIO_OUTPUT) || \ + ((category) == AV_CLASS_CATEGORY_DEVICE_OUTPUT)) + +struct AVOptionRanges; + +/** + * Describe the class of an AVClass context structure. That is an + * arbitrary struct of which the first field is a pointer to an + * AVClass struct (e.g. AVCodecContext, AVFormatContext etc.). + */ +typedef struct AVClass { + /** + * The name of the class; usually it is the same name as the + * context structure type to which the AVClass is associated. + */ + const char* class_name; + + /** + * A pointer to a function which returns the name of a context + * instance ctx associated with the class. + */ + const char* (*item_name)(void* ctx); + + /** + * An array of options for the structure or NULL. + * When non-NULL, the array must be terminated by an option with a NULL + * name. + * + * @see av_set_default_options() + */ + const struct AVOption *option; + + /** + * LIBAVUTIL_VERSION with which this structure was created. + * This is used to allow fields to be added to AVClass without requiring + * major version bumps everywhere. + */ + + int version; + + /** + * Offset in the structure where the log level offset is stored. The log + * level offset is an int added to the log level for logging with this + * object as the context. + * + * 0 means there is no such variable. + */ + int log_level_offset_offset; + + /** + * Offset in the structure where a pointer to the parent context for + * logging is stored. For example a decoder could pass its AVCodecContext + * to eval as such a parent context, which an ::av_log() implementation + * could then leverage to display the parent context. + * + * When the pointer is NULL, or this offset is zero, the object is assumed + * to have no parent. + */ + int parent_log_context_offset; + + /** + * Category used for visualization (like color). + * + * Only used when ::get_category() is NULL. Use this field when all + * instances of this class have the same category, use ::get_category() + * otherwise. + */ + AVClassCategory category; + + /** + * Callback to return the instance category. Use this callback when + * different instances of this class may have different categories, + * ::category otherwise. + */ + AVClassCategory (*get_category)(void* ctx); + + /** + * Callback to return the supported/allowed ranges. + */ + int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); + + /** + * Return next AVOptions-enabled child or NULL + */ + void* (*child_next)(void *obj, void *prev); + + /** + * Iterate over the AVClasses corresponding to potential AVOptions-enabled + * children. + * + * @param iter pointer to opaque iteration state. The caller must initialize + * *iter to NULL before the first call. + * @return AVClass for the next AVOptions-enabled child or NULL if there are + * no more such children. + * + * @note The difference between ::child_next() and ::child_class_iterate() + * is that ::child_next() iterates over _actual_ children of an + * _existing_ object instance, while ::child_class_iterate() iterates + * over the classes of all _potential_ children of any possible + * instance of this class. + */ + const struct AVClass* (*child_class_iterate)(void **iter); + + /** + * When non-zero, offset in the object to an unsigned int holding object + * state flags, a combination of AVClassStateFlags values. The flags are + * updated by the object to signal its state to the generic code. + * + * Added in version 59.41.100. + */ + int state_flags_offset; +} AVClass; + +/** + * @addtogroup lavu_log + * + * @{ + * + * @defgroup lavu_log_constants Logging Constants + * + * @{ + */ + +/** + * Print no output. + */ +#define AV_LOG_QUIET -8 + +/** + * Something went really wrong and we will crash now. + */ +#define AV_LOG_PANIC 0 + +/** + * Something went wrong and recovery is not possible. + * For example, no header was found for a format which depends + * on headers or an illegal combination of parameters is used. + */ +#define AV_LOG_FATAL 8 + +/** + * Something went wrong and cannot losslessly be recovered. + * However, not all future data is affected. + */ +#define AV_LOG_ERROR 16 + +/** + * Something somehow does not look correct. This may or may not + * lead to problems. An example would be the use of '-vstrict -2'. + */ +#define AV_LOG_WARNING 24 + +/** + * Standard information. + */ +#define AV_LOG_INFO 32 + +/** + * Detailed information. + */ +#define AV_LOG_VERBOSE 40 + +/** + * Stuff which is only useful for libav* developers. + */ +#define AV_LOG_DEBUG 48 + +/** + * Extremely verbose debugging, useful for libav* development. + */ +#define AV_LOG_TRACE 56 + +#define AV_LOG_MAX_OFFSET (AV_LOG_TRACE - AV_LOG_QUIET) + +/** + * @} + */ + +/** + * Sets additional colors for extended debugging sessions. + * @code + av_log(ctx, AV_LOG_DEBUG|AV_LOG_C(134), "Message in purple\n"); + @endcode + * Requires 256color terminal support. Uses outside debugging is not + * recommended. + */ +#define AV_LOG_C(x) ((x) << 8) + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + */ +void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); + +/** + * Send the specified message to the log once with the initial_level and then with + * the subsequent_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct or NULL if general log. + * @param initial_level importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant" for the first occurrence. + * @param subsequent_level importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant" after the first occurrence. + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param state a variable to keep trak of if a message has already been printed + * this must be initialized to 0 before the first use. The same state + * must not be accessed by 2 Threads simultaneously. + */ +void av_log_once(void* avcl, int initial_level, int subsequent_level, int *state, const char *fmt, ...) av_printf_format(5, 6); + + +/** + * Send the specified message to the log if the level is less than or equal + * to the current av_log_level. By default, all logging messages are sent to + * stderr. This behavior can be altered by setting a different logging callback + * function. + * @see av_log_set_callback + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_vlog(void *avcl, int level, const char *fmt, va_list vl); + +/** + * Get the current log level + * + * @see lavu_log_constants + * + * @return Current log level + */ +int av_log_get_level(void); + +/** + * Set the log level + * + * @see lavu_log_constants + * + * @param level Logging level + */ +void av_log_set_level(int level); + +/** + * Set the logging callback + * + * @note The callback must be thread safe, even if the application does not use + * threads itself as some codecs are multithreaded. + * + * @see av_log_default_callback + * + * @param callback A logging function with a compatible signature. + */ +void av_log_set_callback(void (*callback)(void*, int, const char*, va_list)); + +/** + * Default logging callback + * + * It prints the message to stderr, optionally colorizing it. + * + * @param avcl A pointer to an arbitrary struct of which the first field is a + * pointer to an AVClass struct. + * @param level The importance level of the message expressed using a @ref + * lavu_log_constants "Logging Constant". + * @param fmt The format string (printf-compatible) that specifies how + * subsequent arguments are converted to output. + * @param vl The arguments referenced by the format string. + */ +void av_log_default_callback(void *avcl, int level, const char *fmt, + va_list vl); + +/** + * Return the context name + * + * @param ctx The AVClass context + * + * @return The AVClass class_name + */ +const char* av_default_item_name(void* ctx); +AVClassCategory av_default_get_category(void *ptr); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line + * @param line_size size of the buffer + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + */ +void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Format a line of log the same way as the default callback. + * @param line buffer to receive the formatted line; + * may be NULL if line_size is 0 + * @param line_size size of the buffer; at most line_size-1 characters will + * be written to the buffer, plus one null terminator + * @param print_prefix used to store whether the prefix must be printed; + * must point to a persistent integer initially set to 1 + * @return Returns a negative value if an error occurred, otherwise returns + * the number of characters that would have been written for a + * sufficiently large buffer, not including the terminating null + * character. If the return value is not less than line_size, it means + * that the log message was truncated to fit the buffer. + */ +int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, + char *line, int line_size, int *print_prefix); + +/** + * Skip repeated messages, this requires the user app to use av_log() instead of + * (f)printf as the 2 would otherwise interfere and lead to + * "Last message repeated x times" messages below (f)printf messages with some + * bad luck. + * Also to receive the last, "last repeated" line if any, the user app must + * call av_log(NULL, AV_LOG_QUIET, "%s", ""); at the end + */ +#define AV_LOG_SKIP_REPEATED 1 + +/** + * Include the log severity in messages originating from codecs. + * + * Results in messages such as: + * [rawvideo @ 0xDEADBEEF] [error] encode did not produce valid pts + */ +#define AV_LOG_PRINT_LEVEL 2 + +/** + * Include system time in log output. + */ +#define AV_LOG_PRINT_TIME 4 + +/** + * Include system date and time in log output. + */ +#define AV_LOG_PRINT_DATETIME 8 + +void av_log_set_flags(int arg); +int av_log_get_flags(void); + +/** + * @} + */ + +#endif /* AVUTIL_LOG_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lzo.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lzo.h new file mode 100644 index 000000000..c03403992 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/macros.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/macros.h new file mode 100644 index 000000000..2a7567c3e --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mastering_display_metadata.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mastering_display_metadata.h new file mode 100644 index 000000000..52fcef9e3 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mastering_display_metadata.h @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2016 Neil Birkbeck + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h new file mode 100644 index 000000000..486de530f --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h @@ -0,0 +1,300 @@ +/* + * copyright (c) 2005-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 + */ + +/** + * @file + * @addtogroup lavu_math + * Mathematical utilities for working with timestamp and time base. + */ + +#ifndef AVUTIL_MATHEMATICS_H +#define AVUTIL_MATHEMATICS_H + +#include +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/md5.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/md5.h new file mode 100644 index 000000000..fc2eabdb1 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/md5.h @@ -0,0 +1,89 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @file + * @ingroup lavu_md5 + * Public header for MD5 hash function implementation. + */ + +#ifndef AVUTIL_MD5_H +#define AVUTIL_MD5_H + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mem.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mem.h new file mode 100644 index 000000000..ab7648ac5 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mem.h @@ -0,0 +1,607 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @file + * @ingroup lavu_mem + * Memory handling functions + */ + +#ifndef AVUTIL_MEM_H +#define AVUTIL_MEM_H + +#include +#include + +#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 Function attribute `malloc` in GCC's documentation + */ + +#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 Function attribute `alloc_size` in GCC's documentation + */ + +#if AV_GCC_VERSION_AT_LEAST(4,3) + #define av_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else + #define av_alloc_size(...) +#endif + +/** + * @} + */ + +/** + * @defgroup lavu_mem_funcs Heap Management + * Functions responsible for allocating, freeing, and copying memory. + * + * All memory allocation functions have a built-in upper limit of `INT_MAX` + * bytes. This may be changed with av_max_alloc(), although exercise extreme + * caution when doing so. + * + * @{ + */ + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU). + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_mallocz() + */ +void *av_malloc(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block with alignment suitable for all memory accesses + * (including vectors if available on the CPU) and zero all the bytes of the + * block. + * + * @param size Size in bytes for the memory block to be allocated + * @return Pointer to the allocated block, or `NULL` if it cannot be allocated + * @see av_malloc() + */ +void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); + +/** + * Allocate a memory block for an array with av_malloc(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of element + * @param size Size of a single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * @see av_malloc() + */ +av_alloc_size(1, 2) void *av_malloc_array(size_t nmemb, size_t size); + +/** + * Allocate a memory block for an array with av_mallocz(). + * + * The allocated memory will have size `size * nmemb` bytes. + * + * @param nmemb Number of elements + * @param size Size of the single element + * @return Pointer to the allocated block, or `NULL` if the block cannot + * be allocated + * + * @see av_mallocz() + * @see av_malloc_array() + */ +void *av_calloc(size_t nmemb, size_t size) av_malloc_attrib av_alloc_size(1, 2); + +/** + * Allocate, reallocate, or free a block of memory. + * + * If `ptr` is `NULL` and `size` > 0, allocate a new block. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param size Size in bytes of the memory block to be allocated or + * reallocated + * + * @return Pointer to a newly-reallocated block or `NULL` if the block + * cannot be reallocated + * + * @warning Unlike av_malloc(), the returned pointer is not guaranteed to be + * correctly aligned. The returned pointer must be freed after even + * if size is zero. + * @see av_fast_realloc() + * @see av_reallocp() + */ +void *av_realloc(void *ptr, size_t size) av_alloc_size(2); + +/** + * Allocate, reallocate, or free a block of memory through a pointer to a + * pointer. + * + * If `*ptr` is `NULL` and `size` > 0, allocate a new block. If `size` is + * zero, free the memory block pointed to by `*ptr`. Otherwise, expand or + * shrink that block of memory according to `size`. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already allocated + * with av_realloc(), or a pointer to `NULL`. The pointer + * is updated on success, or freed on failure. + * @param[in] size Size in bytes for the memory block to be allocated or + * reallocated + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. + */ +av_warn_unused_result +int av_reallocp(void *ptr, size_t size); + +/** + * Allocate, reallocate, or free a block of memory. + * + * This function does the same thing as av_realloc(), except: + * - It takes two size arguments and allocates `nelem * elsize` bytes, + * after checking the result of the multiplication for integer overflow. + * - It frees the input block in case of failure, thus avoiding the memory + * leak with the classic + * @code{.c} + * buf = realloc(buf); + * if (!buf) + * return -1; + * @endcode + * pattern. + */ +void *av_realloc_f(void *ptr, size_t nelem, size_t elsize); + +/** + * Allocate, reallocate, or free an array. + * + * If `ptr` is `NULL` and `nmemb` > 0, allocate a new block. + * + * @param ptr Pointer to a memory block already allocated with + * av_realloc() or `NULL` + * @param nmemb Number of elements in the array + * @param size Size of the single element of the array + * + * @return Pointer to a newly-reallocated block or NULL if the block + * cannot be reallocated + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. The returned pointer must be freed after even if + * nmemb is zero. + * @see av_reallocp_array() + */ +av_alloc_size(2, 3) void *av_realloc_array(void *ptr, size_t nmemb, size_t size); + +/** + * Allocate, reallocate an array through a pointer to a pointer. + * + * If `*ptr` is `NULL` and `nmemb` > 0, allocate a new block. + * + * @param[in,out] ptr Pointer to a pointer to a memory block already + * allocated with av_realloc(), or a pointer to `NULL`. + * The pointer is updated on success, or freed on failure. + * @param[in] nmemb Number of elements + * @param[in] size Size of the single element + * + * @return Zero on success, an AVERROR error code on failure + * + * @warning Unlike av_malloc(), the allocated memory is not guaranteed to be + * correctly aligned. *ptr must be freed after even if nmemb is zero. + */ +int av_reallocp_array(void *ptr, size_t nmemb, size_t size); + +/** + * Reallocate the given buffer if it is not large enough, otherwise do nothing. + * + * If the given buffer is `NULL`, then a new uninitialized buffer is allocated. + * + * If the given buffer is not large enough, and reallocation fails, `NULL` is + * returned and `*size` is set to 0, but the original buffer is not changed or + * freed. + * + * A typical use pattern follows: + * + * @code{.c} + * uint8_t *buf = ...; + * uint8_t *new_buf = av_fast_realloc(buf, ¤t_size, size_needed); + * if (!new_buf) { + * // Allocation failed; clean up original buffer + * av_freep(&buf); + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Already allocated buffer, or `NULL` + * @param[in,out] size Pointer to the size of buffer `ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `ptr` + * @return `ptr` if the buffer is large enough, a pointer to newly reallocated + * buffer if the buffer was not large enough, or `NULL` in case of + * error + * @see av_realloc() + * @see av_fast_malloc() + */ +void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate a buffer, reusing the given one if large enough. + * + * Contrary to av_fast_realloc(), the current buffer contents might not be + * preserved and on error the old buffer is freed, thus no special handling to + * avoid memleaks is necessary. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @code{.c} + * uint8_t *buf = ...; + * av_fast_malloc(&buf, ¤t_size, size_needed); + * if (!buf) { + * // Allocation failed; buf already freed + * return AVERROR(ENOMEM); + * } + * @endcode + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_realloc() + * @see av_fast_mallocz() + */ +void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size); + +/** + * Allocate and clear a buffer, reusing the given one if large enough. + * + * Like av_fast_malloc(), but all newly allocated space is initially cleared. + * Reused buffer is not cleared. + * + * `*ptr` is allowed to be `NULL`, in which case allocation always happens if + * `size_needed` is greater than 0. + * + * @param[in,out] ptr Pointer to pointer to an already allocated buffer. + * `*ptr` will be overwritten with pointer to new + * buffer on success or `NULL` on failure + * @param[in,out] size Pointer to the size of buffer `*ptr`. `*size` is + * updated to the new allocated size, in particular 0 + * in case of failure. + * @param[in] min_size Desired minimal size of buffer `*ptr` + * @see av_fast_malloc() + */ +void av_fast_mallocz(void *ptr, unsigned int *size, size_t min_size); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family. + * + * @param ptr Pointer to the memory block which should be freed. + * + * @note `ptr = NULL` is explicitly allowed. + * @note It is recommended that you use av_freep() instead, to prevent leaving + * behind dangling pointers. + * @see av_freep() + */ +void av_free(void *ptr); + +/** + * Free a memory block which has been allocated with a function of av_malloc() + * or av_realloc() family, and set the pointer pointing to it to `NULL`. + * + * @code{.c} + * uint8_t *buf = av_malloc(16); + * av_free(buf); + * // buf now contains a dangling pointer to freed memory, and accidental + * // dereference of buf will result in a use-after-free, which may be a + * // security risk. + * + * uint8_t *buf = av_malloc(16); + * av_freep(&buf); + * // buf is now NULL, and accidental dereference will only result in a + * // NULL-pointer dereference. + * @endcode + * + * @param ptr Pointer to the pointer to the memory block which should be freed + * @note `*ptr = NULL` is safe and leads to no action. + * @see av_free() + */ +void av_freep(void *ptr); + +/** + * Duplicate a string. + * + * @param s String to be duplicated + * @return Pointer to a newly-allocated string containing a + * copy of `s` or `NULL` if the string cannot be allocated + * @see av_strndup() + */ +char *av_strdup(const char *s) av_malloc_attrib; + +/** + * Duplicate a substring of a string. + * + * @param s String to be duplicated + * @param len Maximum length of the resulting string (not counting the + * terminating byte) + * @return Pointer to a newly-allocated string containing a + * substring of `s` or `NULL` if the string cannot be allocated + */ +char *av_strndup(const char *s, size_t len) av_malloc_attrib; + +/** + * Duplicate a buffer with av_malloc(). + * + * @param p Buffer to be duplicated + * @param size Size in bytes of the buffer copied + * @return Pointer to a newly allocated buffer containing a + * copy of `p` or `NULL` if the buffer cannot be allocated + */ +void *av_memdup(const void *p, size_t size); + +/** + * Overlapping memcpy() implementation. + * + * @param dst Destination buffer + * @param back Number of bytes back to start copying (i.e. the initial size of + * the overlapping window); must be > 0 + * @param cnt Number of bytes to copy; must be >= 0 + * + * @note `cnt > back` is valid, this will copy the bytes we just copied, + * thus creating a repeating pattern with a period length of `back`. + */ +void av_memcpy_backptr(uint8_t *dst, int back, int cnt); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_dynarray Dynamic Array + * + * Utilities to make an array grow when needed. + * + * Sometimes, the programmer would want to have an array that can grow when + * needed. The libavutil dynamic array utilities fill that need. + * + * libavutil supports two systems of appending elements onto a dynamically + * allocated array, the first one storing the pointer to the value in the + * array, and the second storing the value directly. In both systems, the + * caller is responsible for maintaining a variable containing the length of + * the array, as well as freeing of the array after use. + * + * The first system stores pointers to values in a block of dynamically + * allocated memory. Since only pointers are stored, the function does not need + * to know the size of the type. Both av_dynarray_add() and + * av_dynarray_add_nofree() implement this system. + * + * @code + * type **array = NULL; //< an array of pointers to values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * av_dynarray_add(&array, &nb, &to_be_added); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * av_dynarray_add(&array, &nb, &to_be_added2); + * if (nb == 0) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // &to_be_added == array[0] + * // &to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * The second system stores the value directly in a block of memory. As a + * result, the function has to know the size of the type. av_dynarray2_add() + * implements this mechanism. + * + * @code + * type *array = NULL; //< an array of values + * int nb = 0; //< a variable to keep track of the length of the array + * + * type to_be_added = ...; + * type to_be_added2 = ...; + * + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), NULL); + * if (!addr) + * return AVERROR(ENOMEM); + * memcpy(addr, &to_be_added, sizeof(to_be_added)); + * + * // Shortcut of the above. + * type *addr = av_dynarray2_add((void **)&array, &nb, sizeof(*array), + * (const void *)&to_be_added2); + * if (!addr) + * return AVERROR(ENOMEM); + * + * // Now: + * // nb == 2 + * // to_be_added == array[0] + * // to_be_added2 == array[1] + * + * av_freep(&array); + * @endcode + * + * @{ + */ + +/** + * Add the pointer to an element to a dynamic array. + * + * The array to grow is supposed to be an array of pointers to + * structures, and the element to add must be a pointer to an already + * allocated structure. + * + * The array is reallocated when its size reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem Element to add + * @see av_dynarray_add_nofree(), av_dynarray2_add() + */ +void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element to a dynamic array. + * + * Function has the same functionality as av_dynarray_add(), + * but it doesn't free memory on fails. It returns error code + * instead and leave current buffer untouched. + * + * @return >=0 on success, negative otherwise + * @see av_dynarray_add(), av_dynarray2_add() + */ +av_warn_unused_result +int av_dynarray_add_nofree(void *tab_ptr, int *nb_ptr, void *elem); + +/** + * Add an element of size `elem_size` to a dynamic array. + * + * The array is reallocated when its number of elements reaches powers of 2. + * Therefore, the amortized cost of adding an element is constant. + * + * In case of success, the pointer to the array is updated in order to + * point to the new grown array, and the number pointed to by `nb_ptr` + * is incremented. + * In case of failure, the array is freed, `*tab_ptr` is set to `NULL` and + * `*nb_ptr` is set to 0. + * + * @param[in,out] tab_ptr Pointer to the array to grow + * @param[in,out] nb_ptr Pointer to the number of elements in the array + * @param[in] elem_size Size in bytes of an element in the array + * @param[in] elem_data Pointer to the data of the element to add. If + * `NULL`, the space of the newly added element is + * allocated but left uninitialized. + * + * @return Pointer to the data of the element to copy in the newly allocated + * space + * @see av_dynarray_add(), av_dynarray_add_nofree() + */ +void *av_dynarray2_add(void **tab_ptr, int *nb_ptr, size_t elem_size, + const uint8_t *elem_data); + +/** + * @} + */ + +/** + * @defgroup lavu_mem_misc Miscellaneous Functions + * + * Other functions related to memory allocation. + * + * @{ + */ + +/** + * Multiply two `size_t` values checking for overflow. + * + * @param[in] a Operand of multiplication + * @param[in] b Operand of multiplication + * @param[out] r Pointer to the result of the operation + * @return 0 on success, AVERROR(EINVAL) on overflow + */ +int av_size_mult(size_t a, size_t b, size_t *r); + +/** + * Set the maximum size that may be allocated in one block. + * + * The value specified with this function is effective for all libavutil's @ref + * lavu_mem_funcs "heap management functions." + * + * By default, the max value is defined as `INT_MAX`. + * + * @param max Value to be set as the new maximum size + * + * @warning Exercise extreme caution when using this function. Don't touch + * this if you do not understand the full consequence of doing so. + */ +void av_max_alloc(size_t max); + +/** + * @} + * @} + */ + +#endif /* AVUTIL_MEM_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/motion_vector.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/motion_vector.h new file mode 100644 index 000000000..ec2955638 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/motion_vector.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_MOTION_VECTOR_H +#define AVUTIL_MOTION_VECTOR_H + +#include + +typedef struct AVMotionVector { + /** + * Where the current macroblock comes from; negative value when it comes + * from the past, positive value when it comes from the future. + * XXX: set exact relative ref frame reference instead of a +/- 1 "direction". + */ + int32_t source; + /** + * Width and height of the block. + */ + uint8_t w, h; + /** + * Absolute source position. Can be outside the frame area. + */ + int16_t src_x, src_y; + /** + * Absolute destination position. Can be outside the frame area. + */ + int16_t dst_x, dst_y; + /** + * Extra flag information. + * Currently unused. + */ + uint64_t flags; + /** + * Motion vector + * src_x = dst_x + motion_x / motion_scale + * src_y = dst_y + motion_y / motion_scale + */ + int32_t motion_x, motion_y; + uint16_t motion_scale; +} AVMotionVector; + +#endif /* AVUTIL_MOTION_VECTOR_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/murmur3.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/murmur3.h new file mode 100644 index 000000000..d90bc2fcd --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/murmur3.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2013 Reimar Döffinger + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h new file mode 100644 index 000000000..2a50f52fc --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h @@ -0,0 +1,1160 @@ +/* + * AVOptions + * copyright (c) 2005 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_OPT_H +#define AVUTIL_OPT_H + +/** + * @file + * AVOptions + */ + +#include "rational.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); + +/** + * 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); +/** + * @} + */ + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/parseutils.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/parseutils.h new file mode 100644 index 000000000..dad5c2775 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h new file mode 100644 index 000000000..0cc70eb64 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h @@ -0,0 +1,450 @@ +/* + * pixel format descriptor + * 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 + */ + +#ifndef AVUTIL_PIXDESC_H +#define AVUTIL_PIXDESC_H + +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixelutils.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixelutils.h new file mode 100644 index 000000000..7a997cde1 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +/** + * 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< + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + + /** + * CUDA block-linear (opaque). data[0] is a CUarray in block-linear layout, + * e.g. from NVDEC opaque decode. Use for zero-copy to NVENC (CUDA array input). + */ + AV_PIX_FMT_CUARRAY, + + 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/random_seed.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/random_seed.h new file mode 100644 index 000000000..8a47be967 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/random_seed.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2009 Baptiste Coudurier + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h new file mode 100644 index 000000000..30ac2aced --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h @@ -0,0 +1,225 @@ +/* + * rational numbers + * Copyright (c) 2003 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 + */ + +/** + * @file + * @ingroup lavu_math_rational + * Utilities for rational number calculation. + * @author Michael Niedermayer + */ + +#ifndef AVUTIL_RATIONAL_H +#define AVUTIL_RATIONAL_H + +#include +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h new file mode 100644 index 000000000..db6f84102 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2026 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 + */ + +#ifndef AVUTIL_RAW_COLOR_PARAMS_H +#define AVUTIL_RAW_COLOR_PARAMS_H + +#include +#include + +#include "frame.h" +#include "rational.h" + +enum AVRawColorParamsType { + AV_RAW_COLOR_PARAMS_NONE = 0, + + /** + * The union is valid when interpreted as AVProResRawColorParams + * (codec.prores_raw). + */ + AV_RAW_COLOR_PARAMS_PRORES_RAW, +}; + +/** + * ProRes RAW per-frame color transform, parsed from the prrf frame header. + * + * The correct rendering pipeline is: + * -> (sample - black_level) / (white_level - black_level) + * -> per-channel white balance (wb_red, 1.0 for G, wb_blue) pre-debayer + * -> debayer + * -> color_matrix (camera RGB -> CIE 1931 XYZ relative to D65) + * -> gain (scene-linear scale) + * + * Black/white levels live on the outer AVRawColorParams. The matrix output + * is linear-light CIE XYZ D65; convert to a working RGB space downstream. + * + * @note The struct must be allocated as part of AVRawColorParams using + * av_raw_color_params_alloc(). Its size is not a part of the public ABI. + */ +typedef struct AVProResRawColorParams { + /** + * White balance multiplier for the red channel, applied pre-debayer. + */ + AVRational wb_red; + + /** + * White balance multiplier for the blue channel, applied pre-debayer. + * (The green channel is implicit 1.0 for ProRes RAW) + */ + AVRational wb_blue; + + /** + * 3x3 row-major color matrix from camera RGB to linear-light CIE 1931 + * XYZ relative to the D65 illuminant, applied post-debayer. + * out[i] = sum_j color_matrix[i][j] * in[j]. + */ + AVRational color_matrix[3][3]; + + /** + * Post-matrix scene-linear scaling factor. Encodes highlight headroom the + * encoder reserved; multiply the matrixed values by this to recover + * scene-linear light. + */ + AVRational gain; +} AVProResRawColorParams; + +/** + * Per-frame color information for a RAW camera codec. Carried as side data of + * type AV_FRAME_DATA_RAW_COLOR_PARAMS. + * + * The outer struct carries the fields every RAW codec exposes: the sensor's + * valid sample range and the white-balance correlated color temperature. + * The codec union holds the codec-specific transform parameters; `type` + * selects which member of the union is valid. + * + * The codec-specific transform (color_matrix or equivalent) always lands in + * linear-light CIE 1931 XYZ relative to the D65 illuminant, cameras don't + * have standard primaries, so XYZ is the only common target. + * + * @note The struct must be allocated using av_raw_color_params_alloc() or + * av_raw_color_params_create_side_data(). Its size is not a part of the + * public ABI. + */ +typedef struct AVRawColorParams { + /** + * Selects which member of `codec` is valid. + */ + enum AVRawColorParamsType type; + + /** + * Lowest valid raw sample code (sensor black point) + */ + AVRational black_level; + + /** + * Highest valid raw sample code (sensor white point) + */ + AVRational white_level; + + /** + * Color temperature in Kelvin from with the camera's white balance. + * Informational; the math uses the codec-specific white-balance fields. + * 0 if not signaled. + */ + uint32_t wb_cct; + + /** + * Additional codec-specific fields. + */ + union { + AVProResRawColorParams prores_raw; + } codec; +} AVRawColorParams; + +/** + * Allocate an AVRawColorParams structure and zero-initialize it. + * + * @param size if non-NULL, set to sizeof(AVRawColorParams) + * @return the newly allocated struct or NULL on failure + */ +AVRawColorParams *av_raw_color_params_alloc(size_t *size); + +/** + * Allocate and add an AVRawColorParams structure to an existing AVFrame as + * AV_FRAME_DATA_RAW_COLOR_PARAMS side data. + * + * @return the newly allocated struct, or NULL on failure + */ +AVRawColorParams *av_raw_color_params_create_side_data(AVFrame *frame); + +#endif /* AVUTIL_RAW_COLOR_PARAMS_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h new file mode 100644 index 000000000..0c72a88ec --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h new file mode 100644 index 000000000..4e9d78eb0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/replaygain.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/replaygain.h new file mode 100644 index 000000000..b49bf1a3d --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/replaygain.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_REPLAYGAIN_H +#define AVUTIL_REPLAYGAIN_H + +#include + +/** + * ReplayGain information (see + * http://wiki.hydrogenaudio.org/index.php?title=ReplayGain_1.0_specification). + * The size of this struct is a part of the public ABI. + */ +typedef struct AVReplayGain { + /** + * Track replay gain in microbels (divide by 100000 to get the value in dB). + * Should be set to INT32_MIN when unknown. + */ + int32_t track_gain; + /** + * Peak track amplitude, with 100000 representing full scale (but values + * may overflow). 0 when unknown. + */ + uint32_t track_peak; + /** + * Same as track_gain, but for the whole album. + */ + int32_t album_gain; + /** + * Same as track_peak, but for the whole album, + */ + uint32_t album_peak; +} AVReplayGain; + +#endif /* AVUTIL_REPLAYGAIN_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ripemd.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ripemd.h new file mode 100644 index 000000000..9df9f905f --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ripemd.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * 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 + */ + +/** + * @file + * @ingroup lavu_ripemd + * Public header for RIPEMD hash function implementation. + */ + +#ifndef AVUTIL_RIPEMD_H +#define AVUTIL_RIPEMD_H + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h new file mode 100644 index 000000000..6e55d7114 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha.h new file mode 100644 index 000000000..2e1220abd --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2007 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 + */ + +/** + * @file + * @ingroup lavu_sha + * Public header for SHA-1 & SHA-256 hash function implementations. + */ + +#ifndef AVUTIL_SHA_H +#define AVUTIL_SHA_H + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha512.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha512.h new file mode 100644 index 000000000..a4a3f23db --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/sha512.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2007 Michael Niedermayer + * 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 + */ + +/** + * @file + * @ingroup lavu_sha512 + * Public header for SHA-512 implementation. + */ + +#ifndef AVUTIL_SHA512_H +#define AVUTIL_SHA512_H + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h new file mode 100644 index 000000000..4b78978eb --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2016 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/stereo3d.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/stereo3d.h new file mode 100644 index 000000000..c0a4ab3f2 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/stereo3d.h @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2013 Vittorio Giovara + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h new file mode 100644 index 000000000..8629775a2 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +#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(-prec_ref_display_width). + */ + 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^(-prec_ref_viewing_dist). + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tea.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tea.h new file mode 100644 index 000000000..dd929bdaf --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/threadmessage.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/threadmessage.h new file mode 100644 index 000000000..42ce655f3 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/time.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/time.h new file mode 100644 index 000000000..dc169b064 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timecode.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timecode.h new file mode 100644 index 000000000..fe0fc8357 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timecode.h @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2006 Smartjog S.A.S, Baptiste Coudurier + * Copyright (c) 2011-2012 Smartjog S.A.S, Clément Bœsch + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timestamp.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/timestamp.h new file mode 100644 index 000000000..fa53a46b9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tree.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tree.h new file mode 100644 index 000000000..bbb8fbb12 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tree.h @@ -0,0 +1,137 @@ +/* + * copyright (c) 2006 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 + */ + +/** + * @file + * A tree container. + * @author Michael Niedermayer + */ + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/twofish.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/twofish.h new file mode 100644 index 000000000..67f359e88 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h new file mode 100644 index 000000000..c95009573 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/uuid.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/uuid.h new file mode 100644 index 000000000..748b7ed3c --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/uuid.h @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2022 Pierre-Anthony Lemieux + * Zane van Iperen + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 + * @author Zane van Iperen + */ + +#ifndef AVUTIL_UUID_H +#define AVUTIL_UUID_H + +#include +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h new file mode 100644 index 000000000..d5bf20cf8 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h @@ -0,0 +1,118 @@ +/* + * 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 61 +#define LIBAVUTIL_VERSION_MINOR 5 +#define LIBAVUTIL_VERSION_MICRO 100 + +#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_CPU_FLAG_FORCE (LIBAVUTIL_VERSION_MAJOR < 62) +#define FF_API_DOVI_L11_INVALID_PROPS (LIBAVUTIL_VERSION_MAJOR < 62) +#define FF_API_ASSERT_FPU (LIBAVUTIL_VERSION_MAJOR < 62) +#define FF_API_VULKAN_SYNC_QUEUES (LIBAVUTIL_VERSION_MAJOR < 62) + +/** + * @} + * @} + */ + +#endif /* AVUTIL_VERSION_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_enc_params.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_enc_params.h new file mode 100644 index 000000000..62265a5c0 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#include + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h new file mode 100644 index 000000000..8e8af0ae9 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h @@ -0,0 +1,107 @@ +/** + * Copyright 2023 Elias Carotti + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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 +#include +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/xtea.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/xtea.h new file mode 100644 index 000000000..735427c10 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 + +/** + * @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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h new file mode 100644 index 000000000..052089acc --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h new file mode 100644 index 000000000..057ac4b19 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 2 +#define LIBSWRESAMPLE_VERSION_MICRO 100 + +#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h new file mode 100644 index 000000000..0dc51de32 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/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 7 + +#endif /* SWRESAMPLE_VERSION_MAJOR_H */ From 84a5e04fcb1ce1f71193608f44f581b8675edbd7 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:44:43 +0100 Subject: [PATCH 21/48] hires-mic(Phase 3b): add FFmpeg mingw import libs (force past lib/ ignore) The vendored .dll.a import libs are needed to link the AAC-ELD shim; the repo's lib/ ignore rule was hiding them. Co-Authored-By: Claude Opus 4.8 --- .../vendor/ffmpeg/lib/libavcodec.dll.a | Bin 0 -> 132774 bytes .../vendor/ffmpeg/lib/libavutil.dll.a | Bin 0 -> 424590 bytes .../vendor/ffmpeg/lib/libswresample.dll.a | Bin 0 -> 15964 bytes 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavcodec.dll.a create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavutil.dll.a create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libswresample.dll.a diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavcodec.dll.a b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavcodec.dll.a new file mode 100644 index 0000000000000000000000000000000000000000..078273d5f57333caed8cf36f4d039fccc4805e3c GIT binary patch literal 132774 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 literal 0 HcmV?d00001 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavutil.dll.a b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavutil.dll.a new file mode 100644 index 0000000000000000000000000000000000000000..7a9cc478a3ae725eba0119e275863bca9674fcae GIT binary patch literal 424590 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 Cv+=Y5 literal 0 HcmV?d00001 From f6be74e3479cf099a7ce8016e87d8f931f520349 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:50:32 +0100 Subject: [PATCH 22/48] hires-mic(Phase 3b): resample decoder output to 48 kHz (fix pitch) The AAC-ELD decoder outputs at its own rate (voice ELD is typically 24 kHz), but we fed those samples into the 48 kHz capture endpoint -> playback ran ~2x slow (deep 'censored voice'). Resample the decoded audio (whatever rate) to 48 kHz mono s16 via libswresample before feeding the mic pipe, so the pitch is correct. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/eld_shim.c | 53 +++++++++++++------ 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c index a0bfd878c..ee35d0148 100644 --- a/crossplatform/windows-app/librepods-tray/src/eld_shim.c +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -1,20 +1,27 @@ -// Minimal AAC-ELD decoder shim over FFmpeg libavcodec (LGPL). Exposes a small, -// version-stable C ABI so the Rust side never touches AVCodecContext internals. +// Minimal AAC-ELD decoder shim over FFmpeg libavcodec + libswresample (LGPL). +// Exposes a small, version-stable C ABI so the Rust side never touches +// AVCodecContext internals. Decodes AAC-ELD access units and resamples whatever +// rate the decoder produces to a fixed 48 kHz mono s16 (matching the virtual +// mic's capture format), so the pitch is always correct. #include +#include #include #include +#include #include #include #include +#define OUT_RATE 48000 + typedef struct { AVCodecContext *ctx; AVPacket *pkt; - AVFrame *frame; + AVFrame *frame; + SwrContext *swr; + int in_rate; // decoder output rate, learned from the first frame } EldDec; -// Open an AAC-ELD decoder configured by `asc` (AudioSpecificConfig). Returns an -// opaque handle or NULL. void *eld_open(const uint8_t *asc, int asc_len, int sample_rate) { const AVCodec *c = avcodec_find_decoder_by_name("aac"); if (!c) return NULL; @@ -25,34 +32,47 @@ void *eld_open(const uint8_t *asc, int asc_len, int sample_rate) { memset(ctx->extradata, 0, asc_len + AV_INPUT_BUFFER_PADDING_SIZE); memcpy(ctx->extradata, asc, asc_len); ctx->extradata_size = asc_len; - ctx->sample_rate = sample_rate; // channels/rate also come from the ASC + ctx->sample_rate = sample_rate; // channels/rate ultimately come from the ASC if (avcodec_open2(ctx, c, NULL) < 0) { avcodec_free_context(&ctx); return NULL; } - EldDec *d = (EldDec *)malloc(sizeof(EldDec)); + EldDec *d = (EldDec *)calloc(1, sizeof(EldDec)); if (!d) { avcodec_free_context(&ctx); return NULL; } d->ctx = ctx; d->pkt = av_packet_alloc(); d->frame = av_frame_alloc(); + d->swr = NULL; + d->in_rate = 0; return d; } -// Decode one access unit into interleaved mono i16 `out` (capacity `out_cap` -// samples). Returns the number of samples written, or -1 on error. +// Decode one access unit into interleaved mono s16 at 48 kHz. `out_cap` is the +// sample capacity. Returns the number of samples written, or -1 on error. int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int out_cap) { EldDec *d = (EldDec *)handle; if (!d) return -1; d->pkt->data = (uint8_t *)au; d->pkt->size = au_len; if (avcodec_send_packet(d->ctx, d->pkt) < 0) return -1; + int total = 0; while (avcodec_receive_frame(d->ctx, d->frame) == 0) { - int n = d->frame->nb_samples; - const float *p = (const float *)d->frame->data[0]; // FLTP mono -> plane 0 - for (int i = 0; i < n && total < out_cap; i++) { - float s = p[i]; - if (s > 1.0f) s = 1.0f; - if (s < -1.0f) s = -1.0f; - out[total++] = (int16_t)(s * 32767.0f); + // (Re)build the resampler when the decoder's output rate is first known + // or changes: decoder rate -> 48 kHz mono s16. + if (!d->swr || d->in_rate != d->frame->sample_rate) { + if (d->swr) swr_free(&d->swr); + AVChannelLayout out_ch; + av_channel_layout_default(&out_ch, 1); + swr_alloc_set_opts2(&d->swr, &out_ch, AV_SAMPLE_FMT_S16, OUT_RATE, + &d->frame->ch_layout, (enum AVSampleFormat)d->frame->format, + d->frame->sample_rate, 0, NULL); + swr_init(d->swr); + d->in_rate = d->frame->sample_rate; } + uint8_t *outp = (uint8_t *)(out + total); + int room = out_cap - total; + if (room <= 0) { av_frame_unref(d->frame); break; } + int got = swr_convert(d->swr, &outp, room, + (const uint8_t **)d->frame->data, d->frame->nb_samples); + if (got > 0) total += got; av_frame_unref(d->frame); } return total; @@ -61,6 +81,7 @@ int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int ou void eld_close(void *handle) { EldDec *d = (EldDec *)handle; if (!d) return; + if (d->swr) swr_free(&d->swr); av_frame_free(&d->frame); av_packet_free(&d->pkt); avcodec_free_context(&d->ctx); From 4a9871a066695f13d9f23721bd69cfb4472ff259 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 19:59:55 +0100 Subject: [PATCH 23/48] hires-mic(Phase 3b): virtual mic offers 48 kHz only (fix deep/robotic pitch) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diagnosed from the user's recordings: the virtual mic was captured at 44100 Hz (Voice Recorder's pick) while we feed audio resampled to 48000 Hz, so playback ran ~8% slow → deep "robotic" voice (duration ratio 11.91/11.05 = 1.078 ~= 48000/44100). Drop the 44100 format from the capture circuit so every app opens at 48000, matching our feed. (eld_shim: add eld_in_rate diagnostic helper.) Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/eld_shim.c | 6 ++++++ .../windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c index ee35d0148..2164b0a8b 100644 --- a/crossplatform/windows-app/librepods-tray/src/eld_shim.c +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -78,6 +78,12 @@ int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int ou return total; } +// The decoder's output sample rate (learned after the first decoded frame), or 0. +int eld_in_rate(void *handle) { + EldDec *d = (EldDec *)handle; + return d ? d->in_rate : 0; +} + void eld_close(void *handle) { EldDec *d = (EldDec *)handle; if (!d) return; diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp index f255316b1..399ddc203 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/Common/CaptureCircuit.cpp @@ -332,7 +332,6 @@ Capture_AllocateSupportedFormats( UNREFERENCED_PARAMETER(CodecCapturePinCount); NTSTATUS status = STATUS_SUCCESS; - ACXDATAFORMAT formatPcm44100c1; ACXDATAFORMAT formatPcm48000c1; ACXDATAFORMATLIST formatList; @@ -344,7 +343,9 @@ Capture_AllocateSupportedFormats( // Allocate the formats this circuit supports. // - RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm44100c1, Circuit, Device, &formatPcm44100c1)); + // Offer 48000 Hz only: LibrePods always feeds decoded audio resampled to + // 48 kHz, so exposing 44100 too made apps (e.g. Voice Recorder) open at + // 44100 and play our 48 kHz samples ~8% slow (deep/robotic). RETURN_NTSTATUS_IF_FAILED(AllocateFormat(Pcm48000c1, Circuit, Device, &formatPcm48000c1)); /////////////////////////////////////////////////////////// @@ -365,7 +366,6 @@ Capture_AllocateSupportedFormats( // The driver uses this DDI to add data formats to the raw // processing mode list associated with the current circuit. // - RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm44100c1)); RETURN_NTSTATUS_IF_FAILED(AcxDataFormatListAddDataFormat(formatList, formatPcm48000c1)); return status; From 8c9d352ecf243520442ad1965c4b5d403f61b801 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 20:06:21 +0100 Subject: [PATCH 24/48] windows-tray: single-instance guard (named mutex) Launching the tray while a copy was still starting left two icons fighting over the single-open driver and the exclusive mic pipe. Bail on startup if the named mutex already exists. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/Cargo.toml | 1 + crossplatform/windows-app/librepods-tray/src/main.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/crossplatform/windows-app/librepods-tray/Cargo.toml b/crossplatform/windows-app/librepods-tray/Cargo.toml index b660c36df..dc433b45f 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.toml +++ b/crossplatform/windows-app/librepods-tray/Cargo.toml @@ -14,6 +14,7 @@ windows-sys = { version = "0.59", features = [ "Win32_Foundation", "Win32_System_IO", "Win32_System_Registry", + "Win32_System_Threading", "Win32_Storage_FileSystem", "Win32_Security", "Win32_Devices_DeviceAndDriverInstallation", diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 430eec021..fedec5e69 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -28,6 +28,8 @@ use driver::Driver; use tray_icon::menu::{CheckMenuItem, Menu, MenuEvent, MenuId, MenuItem, PredefinedMenuItem}; use tray_icon::{Icon, TrayIconBuilder}; +use windows_sys::Win32::Foundation::{ERROR_ALREADY_EXISTS, GetLastError}; +use windows_sys::Win32::System::Threading::CreateMutexW; use windows_sys::Win32::UI::WindowsAndMessaging::{ DispatchMessageW, GetMessageW, MSG, PostQuitMessage, SetTimer, TranslateMessage, WM_TIMER, }; @@ -309,6 +311,16 @@ fn run_receiver( } fn main() { + // Single instance: if a LibrePods tray is already running, exit quietly so we + // never end up with two icons fighting over the single-open driver / mic pipe. + unsafe { + let name: Vec = "Local\\LibrePodsTraySingleton\0".encode_utf16().collect(); + let _ = CreateMutexW(std::ptr::null(), 0, name.as_ptr()); + if GetLastError() == ERROR_ALREADY_EXISTS { + return; + } + } + volume::init(); // COM for Core Audio, on this (main) thread overlay::init(); // create the (hidden) centered popup window on this thread theme::apply_menu_theme(); // dark/light Win32 context menu, per the OS theme From 5b4705d2549cedfb0a6bf95b755a3c21f649d1d6 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 20:30:13 +0100 Subject: [PATCH 25/48] hires-mic(Phase 3b): prime the mic ring with a silence cushion (fix clicks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Diagnosed via a dump of our decoded PCM: the decode is clean (no clicks), so the periodic clicks in the recording came from the ring, not the codec. We feed in per-packet bursts (~80 ms of audio at once) while the capture endpoint drains steadily, so with no head start the ring underran between bursts — a click per packet. Prime the ring with ~150 ms of silence on start-up to absorb the burstiness. Also decode a whole packet's AUs and write once. Removed the debug packet/PCM dumps. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/main.rs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index fedec5e69..d5423c1e3 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -134,7 +134,7 @@ fn run_receiver( driver_cell: Arc>>, mic_on: Arc, ) { - let mut buf = [0u8; 2048]; + let mut buf = [0u8; 8192]; let mut audio_pkts = 0u32; // Hi-res mic pipeline (Phase 3b): created on first audio packet, torn down // when the mic is disabled. The decoder holds the FFmpeg AAC-ELD context; @@ -199,6 +199,14 @@ fn run_receiver( if decoder.is_none() { decoder = eld::Decoder::new(); pipe = micpipe::MicPipe::open(); + if let Some(pp) = pipe.as_ref() { + // Prime the ring with a short silence cushion: + // we feed in per-packet bursts (~80 ms) while + // the capture drains steadily, so without a + // head start the ring underran between bursts + // (a click per packet). ~150 ms absorbs it. + pp.write(&[0i16; 7200]); + } let msg = match (decoder.is_some(), pipe.is_some()) { (true, true) => "Hi-res mic: streaming to the mic", (false, _) => "Hi-res mic: decoder failed (FFmpeg)", @@ -207,12 +215,14 @@ fn run_receiver( overlay::show(&dev_name, msg); } if let (Some(dec), Some(pp)) = (decoder.as_mut(), pipe.as_ref()) { + // Decode all the packet's AUs, then write once. + let mut out: Vec = Vec::new(); aap::for_each_au(data, |au| { - let pcm = dec.decode(au); - if !pcm.is_empty() { - pp.write(pcm); - } + out.extend_from_slice(dec.decode(au)); }); + if !out.is_empty() { + pp.write(&out); + } } audio_pkts = audio_pkts.saturating_add(1); } From 885a7395980b3ce1795be296d8c3bf3adaa92257 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 20:39:23 +0100 Subject: [PATCH 26/48] hires-mic(Phase 3b): decode the mic as 64 kHz (fix deep pitch + clicks) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AirPods hi-res mic AAC-ELD frames are 480 samples at 64 kHz (7.5 ms), but the 4-byte ASC advertises samplingFrequencyIndex 3 (48000), so FFmpeg labels them 48000. Confirmed by the 0x58 AU timestamps incrementing +180 per frame — a 24 kHz clock over 7.5 ms frames (7.5ms * 24000 = 180) — and by the measured deep pitch (~1.33x). Feeding 64 kHz content as 48 kHz played it ~0.75x slow (deep) AND overfed the ring (the clicks). Resample from the true 64 kHz -> 48 kHz, which fixes both at once. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/eld_shim.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c index 2164b0a8b..b7e3f4bbe 100644 --- a/crossplatform/windows-app/librepods-tray/src/eld_shim.c +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -13,6 +13,11 @@ #include #define OUT_RATE 48000 +// The AirPods hi-res mic AAC-ELD actually decodes at 64 kHz (PR #655's +// ELD_SAMPLE_RATE), but its 4-byte ASC advertises index 3 (48000), so FFmpeg +// labels the frames 48000. Feeding that 64 kHz content as 48 kHz played ~0.75x +// slow (deep) and overfed the ring. Resample from the true 64 kHz instead. +#define IN_RATE 64000 typedef struct { AVCodecContext *ctx; @@ -63,7 +68,7 @@ int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int ou av_channel_layout_default(&out_ch, 1); swr_alloc_set_opts2(&d->swr, &out_ch, AV_SAMPLE_FMT_S16, OUT_RATE, &d->frame->ch_layout, (enum AVSampleFormat)d->frame->format, - d->frame->sample_rate, 0, NULL); + IN_RATE, 0, NULL); swr_init(d->swr); d->in_rate = d->frame->sample_rate; } From a324a840db4c88a056168bbb27d5a7604b46a6c9 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 20:43:19 +0100 Subject: [PATCH 27/48] hires-mic: mark Phase 3b done (voice decoded clean + in tune on hardware) Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index a74862cb4..596221c01 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -92,10 +92,16 @@ the sink. receive loop confirmed the **0x58 uplink audio packets flow** ("receiving audio" card). Constants + `is_audio_packet` in `aap.rs`; protocol in [[hires-mic-protocol]]. -- **Phase 3b — next (the hard part)**: decode the 0x58 packets' **AAC-ELD** to - PCM and feed `\\.\LibrePodsMic`. Parse AUs (header 22, AU len at `off+4`, - payload `off+5`), decode AAC-ELD (64000/480/mono, ASC `F8 E6 30 00`) → f32 → - i16. **Blocker: the decoder on Windows/mingw** — FFmpeg libavcodec (native - AAC-ELD, LGPL) or libfdk-aac, cross-compiled for `x86_64-pc-windows-gnu` or - linked against prebuilt DLLs. Plus the A2DP reset to restore stereo playback. +- **Phase 3b — DONE** ✅ (validated on hardware, user's voice recorded clean & + in tune). The tray decodes the 0x58 AUs (AAC-ELD) via an FFmpeg libavcodec + shim (LGPL, `eld_shim.c`), resamples, and streams to `\\.\LibrePodsMic`. Key + fixes: mic frames are **480 samples @ 64 kHz** (not 48 kHz — the 4-byte ASC + lies; confirmed by the +180/AU timestamp = a 24 kHz clock over 7.5 ms frames), + so resample **64000 → 48000**; capture circuit restricted to **48 kHz only**; + and a **~150 ms silence cushion** on the ring to absorb the bursty per-packet + feed. Pitch went ~105 → ~122 Hz (ref ~148), zero click/gap artifacts. Audio is + a bit quiet (a gain stage would help) and mono (single mic capsule). +- **Phase 4 — polish (next)**: A2DP reset so playback restores to stereo after + the mic stops (today it needs a BT restart); the 2 s stall watchdog; optional + gain/AGC; auto enable/disable when an app opens the mic; dynamic endpoint name. - Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. From de5f40f9c3ac5c3454e6d94813c1735fd96cd404 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:00:57 +0100 Subject: [PATCH 28/48] hires-mic(Phase 4): auto A2DP reset on mic stop (restore stereo) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hi-res mic puts the AirPods into a bidirectional "call" mode that degrades A2DP playback to mono/right and stays that way until reconnected (the user was restarting Bluetooth each time). On mic-off, toggle the AirPods' A2DP service (BluetoothSetServiceState disable→enable, off the UI thread) to reconnect the audio link and restore stereo — the scoped, programmatic equivalent of disconnect+reconnect. Best-effort (silently ignored if it needs elevation). Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/a2dp.rs | 84 +++++++++++++++++++ .../windows-app/librepods-tray/src/main.rs | 11 ++- 2 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 crossplatform/windows-app/librepods-tray/src/a2dp.rs diff --git a/crossplatform/windows-app/librepods-tray/src/a2dp.rs b/crossplatform/windows-app/librepods-tray/src/a2dp.rs new file mode 100644 index 000000000..096b23238 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/a2dp.rs @@ -0,0 +1,84 @@ +//! A2DP recovery: after the hi-res mic puts the AirPods into their bidirectional +//! "call" mode, A2DP playback degrades to mono/right until the audio link is +//! re-established. This toggles the AirPods' A2DP service off then on — the +//! programmatic equivalent of disconnecting + reconnecting them — to restore +//! stereo, without a full Bluetooth restart. + +use std::mem::{size_of, zeroed}; + +use windows_sys::Win32::Devices::Bluetooth::{ + BLUETOOTH_DEVICE_INFO, BLUETOOTH_DEVICE_SEARCH_PARAMS, BLUETOOTH_FIND_RADIO_PARAMS, + BluetoothFindDeviceClose, BluetoothFindFirstDevice, BluetoothFindFirstRadio, + BluetoothFindNextDevice, BluetoothFindRadioClose, BluetoothSetServiceState, +}; +use windows_sys::Win32::Foundation::{CloseHandle, HANDLE}; +use windows_sys::core::GUID; + +// AdvancedAudioDistribution (A2DP) profile service. +const A2DP_SERVICE: GUID = GUID { + data1: 0x0000_110D, + data2: 0x0000, + data3: 0x1000, + data4: [0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB], +}; + +const BLUETOOTH_SERVICE_DISABLE: u32 = 0x00; +const BLUETOOTH_SERVICE_ENABLE: u32 = 0x01; + +fn find_device(mac: u64) -> Option { + unsafe { + let mut params: BLUETOOTH_DEVICE_SEARCH_PARAMS = zeroed(); + params.dwSize = size_of::() as u32; + params.fReturnAuthenticated = 1; + params.fReturnRemembered = 1; + params.fReturnConnected = 1; + params.fReturnUnknown = 1; + + let mut info: BLUETOOTH_DEVICE_INFO = zeroed(); + info.dwSize = size_of::() as u32; + let h = BluetoothFindFirstDevice(¶ms, &mut info); + if h.is_null() { + return None; + } + let mut found = None; + loop { + if info.Address.Anonymous.ullLong == mac { + found = Some(info); + break; + } + info.dwSize = size_of::() as u32; + if BluetoothFindNextDevice(h, &mut info) == 0 { + break; + } + } + BluetoothFindDeviceClose(h); + found + } +} + +/// Reconnect the AirPods' A2DP service (disable then enable) to restore stereo. +/// Best-effort: any failure (e.g. needs elevation) is silently ignored — the +/// user can still recover by toggling Bluetooth. +pub fn reset(mac: u64) { + unsafe { + let info = match find_device(mac) { + Some(i) => i, + None => return, + }; + + let mut rparams: BLUETOOTH_FIND_RADIO_PARAMS = zeroed(); + rparams.dwSize = size_of::() as u32; + let mut radio: HANDLE = std::ptr::null_mut(); + let hfind = BluetoothFindFirstRadio(&rparams, &mut radio); + if hfind.is_null() { + return; + } + + BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_DISABLE); + std::thread::sleep(std::time::Duration::from_millis(600)); + BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); + + CloseHandle(radio); + BluetoothFindRadioClose(hfind); + } +} diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index d5423c1e3..257a5db32 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -9,6 +9,7 @@ #![windows_subsystem = "windows"] // no console window +mod a2dp; mod aap; mod bt; mod driver; @@ -509,9 +510,17 @@ fn main() { let cmd: &[u8] = if on { &aap::START_AUDIO } else { &aap::STOP_AUDIO }; let _ = drv.send(cmd); } + if !on { + // The mic mode degraded A2DP to mono; reconnect the A2DP + // service to restore stereo (off the UI thread — it waits + // ~0.6 s between disable/enable). + if let Some(m) = mac { + thread::spawn(move || a2dp::reset(m)); + } + } overlay::show( &dev_name, - if on { "Hi-res mic: enabling…" } else { "Hi-res mic: off" }, + if on { "Hi-res mic: enabling…" } else { "Hi-res mic: restoring stereo…" }, ); } else if let Some(mode) = mode_for(&ev.id) { if let Some(drv) = driver_cell.lock().unwrap().clone() { From 34cb610cfb6d7a4fbc70ab68c7ad28b229000167 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:22:58 +0100 Subject: [PATCH 29/48] hires-mic(Phase 4): A2DP auto-reset works (correct service GUID + timing) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The A2DP audio service the AirPods actually expose is AudioSink (0x110B), not AdvancedAudioDistribution (0x110D) — toggling 0x110D returned ERROR 1060 (service not installed). Enumerating the device's installed services found the right GUID. Toggling 0x110B disable→enable (with a 1 s settle after the mic stop and a 2 s teardown before reconnect) reliably restores stereo — no Bluetooth restart needed. Removed the debug service-dump and the result-code overlay. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/a2dp.rs | 28 +++++++++++-------- .../windows-app/librepods-tray/src/main.rs | 6 ++-- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/a2dp.rs b/crossplatform/windows-app/librepods-tray/src/a2dp.rs index 096b23238..6ba38a802 100644 --- a/crossplatform/windows-app/librepods-tray/src/a2dp.rs +++ b/crossplatform/windows-app/librepods-tray/src/a2dp.rs @@ -14,9 +14,10 @@ use windows_sys::Win32::Devices::Bluetooth::{ use windows_sys::Win32::Foundation::{CloseHandle, HANDLE}; use windows_sys::core::GUID; -// AdvancedAudioDistribution (A2DP) profile service. +// AudioSink (A2DP) — the service the AirPods actually expose for audio (0x110B). +// (0x110D AdvancedAudioDistribution isn't an installed service here -> ERROR 1060.) const A2DP_SERVICE: GUID = GUID { - data1: 0x0000_110D, + data1: 0x0000_110B, data2: 0x0000, data3: 0x1000, data4: [0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB], @@ -57,28 +58,33 @@ fn find_device(mac: u64) -> Option { } /// Reconnect the AirPods' A2DP service (disable then enable) to restore stereo. -/// Best-effort: any failure (e.g. needs elevation) is silently ignored — the -/// user can still recover by toggling Bluetooth. -pub fn reset(mac: u64) { +/// Returns the (disable, enable) Win32 result codes: 0 = success, 5 = access +/// denied (needs elevation), 0xFFFFFFFF = device not found, 0xFFFFFFFE = no radio. +pub fn reset(mac: u64) -> (u32, u32) { unsafe { let info = match find_device(mac) { Some(i) => i, - None => return, + None => return (0xFFFF_FFFF, 0), }; - let mut rparams: BLUETOOTH_FIND_RADIO_PARAMS = zeroed(); rparams.dwSize = size_of::() as u32; let mut radio: HANDLE = std::ptr::null_mut(); let hfind = BluetoothFindFirstRadio(&rparams, &mut radio); if hfind.is_null() { - return; + return (0xFFFF_FFFE, 0); } - BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_DISABLE); - std::thread::sleep(std::time::Duration::from_millis(600)); - BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); + // Let the mic-stop transition settle so the AirPods have left mic mode + // before we touch A2DP. + std::thread::sleep(std::time::Duration::from_millis(1000)); + let d = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_DISABLE); + // Let the A2DP link fully tear down before reconnecting, else it + // re-establishes mid-teardown (mono/crackle) and needs another try. + std::thread::sleep(std::time::Duration::from_millis(2000)); + let e = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); CloseHandle(radio); BluetoothFindRadioClose(hfind); + (d, e) } } diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 257a5db32..db3dbf37d 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -513,9 +513,11 @@ fn main() { if !on { // The mic mode degraded A2DP to mono; reconnect the A2DP // service to restore stereo (off the UI thread — it waits - // ~0.6 s between disable/enable). + // ~1.5 s between disable/enable). Report the result codes. if let Some(m) = mac { - thread::spawn(move || a2dp::reset(m)); + thread::spawn(move || { + a2dp::reset(m); + }); } } overlay::show( From c726fcb581f2bd237da2a34c1c106abad843e6d0 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:23:23 +0100 Subject: [PATCH 30/48] hires-mic: mark A2DP auto-reset done in the plan Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index 596221c01..6a5de3f45 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -101,7 +101,11 @@ the sink. and a **~150 ms silence cushion** on the ring to absorb the bursty per-packet feed. Pitch went ~105 → ~122 Hz (ref ~148), zero click/gap artifacts. Audio is a bit quiet (a gain stage would help) and mono (single mic capsule). -- **Phase 4 — polish (next)**: A2DP reset so playback restores to stereo after - the mic stops (today it needs a BT restart); the 2 s stall watchdog; optional - gain/AGC; auto enable/disable when an app opens the mic; dynamic endpoint name. +- **Phase 4 — in progress**: **A2DP auto-reset DONE** ✅ (`34cb610`) — on mic + stop the tray toggles the AirPods' **AudioSink (0x110B)** Bluetooth service + disable→enable (1 s settle + 2 s teardown) to reconnect A2DP and restore + stereo, no BT restart (0x110D gave ERROR 1060; found 0x110B via + BluetoothEnumerateInstalledServices). Remaining: 2 s stall watchdog; optional + gain/AGC (audio's a bit quiet); auto enable/disable when an app opens the mic; + dynamic endpoint name; and bundle it all into the dist. - Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. From d2716af6f2a5721402ee260611873dd2cb53363a Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:30:38 +0100 Subject: [PATCH 31/48] hires-mic(Phase 4): make-up gain + smaller latency cushion Measured from the user's recordings: the AirPods mic was ~4 dB quieter than a reference with ~22 dB of headroom, and the 150 ms ring cushion added noticeable start latency + clipped the tail on stop. Add a x3 (~+9.5 dB) make-up gain on the decoded float (before swr, so loud transients clamp cleanly) and drop the cushion to 80 ms (still covers the ~30 ms per-packet bursts). Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/eld_shim.c | 11 +++++++++++ crossplatform/windows-app/librepods-tray/src/main.rs | 12 ++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c index b7e3f4bbe..b7301dea7 100644 --- a/crossplatform/windows-app/librepods-tray/src/eld_shim.c +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -18,6 +18,10 @@ // labels the frames 48000. Feeding that 64 kHz content as 48 kHz played ~0.75x // slow (deep) and overfed the ring. Resample from the true 64 kHz instead. #define IN_RATE 64000 +// The AirPods mic runs a few dB quiet with lots of headroom; a make-up gain +// brings it up to a comfortable level (applied on the float before resampling, +// so swr clamps cleanly if a loud transient would exceed full scale). +#define GAIN 3.0f typedef struct { AVCodecContext *ctx; @@ -72,6 +76,13 @@ int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int ou swr_init(d->swr); d->in_rate = d->frame->sample_rate; } + // Make-up gain on the decoded float samples (mono plane 0). + if (d->frame->format == AV_SAMPLE_FMT_FLTP || d->frame->format == AV_SAMPLE_FMT_FLT) { + float *pf = (float *)d->frame->data[0]; + for (int i = 0; i < d->frame->nb_samples; i++) { + pf[i] *= GAIN; + } + } uint8_t *outp = (uint8_t *)(out + total); int room = out_cap - total; if (room <= 0) { av_frame_unref(d->frame); break; } diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index db3dbf37d..99cbce82c 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -201,12 +201,12 @@ fn run_receiver( decoder = eld::Decoder::new(); pipe = micpipe::MicPipe::open(); if let Some(pp) = pipe.as_ref() { - // Prime the ring with a short silence cushion: - // we feed in per-packet bursts (~80 ms) while - // the capture drains steadily, so without a - // head start the ring underran between bursts - // (a click per packet). ~150 ms absorbs it. - pp.write(&[0i16; 7200]); + // Prime the ring with a small silence cushion: + // we feed in ~30 ms per-packet bursts while the + // capture drains steadily, so a head start + // avoids underruns between bursts. 80 ms is + // enough and keeps the added latency low. + pp.write(&[0i16; 3840]); } let msg = match (decoder.is_some(), pipe.is_some()) { (true, true) => "Hi-res mic: streaming to the mic", From 3ae0bc55c1c19c68b407bf7264789e55f1de06d1 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:36:03 +0100 Subject: [PATCH 32/48] hires-mic(Phase 4): soft-limit the make-up gain (tanh) to avoid clipping The x3 gain sounded blown out on loud transients (peaks hit -7.8 dB and louder ones hard-clipped). Pass the gained float through tanh: near-linear x3 for normal speech, smooth saturation on peaks instead of harsh clipping. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/eld_shim.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/eld_shim.c b/crossplatform/windows-app/librepods-tray/src/eld_shim.c index b7301dea7..f64895db7 100644 --- a/crossplatform/windows-app/librepods-tray/src/eld_shim.c +++ b/crossplatform/windows-app/librepods-tray/src/eld_shim.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -76,11 +77,13 @@ int eld_decode(void *handle, const uint8_t *au, int au_len, int16_t *out, int ou swr_init(d->swr); d->in_rate = d->frame->sample_rate; } - // Make-up gain on the decoded float samples (mono plane 0). + // Make-up gain with a soft limiter (tanh): normal speech keeps the ~x3 + // gain (nearly linear at low levels), while loud transients saturate + // smoothly instead of hard-clipping (which sounded blown out). if (d->frame->format == AV_SAMPLE_FMT_FLTP || d->frame->format == AV_SAMPLE_FMT_FLT) { float *pf = (float *)d->frame->data[0]; for (int i = 0; i < d->frame->nb_samples; i++) { - pf[i] *= GAIN; + pf[i] = tanhf(pf[i] * GAIN); } } uint8_t *outp = (uint8_t *)(out + total); From 57a2267913521f431f9170dee25f8d1f65dab249 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 21:50:22 +0100 Subject: [PATCH 33/48] hires-mic(Phase 4): auto-enable the mic when an app records (+ UI) Driver: add a capture-activity counter (advances on each MicPipeRead) exposed via IOCTL_LIBREPODS_MIC_STATUS (0x00226004). Tray: open the exclusive mic-pipe handle once and share it between the receive thread (writes) and a new poll thread. The poll reads the counter every 500 ms; when an app starts recording from the virtual mic it auto-sends START_AUDIO (hi-res on), and when it stops (debounced ~1.5 s) it sends STOP_AUDIO + the A2DP stereo reset. No manual toggle needed: replaced the "Hi-res microphone (test)" menu item with an auto-updating "Microphone: idle / recording" status line. Needs a driver reinstall for the new IOCTL. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/main.rs | 123 +++++++++++------- .../windows-app/librepods-tray/src/micpipe.rs | 29 ++++- .../LibrePodsMic/Common/MicPipe.cpp | 15 +++ .../LibrePodsMic/Common/MicPipe.h | 10 ++ 4 files changed, 126 insertions(+), 51 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 99cbce82c..4b601be43 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -134,14 +134,13 @@ fn run_receiver( dev_name: String, driver_cell: Arc>>, mic_on: Arc, + pipe: Option>, ) { let mut buf = [0u8; 8192]; let mut audio_pkts = 0u32; - // Hi-res mic pipeline (Phase 3b): created on first audio packet, torn down - // when the mic is disabled. The decoder holds the FFmpeg AAC-ELD context; - // the pipe writes decoded PCM into \\.\LibrePodsMic. + // Hi-res mic decoder (Phase 3b): created on the first audio packet, torn down + // when the mic is disabled. It feeds the shared mic pipe. let mut decoder: Option = None; - let mut pipe: Option = None; media::init(); // COM (MTA) for the SMTC ear-detection auto-pause on this thread let mut last_anc = 0u8; let mut last_case_present: Option = None; @@ -195,25 +194,16 @@ fn run_receiver( // uplink audio packets and confirm the stream actually started. if mic_on.load(Ordering::Relaxed) { if aap::is_audio_packet(data) { - // Lazily bring up the decoder + mic pipe on the first - // audio packet, and report the outcome once. + // Bring up the decoder on the first audio packet and + // prime the shared mic pipe's ring with a small cushion. if decoder.is_none() { decoder = eld::Decoder::new(); - pipe = micpipe::MicPipe::open(); if let Some(pp) = pipe.as_ref() { - // Prime the ring with a small silence cushion: - // we feed in ~30 ms per-packet bursts while the - // capture drains steadily, so a head start - // avoids underruns between bursts. 80 ms is - // enough and keeps the added latency low. + // We feed ~30 ms per-packet bursts while the + // capture drains steadily, so an 80 ms head + // start avoids underruns without much latency. pp.write(&[0i16; 3840]); } - let msg = match (decoder.is_some(), pipe.is_some()) { - (true, true) => "Hi-res mic: streaming to the mic", - (false, _) => "Hi-res mic: decoder failed (FFmpeg)", - (_, false) => "Hi-res mic: virtual mic not found", - }; - overlay::show(&dev_name, msg); } if let (Some(dec), Some(pp)) = (decoder.as_mut(), pipe.as_ref()) { // Decode all the packet's AUs, then write once. @@ -227,10 +217,9 @@ fn run_receiver( } audio_pkts = audio_pkts.saturating_add(1); } - } else if decoder.is_some() || pipe.is_some() { - // Mic disabled: tear the pipeline down. + } else if decoder.is_some() { + // Mic disabled: drop the decoder. decoder = None; - pipe = None; audio_pkts = 0; } if let Some(b) = aap::parse_battery(data) { @@ -347,10 +336,16 @@ fn main() { // so a stale handle fails) and publishes the live one here. let driver_cell: Arc>> = Arc::new(Mutex::new(None)); - // Whether the hi-res mic stream is enabled (toggled from the menu, read by - // the receive loop). Phase 3. + // Whether the hi-res mic stream is enabled. Driven automatically by the + // capture-activity poll below (on when an app records from the virtual mic), + // read by the receive loop. let mic_on = Arc::new(AtomicBool::new(false)); + // The single (exclusive) handle to the virtual-mic control device, shared by + // the receive thread (writes decoded audio) and the poll thread (reads the + // capture-activity counter). + let pipe: Option> = micpipe::MicPipe::open().map(Arc::new); + // Start the background AAP session if the AirPods are paired. run_receiver // opens the driver itself and keeps retrying, so this works even if they // aren't connected yet at startup. @@ -359,7 +354,53 @@ fn main() { let name = dev_name.clone(); let cell = driver_cell.clone(); let mic = mic_on.clone(); - thread::spawn(move || run_receiver(mac, st, name, cell, mic)); + let rx_pipe = pipe.clone(); + thread::spawn(move || run_receiver(mac, st, name, cell, mic, rx_pipe)); + + // Auto-activate: the driver's capture counter advances while an app is + // recording from the virtual mic. When it starts, enable the hi-res + // stream; when it stops (debounced ~1.5 s), disable it and restore A2DP + // stereo — so the mic "just works" when you join a call. + let poll_pipe = pipe.clone(); + let poll_mic = mic_on.clone(); + let poll_cell = driver_cell.clone(); + let poll_name = dev_name.clone(); + thread::spawn(move || { + let mut prev = poll_pipe.as_ref().map(|p| p.status()).unwrap_or(0); + let mut idle = 0u32; + let mut on = false; + loop { + thread::sleep(Duration::from_millis(500)); + let cur = match poll_pipe.as_ref() { + Some(p) => p.status(), + None => break, + }; + let capturing = cur != prev; + prev = cur; + if capturing { + idle = 0; + if !on { + on = true; + poll_mic.store(true, Ordering::Relaxed); + if let Some(drv) = poll_cell.lock().unwrap().clone() { + let _ = drv.send(&aap::START_AUDIO); + } + overlay::show(&poll_name, "Microphone in use — hi-res on"); + } + } else { + idle += 1; + if on && idle >= 3 { + on = false; + poll_mic.store(false, Ordering::Relaxed); + if let Some(drv) = poll_cell.lock().unwrap().clone() { + let _ = drv.send(&aap::STOP_AUDIO); + } + a2dp::reset(mac); + overlay::show(&poll_name, "Microphone released — stereo restored"); + } + } + } + }); } // --- Tray menu --- @@ -374,7 +415,9 @@ fn main() { let m_vol_up = MenuItem::new("Volume +", true, None); let m_vol_down = MenuItem::new("Volume −", true, None); let m_mute = MenuItem::new("Mute / Unmute", true, None); - let m_mic = CheckMenuItem::new("Hi-res microphone (test)", true, false, None); + // Auto-managed hi-res mic status line (enabled automatically when an app + // records from the virtual mic). + let m_mic = MenuItem::new("Microphone: idle", false, None); let m_open = MenuItem::new("Open App", true, None); let quit = MenuItem::new("Quit", true, None); @@ -385,7 +428,6 @@ fn main() { let vol_up_id = m_vol_up.id().clone(); let vol_down_id = m_vol_down.id().clone(); let mute_id = m_mute.id().clone(); - let mic_id = m_mic.id().clone(); let open_id = m_open.id().clone(); let quit_id = quit.id().clone(); @@ -446,6 +488,11 @@ fn main() { .unwrap_or_else(|| "—".into()) }; vol_line.set_text(format!("Volume: {vol}")); + m_mic.set_text(if mic_on.load(Ordering::Relaxed) { + "Microphone: recording (hi-res)" + } else { + "Microphone: idle" + }); let _ = tray.set_tooltip(Some(format!( "{dev_name} · {bt} · ANC: {} · Vol: {vol}", aap::anc_name(s.anc) @@ -500,30 +547,6 @@ fn main() { } else if ev.id == mute_id { volume::toggle_mute(); refresh(); - } else if ev.id == mic_id { - // Toggle the hi-res mic stream (Phase 3 de-risk): send the - // enable/stop command; the receive loop confirms audio flow. - let on = !mic_on.load(Ordering::Relaxed); - mic_on.store(on, Ordering::Relaxed); - m_mic.set_checked(on); - if let Some(drv) = driver_cell.lock().unwrap().clone() { - let cmd: &[u8] = if on { &aap::START_AUDIO } else { &aap::STOP_AUDIO }; - let _ = drv.send(cmd); - } - if !on { - // The mic mode degraded A2DP to mono; reconnect the A2DP - // service to restore stereo (off the UI thread — it waits - // ~1.5 s between disable/enable). Report the result codes. - if let Some(m) = mac { - thread::spawn(move || { - a2dp::reset(m); - }); - } - } - overlay::show( - &dev_name, - if on { "Hi-res mic: enabling…" } else { "Hi-res mic: restoring stereo…" }, - ); } else if let Some(mode) = mode_for(&ev.id) { if let Some(drv) = driver_cell.lock().unwrap().clone() { let _ = drv.send(&aap::anc_command(mode)); diff --git a/crossplatform/windows-app/librepods-tray/src/micpipe.rs b/crossplatform/windows-app/librepods-tray/src/micpipe.rs index 15583c16c..f36b6f28f 100644 --- a/crossplatform/windows-app/librepods-tray/src/micpipe.rs +++ b/crossplatform/windows-app/librepods-tray/src/micpipe.rs @@ -10,15 +10,22 @@ use windows_sys::Win32::Storage::FileSystem::{ }; use windows_sys::Win32::System::IO::DeviceIoControl; +const GENERIC_READ: u32 = 0x8000_0000; const GENERIC_WRITE: u32 = 0x4000_0000; // CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) const IOCTL_LIBREPODS_MIC_WRITE_PCM: u32 = 0x0022_A000; +// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA) +const IOCTL_LIBREPODS_MIC_STATUS: u32 = 0x0022_6004; pub struct MicPipe { handle: HANDLE, } +// One tray owns the single exclusive handle and uses it from the receive thread +// (writes) and the status-poll thread (reads); both DeviceIoControl paths are +// independent, so sharing the handle is safe. unsafe impl Send for MicPipe {} +unsafe impl Sync for MicPipe {} impl MicPipe { /// Open the virtual-mic control device. None if the LibrePodsMic driver @@ -31,7 +38,7 @@ impl MicPipe { let handle = unsafe { CreateFileW( path.as_ptr(), - GENERIC_WRITE, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, ptr::null(), OPEN_EXISTING, @@ -46,6 +53,26 @@ impl MicPipe { } } + /// Capture-activity counter — advances while an app is recording from the + /// virtual mic. The tray polls it to auto-enable/disable the hi-res stream. + pub fn status(&self) -> i32 { + let mut out = [0u8; 4]; + let mut returned = 0u32; + unsafe { + DeviceIoControl( + self.handle, + IOCTL_LIBREPODS_MIC_STATUS, + ptr::null(), + 0, + out.as_mut_ptr() as *mut c_void, + 4, + &mut returned, + ptr::null_mut(), + ); + } + i32::from_le_bytes(out) + } + /// Push mono 16-bit PCM samples into the mic ring. pub fn write(&self, samples: &[i16]) { if samples.is_empty() { diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp index a58019bd0..fdeea4195 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp +++ b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.cpp @@ -36,6 +36,11 @@ static BOOLEAN g_Inited = FALSE; static WDFDEVICE g_ControlDevice = NULL; +// Advances on every capture pull (MicPipeRead). The tray polls it to tell when +// an app is actually recording from the mic, and auto-enables/disables the +// hi-res stream accordingly. +static volatile LONG g_ReadTick = 0; + EXTERN_C_START VOID @@ -92,6 +97,8 @@ MicPipeRead( if (Out == NULL || Len == 0) { return; } + // A capture is pulling data: mark activity so the tray can auto-enable. + InterlockedIncrement(&g_ReadTick); if (!g_Inited) { RtlZeroMemory(Out, Len); return; @@ -136,6 +143,14 @@ MicPipe_EvtIoDeviceControl( MicPipeWrite(buf, (ULONG)len); info = len; } + } else if (IoControlCode == IOCTL_LIBREPODS_MIC_STATUS) { + PVOID buf = NULL; + size_t len = 0; + status = WdfRequestRetrieveOutputBuffer(Request, sizeof(LONG), &buf, &len); + if (NT_SUCCESS(status)) { + *(LONG *)buf = InterlockedCompareExchange(&g_ReadTick, 0, 0); + info = sizeof(LONG); + } } WdfRequestCompleteWithInformation(Request, status, info); diff --git a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h index 429f256e8..aab435dc1 100644 --- a/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h +++ b/crossplatform/windows-driver/LibrePodsMic/Common/MicPipe.h @@ -34,6 +34,16 @@ Module Name: #define IOCTL_LIBREPODS_MIC_WRITE_PCM \ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_WRITE_DATA) +// +// IOCTL: user mode reads a capture-activity counter (ULONG). It advances every +// time an app pulls a capture packet, so the tray can tell when the mic is +// actually being recorded and auto-enable/disable the hi-res stream. +// Value (precomputed): 0x00226004. +// CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA) +// +#define IOCTL_LIBREPODS_MIC_STATUS \ + CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_READ_DATA) + EXTERN_C_START // From 4d1304550762e1562e7a18a9762ddc1b441756f3 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:01:54 +0100 Subject: [PATCH 34/48] hires-mic(Phase 4): faster A2DP reset (shorter disconnect on mic stop) Cut the settle+teardown from 1s+2s to 0.4s+1.4s so the stereo-restore reconnect is a ~1.8 s blip instead of ~3 s. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/a2dp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/a2dp.rs b/crossplatform/windows-app/librepods-tray/src/a2dp.rs index 6ba38a802..5d3e259d1 100644 --- a/crossplatform/windows-app/librepods-tray/src/a2dp.rs +++ b/crossplatform/windows-app/librepods-tray/src/a2dp.rs @@ -76,11 +76,11 @@ pub fn reset(mac: u64) -> (u32, u32) { // Let the mic-stop transition settle so the AirPods have left mic mode // before we touch A2DP. - std::thread::sleep(std::time::Duration::from_millis(1000)); + std::thread::sleep(std::time::Duration::from_millis(400)); let d = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_DISABLE); - // Let the A2DP link fully tear down before reconnecting, else it - // re-establishes mid-teardown (mono/crackle) and needs another try. - std::thread::sleep(std::time::Duration::from_millis(2000)); + // Let the A2DP link tear down before reconnecting, else it re-establishes + // mid-teardown (mono/crackle) and needs another try. + std::thread::sleep(std::time::Duration::from_millis(1400)); let e = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); CloseHandle(radio); From 2efd000fe7293f4384ce1ba997d5aa7f2bf33fb3 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:07:59 +0100 Subject: [PATCH 35/48] hires-mic(Phase 4): faster reset + manual mode toggle - a2dp reset trimmed to 150 ms settle + 1000 ms teardown (shorter playback blip; the reconnect handshake itself is Windows/BT and can't be sped up). - Menu: "Auto-enable on recording" checkbox (default on) + a "Hi-res microphone (manual)" override. In manual mode the poll stops auto-managing and the user drives the mic directly (with the same STOP + stereo reset on off). Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/a2dp.rs | 7 +-- .../windows-app/librepods-tray/src/main.rs | 49 ++++++++++++++++++- 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/a2dp.rs b/crossplatform/windows-app/librepods-tray/src/a2dp.rs index 5d3e259d1..256dfa40d 100644 --- a/crossplatform/windows-app/librepods-tray/src/a2dp.rs +++ b/crossplatform/windows-app/librepods-tray/src/a2dp.rs @@ -76,11 +76,12 @@ pub fn reset(mac: u64) -> (u32, u32) { // Let the mic-stop transition settle so the AirPods have left mic mode // before we touch A2DP. - std::thread::sleep(std::time::Duration::from_millis(400)); + std::thread::sleep(std::time::Duration::from_millis(150)); let d = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_DISABLE); // Let the A2DP link tear down before reconnecting, else it re-establishes - // mid-teardown (mono/crackle) and needs another try. - std::thread::sleep(std::time::Duration::from_millis(1400)); + // mid-teardown (mono/crackle) and needs another try. (The reconnect + // handshake after ENABLE is Windows/BT — we can't speed that part up.) + std::thread::sleep(std::time::Duration::from_millis(1000)); let e = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); CloseHandle(radio); diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 4b601be43..f392954a6 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -341,6 +341,10 @@ fn main() { // read by the receive loop. let mic_on = Arc::new(AtomicBool::new(false)); + // Auto mode (default): the poll auto-enables/disables the mic on recording. + // Users who prefer can turn it off and drive the mic manually. + let auto_mode = Arc::new(AtomicBool::new(true)); + // The single (exclusive) handle to the virtual-mic control device, shared by // the receive thread (writes decoded audio) and the poll thread (reads the // capture-activity counter). @@ -365,6 +369,7 @@ fn main() { let poll_mic = mic_on.clone(); let poll_cell = driver_cell.clone(); let poll_name = dev_name.clone(); + let poll_auto = auto_mode.clone(); thread::spawn(move || { let mut prev = poll_pipe.as_ref().map(|p| p.status()).unwrap_or(0); let mut idle = 0u32; @@ -377,6 +382,12 @@ fn main() { }; let capturing = cur != prev; prev = cur; + // Manual mode: don't auto-manage (but keep `prev` fresh above so + // re-enabling auto doesn't fire a spurious transition). + if !poll_auto.load(Ordering::Relaxed) { + on = poll_mic.load(Ordering::Relaxed); + continue; + } if capturing { idle = 0; if !on { @@ -415,9 +426,10 @@ fn main() { let m_vol_up = MenuItem::new("Volume +", true, None); let m_vol_down = MenuItem::new("Volume −", true, None); let m_mute = MenuItem::new("Mute / Unmute", true, None); - // Auto-managed hi-res mic status line (enabled automatically when an app - // records from the virtual mic). + // Hi-res mic: a status line + an "auto" toggle + a manual override. let m_mic = MenuItem::new("Microphone: idle", false, None); + let m_auto = CheckMenuItem::new("Auto-enable on recording", true, true, None); + let m_mic_manual = CheckMenuItem::new("Hi-res microphone (manual)", true, false, None); let m_open = MenuItem::new("Open App", true, None); let quit = MenuItem::new("Quit", true, None); @@ -428,6 +440,8 @@ fn main() { let vol_up_id = m_vol_up.id().clone(); let vol_down_id = m_vol_down.id().clone(); let mute_id = m_mute.id().clone(); + let auto_id = m_auto.id().clone(); + let mic_manual_id = m_mic_manual.id().clone(); let open_id = m_open.id().clone(); let quit_id = quit.id().clone(); @@ -447,6 +461,8 @@ fn main() { menu.append(&m_mute).unwrap(); menu.append(&PredefinedMenuItem::separator()).unwrap(); menu.append(&m_mic).unwrap(); + menu.append(&m_auto).unwrap(); + menu.append(&m_mic_manual).unwrap(); menu.append(&m_open).unwrap(); menu.append(&quit).unwrap(); @@ -493,6 +509,8 @@ fn main() { } else { "Microphone: idle" }); + m_auto.set_checked(auto_mode.load(Ordering::Relaxed)); + m_mic_manual.set_checked(mic_on.load(Ordering::Relaxed)); let _ = tray.set_tooltip(Some(format!( "{dev_name} · {bt} · ANC: {} · Vol: {vol}", aap::anc_name(s.anc) @@ -547,6 +565,33 @@ fn main() { } else if ev.id == mute_id { volume::toggle_mute(); refresh(); + } else if ev.id == auto_id { + let on = !auto_mode.load(Ordering::Relaxed); + auto_mode.store(on, Ordering::Relaxed); + m_auto.set_checked(on); + overlay::show( + &dev_name, + if on { "Microphone: auto mode" } else { "Microphone: manual mode" }, + ); + } else if ev.id == mic_manual_id { + // Manual override: turn the hi-res mic on/off directly. + let on = !mic_on.load(Ordering::Relaxed); + mic_on.store(on, Ordering::Relaxed); + m_mic_manual.set_checked(on); + if let Some(drv) = driver_cell.lock().unwrap().clone() { + let cmd: &[u8] = if on { &aap::START_AUDIO } else { &aap::STOP_AUDIO }; + let _ = drv.send(cmd); + } + if !on { + if let Some(m) = mac { + thread::spawn(move || a2dp::reset(m)); + } + } + overlay::show( + &dev_name, + if on { "Hi-res mic on" } else { "Hi-res mic off — restoring stereo…" }, + ); + refresh(); } else if let Some(mode) = mode_for(&ev.id) { if let Some(drv) = driver_cell.lock().unwrap().clone() { let _ = drv.send(&aap::anc_command(mode)); From a538d6e31be252ab93618a89b2279755d404976e Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:20:08 +0100 Subject: [PATCH 36/48] hires-mic(Phase 4): manual-mode debounce + persistent reconnect card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Manual mic-off now uses the same 1.5 s debounce as auto (keeps decoding the tail before STOP), so it no longer clips the end of a recording. - Show "Restoring stereo…" through the whole A2DP reconnect and "Stereo restored" when it finishes (both auto and manual), and bump the overlay auto-hide to 4.5 s so the card stays up until the switch completes. Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/src/main.rs | 40 +++++++++++++------ .../windows-app/librepods-tray/src/overlay.rs | 2 +- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index f392954a6..2b9c188e6 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -406,8 +406,9 @@ fn main() { if let Some(drv) = poll_cell.lock().unwrap().clone() { let _ = drv.send(&aap::STOP_AUDIO); } + overlay::show(&poll_name, "Microphone released — restoring stereo…"); a2dp::reset(mac); - overlay::show(&poll_name, "Microphone released — stereo restored"); + overlay::show(&poll_name, "Stereo restored"); } } } @@ -576,21 +577,34 @@ fn main() { } else if ev.id == mic_manual_id { // Manual override: turn the hi-res mic on/off directly. let on = !mic_on.load(Ordering::Relaxed); - mic_on.store(on, Ordering::Relaxed); m_mic_manual.set_checked(on); - if let Some(drv) = driver_cell.lock().unwrap().clone() { - let cmd: &[u8] = if on { &aap::START_AUDIO } else { &aap::STOP_AUDIO }; - let _ = drv.send(cmd); - } - if !on { - if let Some(m) = mac { - thread::spawn(move || a2dp::reset(m)); + if on { + mic_on.store(true, Ordering::Relaxed); + if let Some(drv) = driver_cell.lock().unwrap().clone() { + let _ = drv.send(&aap::START_AUDIO); } + overlay::show(&dev_name, "Hi-res mic on"); + } else { + // Same 1.5 s debounce as auto so the tail isn't clipped, + // then stop + restore stereo, keeping the card up through + // the whole reconnect. + let mic = mic_on.clone(); + let cell = driver_cell.clone(); + let name = dev_name.clone(); + thread::spawn(move || { + thread::sleep(Duration::from_millis(1500)); + mic.store(false, Ordering::Relaxed); + if let Some(drv) = cell.lock().unwrap().clone() { + let _ = drv.send(&aap::STOP_AUDIO); + } + overlay::show(&name, "Restoring stereo…"); + if let Some(m) = mac { + a2dp::reset(m); + } + overlay::show(&name, "Stereo restored"); + }); + overlay::show(&dev_name, "Hi-res mic off"); } - overlay::show( - &dev_name, - if on { "Hi-res mic on" } else { "Hi-res mic off — restoring stereo…" }, - ); refresh(); } else if let Some(mode) = mode_for(&ev.id) { if let Some(drv) = driver_cell.lock().unwrap().clone() { diff --git a/crossplatform/windows-app/librepods-tray/src/overlay.rs b/crossplatform/windows-app/librepods-tray/src/overlay.rs index 74dadf3bd..103cf1d26 100644 --- a/crossplatform/windows-app/librepods-tray/src/overlay.rs +++ b/crossplatform/windows-app/librepods-tray/src/overlay.rs @@ -27,7 +27,7 @@ const WIDTH: i32 = 380; const HEIGHT: i32 = 96; const TOP_MARGIN: i32 = 48; const HIDE_TIMER_ID: usize = 1; -const HIDE_MS: u32 = 3200; +const HIDE_MS: u32 = 4500; const WM_SHOW_OVERLAY: u32 = WM_APP + 1; const HWND_TOPMOST: HWND = -1isize as HWND; From 7fb630ce4dad92224d6fe49b2d875cf0dfea16b1 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:24:18 +0100 Subject: [PATCH 37/48] hires-mic(Phase 4): longer manual debounce + card stays through reconnect Manual mic-off debounce 1.5s -> 3.5s (more tail margin, per feedback). a2dp reset now waits ~1.5s after ENABLE for the reconnect handshake before returning, so the 'Restoring stereo...' card stays up through the whole reconnect and 'Stereo restored' lands when the stereo is actually back. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-app/librepods-tray/src/a2dp.rs | 4 ++++ crossplatform/windows-app/librepods-tray/src/main.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/crossplatform/windows-app/librepods-tray/src/a2dp.rs b/crossplatform/windows-app/librepods-tray/src/a2dp.rs index 256dfa40d..a5853fb35 100644 --- a/crossplatform/windows-app/librepods-tray/src/a2dp.rs +++ b/crossplatform/windows-app/librepods-tray/src/a2dp.rs @@ -83,6 +83,10 @@ pub fn reset(mac: u64) -> (u32, u32) { // handshake after ENABLE is Windows/BT — we can't speed that part up.) std::thread::sleep(std::time::Duration::from_millis(1000)); let e = BluetoothSetServiceState(radio, &info, &A2DP_SERVICE, BLUETOOTH_SERVICE_ENABLE); + // ENABLE returns immediately but the A2DP reconnect handshake runs after + // it in the BT stack; wait for it so the caller's "restored" card lands + // when the stereo is actually back (not before). + std::thread::sleep(std::time::Duration::from_millis(1500)); CloseHandle(radio); BluetoothFindRadioClose(hfind); diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index 2b9c188e6..c9682d4a1 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -592,7 +592,7 @@ fn main() { let cell = driver_cell.clone(); let name = dev_name.clone(); thread::spawn(move || { - thread::sleep(Duration::from_millis(1500)); + thread::sleep(Duration::from_millis(3500)); mic.store(false, Ordering::Relaxed); if let Some(drv) = cell.lock().unwrap().clone() { let _ = drv.send(&aap::STOP_AUDIO); From 4936f210d7eae625163e847d012c608c5bf0d06f Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:33:35 +0100 Subject: [PATCH 38/48] =?UTF-8?q?hires-mic(Phase=204):=20minimal=20FFmpeg?= =?UTF-8?q?=20build=20=E2=80=94=2069=20MB=20avcodec=20->=200.7=20MB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the BtbN full FFmpeg DLLs with a minimal FFmpeg 7.1 build (LGPL, only the AAC decoder: --disable-everything --enable-decoder=aac...). avcodec 69 MB -> 0.7 MB; the three DLLs total ~1.6 MB (was ~73 MB), small enough to commit so the repo is self-contained. Re-vendored include/ + import libs + DLLs (avcodec-61, avutil-59, swresample-5); the tray relinks against them unchanged. Co-Authored-By: Claude Opus 4.8 --- .../librepods-tray/vendor/ffmpeg/.gitignore | 3 +- .../vendor/ffmpeg/LICENSE-ffmpeg.txt | 657 +++++++++++++----- .../librepods-tray/vendor/ffmpeg/README.md | 21 +- .../vendor/ffmpeg/bin/avcodec-61.dll | Bin 0 -> 748032 bytes .../vendor/ffmpeg/bin/avutil-59.dll | Bin 0 -> 854528 bytes .../vendor/ffmpeg/bin/swresample-5.dll | Bin 0 -> 92160 bytes .../ffmpeg/include/libavcodec/avcodec.h | 307 ++++++-- .../vendor/ffmpeg/include/libavcodec/avdct.h | 3 - .../vendor/ffmpeg/include/libavcodec/avfft.h | 149 ++++ .../vendor/ffmpeg/include/libavcodec/bsf.h | 376 ---------- .../vendor/ffmpeg/include/libavcodec/codec.h | 37 + .../ffmpeg/include/libavcodec/codec_desc.h | 8 - .../ffmpeg/include/libavcodec/codec_id.h | 29 +- .../ffmpeg/include/libavcodec/codec_par.h | 146 ++-- .../vendor/ffmpeg/include/libavcodec/defs.h | 25 - .../vendor/ffmpeg/include/libavcodec/exif.h | 242 ------- .../vendor/ffmpeg/include/libavcodec/packet.h | 95 +-- .../ffmpeg/include/libavcodec/smpte_436m.h | 254 ------- .../vendor/ffmpeg/include/libavcodec/vdpau.h | 33 + .../ffmpeg/include/libavcodec/version.h | 2 +- .../ffmpeg/include/libavcodec/version_major.h | 15 +- .../ffmpeg/include/libavutil/attributes.h | 78 +-- .../ffmpeg/include/libavutil/avassert.h | 51 +- .../ffmpeg/include/libavutil/avstring.h | 2 +- .../vendor/ffmpeg/include/libavutil/avutil.h | 22 + .../vendor/ffmpeg/include/libavutil/bswap.h | 2 +- .../ffmpeg/include/libavutil/channel_layout.h | 21 +- .../vendor/ffmpeg/include/libavutil/common.h | 19 +- .../ffmpeg/include/libavutil/container_fifo.h | 130 ---- .../vendor/ffmpeg/include/libavutil/cpu.h | 23 +- .../vendor/ffmpeg/include/libavutil/csp.h | 64 +- .../vendor/ffmpeg/include/libavutil/dict.h | 3 +- .../ffmpeg/include/libavutil/dovi_meta.h | 12 - .../ffmpeg/include/libavutil/downmix_info.h | 65 -- .../ffmpeg/include/libavutil/ffversion.h | 2 +- .../include/libavutil/film_grain_params.h | 60 +- .../vendor/ffmpeg/include/libavutil/frame.h | 196 ++---- .../include/libavutil/hdr_dynamic_metadata.h | 104 --- .../libavutil/hdr_dynamic_vivid_metadata.h | 60 +- .../ffmpeg/include/libavutil/hwcontext.h | 5 +- .../ffmpeg/include/libavutil/hwcontext_amf.h | 58 -- .../ffmpeg/include/libavutil/hwcontext_cuda.h | 74 +- .../include/libavutil/hwcontext_d3d11va.h | 14 - .../include/libavutil/hwcontext_d3d12va.h | 69 +- .../ffmpeg/include/libavutil/hwcontext_oh.h | 34 - .../include/libavutil/hwcontext_opencl.h | 2 +- .../ffmpeg/include/libavutil/hwcontext_qsv.h | 1 + .../include/libavutil/hwcontext_vaapi.h | 2 +- .../include/libavutil/hwcontext_vulkan.h | 101 ++- .../vendor/ffmpeg/include/libavutil/iamf.h | 25 +- .../vendor/ffmpeg/include/libavutil/lfg.h | 4 +- .../vendor/ffmpeg/include/libavutil/log.h | 76 +- .../ffmpeg/include/libavutil/mathematics.h | 2 +- .../vendor/ffmpeg/include/libavutil/opt.h | 35 +- .../vendor/ffmpeg/include/libavutil/pixdesc.h | 10 - .../vendor/ffmpeg/include/libavutil/pixfmt.h | 115 +-- .../ffmpeg/include/libavutil/rational.h | 2 +- .../include/libavutil/raw_color_params.h | 147 ---- .../vendor/ffmpeg/include/libavutil/rc4.h | 2 +- .../ffmpeg/include/libavutil/refstruct.h | 297 -------- .../ffmpeg/include/libavutil/samplefmt.h | 3 +- .../ffmpeg/include/libavutil/spherical.h | 6 - .../vendor/ffmpeg/include/libavutil/tdrdi.h | 164 ----- .../vendor/ffmpeg/include/libavutil/tx.h | 2 +- .../vendor/ffmpeg/include/libavutil/version.h | 22 +- .../ffmpeg/include/libavutil/video_hint.h | 2 +- .../ffmpeg/include/libswresample/swresample.h | 2 +- .../ffmpeg/include/libswresample/version.h | 2 +- .../include/libswresample/version_major.h | 2 +- .../vendor/ffmpeg/lib/libavcodec.dll.a | Bin 132774 -> 107470 bytes .../vendor/ffmpeg/lib/libavutil.dll.a | Bin 424590 -> 398602 bytes .../vendor/ffmpeg/lib/libswresample.dll.a | Bin 15964 -> 15964 bytes 72 files changed, 1452 insertions(+), 3144 deletions(-) create mode 100755 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avcodec-61.dll create mode 100755 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avutil-59.dll create mode 100755 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/swresample-5.dll create mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avfft.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h delete mode 100644 crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore index 4b7734f67..981264126 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/.gitignore @@ -1,2 +1 @@ -# Runtime DLLs (~75 MB) — fetched, not committed. See README / fetch note. -bin/*.dll +# (Minimal FFmpeg DLLs are small enough to commit — see README.) diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt index 65c5ca88a..58af0d378 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/LICENSE-ffmpeg.txt @@ -1,165 +1,502 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md index 8c2a6794e..71cc9e4f0 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/README.md @@ -1,11 +1,14 @@ -# Vendored FFmpeg (LGPL) — AAC-ELD decoder for the hi-res mic +# Vendored FFmpeg (LGPL, minimal) — AAC-ELD decoder for the hi-res mic -From BtbN's **`ffmpeg-master-latest-win64-lgpl-shared`** -(https://github.com/BtbN/FFmpeg-Builds/releases/latest) — LGPLv3, no GPL/nonfree, -`--disable-libfdk-aac`. See `LICENSE-ffmpeg.txt`. +A **minimal** FFmpeg 7.1 build (LGPL v2.1), configured with only the AAC decoder: -Committed (needed to *build*): `include/` (libavcodec, libavutil, libswresample) -and `lib/*.dll.a` (mingw import libs). The `bin/*.dll` runtime libraries -(`avcodec-63.dll`, `avutil-61.dll`, `swresample-7.dll`, ~75 MB) are **not** in git -— download the same BtbN build and copy them into `bin/`, and ship them next to -`librepods-tray.exe`. + ./configure --cross-prefix=x86_64-w64-mingw32- --arch=x86_64 --target-os=mingw32 \ + --enable-shared --disable-static --disable-everything --disable-programs \ + --disable-avdevice --disable-avformat --disable-swscale --disable-postproc \ + --disable-avfilter --disable-network --disable-x86asm \ + --enable-decoder=aac --enable-decoder=aac_fixed --enable-decoder=aac_latm + +That shrinks avcodec from ~69 MB (BtbN full build) to ~0.7 MB. Committed: +`include/` (libavcodec, libavutil, libswresample), `lib/*.dll.a` (mingw import +libs), and `bin/*.dll` (avcodec-61, avutil-59, swresample-5 — ~1.6 MB total, +shipped next to librepods-tray.exe). See `LICENSE-ffmpeg.txt`. diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avcodec-61.dll b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avcodec-61.dll new file mode 100755 index 0000000000000000000000000000000000000000..2799bb892050dd8390d90c426aac0ab3d5027d8c GIT binary patch literal 748032 zcmd44e|!|x)%d@gY#=~j0tOl@O6s#(VyO>lwPg#o8Q6tc*eETisI=0CQmoYSXrfpV z5_cCe4iiw3^0aFC^w(pnt^JAM58O?F5Uff_RnWEqTHPU{h)*G)knj84ncZvv`^C>c z-)~;Z?97~d?z!ilbMCq4o_nX}+Eu`RyXfUgV{Ea&V|`g{otiZ_FqjP9Nr* zE{r)i&=)>mpuE31!+dLpXKzluuKVFY-{?~x`x-_J^Og5I%?t0*#dY6aRLAeN-=NJx zkhEPoCGT$zPcNSP&AM;$Y>zx&2#hp)F4w%jYM(E4@y#w^s+LAH@P01Wd8fctU%b$T zQ*ETJKIxe4T=V{_5r>Nxxo|Tpc~L>1T*URA)4+Y}mRqD~^#e3^I&i1?YY_Ur?c!5B zhxfiR0L%NrS4+J&xNxdZO6l7Q;KrN+m%4b;*Jkp@H%tB*3!LyJb{e?41&Th^=hYtE z<)?wW`Ieh&L7`*-Sx|j(QhTa}zMH?j;QIh7nLsvtBPcZU6nqnT`v1#6!ybI}D}#K_ z>f!x;+Nf&ZmHJismHN!9ubN@R->xw11;Gl#e4)nNoZP7;m(m2QXfN=|)RJ$+Gk(K5 z_ni9%`XW_tJcFkB%%Uy4i&>w2sNXPOSBc=;m_hFJo)=^0o`Z(=`|*ak)kvo5Glq59 zd-o3XS^eYP1zKV&g*S@UW!^ZuzwZf!YljivTyfnuuGeSlU)R6!_11aXsIbo$KjyE0 z?c0VGxL_>c)c<3!7}mn#NY#Oub?F6CahW#CXN0zDiIsxZCE%r)nGpg$FSYLj*sv~L zCb@5xnk1BEo@8gnrkvDDqgdpc~_1@*;LsH;#JXm#Q zZ*PuPy&1DEm?a3z=XJ9zXm-ZTw&c$GIabj?$fku~$XpZZ=Zl)%RXYvyz09MN)Q$Oy z+^o#I(akNH7moMzz|MZ~8;*v}jNTRqQfm)gH`?pEueYjpX9~e;PwD}&!UflF8=q-b z2 z^84K8T5u6{IA7<9OUEOZss^b(lQum&Q6WyIwB-2wVt?d$4#%4Oo82FRP*Vu2k&B|E zE9oeq$>%hmfR1?=XFF5m(AH%z{$GERYvXQ`K{0P`}uKZHC!zgGdY=^z~Nm0q_HtEo{WQd+G{}0sS_J z>?xqUCMmlx+OV#vh}rRV0c@;ott%0Ics^>c@=5y@pAD-(^kt-BH&tIQubYgAxY$j; zx7A(o1i#OSw-m=hE%lu-`!2E9HKA?wPZ*XZK1k-Qs(wCe&0J_ubReVsU8!m{tosBa zg6f#>wM|^;D+YY#v;cy$=x;`Cvy_o{+l}(M>y zgaOF|TH;$2)U61u(GuSn0^;L-ZRHl)RAVhMqV_}Uqz>~$)O@W=o3|<&Z!3<5dbGsP zfQVY7jO43zT~@pT_M(}4t^0!VYv-but@wO?g&rBrzgpr-ki@$SwbdzYeJY;v!=^u5 z)&d1FMnS{{;wTVlZGC&#o?Yz6^e$Ot#TW8={3Bx((58Gex*aYAs6cD}4#I6&bqeqj z1^BPiU@O#`zbt_9MGA170vver z1$ayVvrY9d_S2eM0SrA77LerQ{0@hHHdo#Jnw$8O34Z(Q#?o1aZlJ)O)TPty^~WPt_B_nQX5sr+_@6fbUP)0s^T7X7gzU zX2|K~CH|zyi@$zfPF!~N6_>+Bc|3H*Wqn_937)2d{Y&m~#U+fx z$4T!e_E12#mSvDMJhlIbTK9{+t+8w|!n&DJ2xbN=V&;CmXN{P$`0+w5(WY$3H>THM zvS6%X{zH7J244G4YiC@!Dg0=;Y5sqeo2LZg6f<*@+#JbA(`#lx zZbqJ|+{_TbQ_al(S8@}!R;VFLb@qNG8*8K^^|pv~C;hn@WA$ORmi)m{{52Vc;s^XO zi$TixtPIBS4C zuJv|U?OD!9Rl93RF`;TW5+uJ?T~VMVuLGNFfYgZZ%m>3N@Wm9qg@W%WvVA#>{wT97 z1DI=;wZw(Mh3#2tL`sg}#>MSiDzxTYH1JPX_~o&p_a{=$oElI|hRiJeijFM(D|@lGf~XJuvlRX| z!7o#p1Au-c{W8?%=x+rwNBHAH|RS{!9Ru>(4rFy#8DbqCWg^`%@k(e*8?zol$?@4rGoWH}uwUHKzL;UyT<8SQ6|7Q^O!SBlB z^I7|{LCSp;|NF?JjQ%t7fD z(f2+4)6W?Hh57hL^x}UCRC)Ma{=b~<-;n^GN&o&Y&VEjQ-r&ZQ{|8R)Uzh%Mf?w?W zeku1+{O`k`6p%Uo|E{-&T2N)_k6M=(ht0Xc3f**KcF}?B2)~W?{DaK96~sW4lW^sG z#5`W297DKn>wXM|Oher9QCcgLqM#?e&ToM}Bfvkw$%yq}0KYSmd{s-leW<5LZ+JQ- z9!lL1&nmf&?O2{SP$iSstw4#Jn|zudOp$~VfMP;N%xu969viXLWGW`g6p_&7Lx4uy zDO4oct|g!0-g%XO!sagNh1{e~vDRx|woz)tbUr-zaiEV&g=fO74Em;UaptVJ>0>c&D3qKj)&KD^xH0r&aAWEx<4i*9Go7r3uSffU@8ExQ?(kWxEP7D!Z z)c*dVwxwSb)G_}*!c8;J>aT}7mYf^b){l^f9*n#wCSvR7<`T5DGr4)EYlIi)j<*!*@h$%Nd;VDHP~F&u9~AiOFKYObzy6N*81Ts{<`_v<66`_Y%n38AMJc|Ui>IA-q&cs zyvC!xg1V@|LO{e`e6BC%-y?L>$7it^FwGxt^~cPyTdN29V*?IF3CNG0i%G_Q4#IjYnVhJ_R?LW zr4KUYZ}s%}+gRdRQU#j+^H^}Gf6UXTs&>QNW;AXVA?Ooz@ZQ&$PMD!^rf&Y-{6H2- zW(m8rM3Ar@Bn^aTG3Mu4p4B}@Plip$u*<52WrlyhVwex<{u2LxO_)_P;C(@I|S`1=UVds<>V!rX9s0rRUW`4#fl|4q3D~I=0!Rrcn3`#GzXAk#P5fZv9ndD!n#M1}YY;^L#)q`SYuQa5@RRZ%c zwxh;;&82M}gPbxSTA~!9^G!(3UZWGkwDnVa%}4>-(W@CJn~@!=C72OiI`X!R7B|lW7dIRM=^IGWfNzCgNUkcBRFFEtNRNFvb3LTJstMKU*OPj|mWoN(U+1XFJ{Mt)|rH`%6 z!To(=p|gI7}YL%6hT!^|D_EtDI zB5J-L?R?!OYpRfik+pB}pKN7M=36;hfIPj{SDp^#4NJ%qRUl8)rzPKon4CULr9Flf z!w#Ffj14_Kg}!bYWQ5XM;%YHEu0Mt%!QV~rmy8qF`>EOqA7hqL8XI4H%V=%=!g4xu z*4giC-hkGT-~&=INUUA00w`cZtm2ER+nP*)L_8+bgQ^y&EExQ#N5&Kpwh?Q zap<_>56KTK;@tpq&Ob%0M$-&9q=xIhEMolszmzM*pBD(EWcky)2Qy18&M5k$H-3XV z;4~xF@zw%o8CU3x@9{g+8NcuioLkhZfO8{PB?`&Q&>5#3T<*9cGw6ld`f%_E@M}eI z6*8qgJ~Oz8y9a_hxNAxTf5atbCft|n6G7Zv-#nJc*UED%5p3Y9J-#~F#1-&YxCpqE z)&T!CR{`I}6|}1r9x1m@0EWhb3wiqU;P2!PEDx)vtAh<(6-|5GACD@8f><6<&weg~ z<{($8=a^iFKH!o$^ydn_)SFSyA9X7jy27Q4in@8O=n=nCkua7YARfp?>QVkCh(9U! zR8-1U5EgS4O3S$d{v|FHe;`=F4=E>T1a2HxZRl#3KnRoa8iWZP(U9gt#Ifj6!-n6k z^Rh$ar2zFQHR4+e!%dOn+)sRuA1CC;A%652NbGKBJ!Msgu3UgTIDb$fAJIqCamI5a zlJX$elkywJ>6Ts^vA$X!PZj8)7G0a%5;LETnw>S~7QMk(wW27MQrKh9Bm&*B_xo-&h9n(s~){OF)HOSn? zJV@qC0p>xvb;(fe`OY`f@8poV=-k)9>DHK`+H;-%Odt4YhzUcr7dqcczk3pdJ28t; zg+0AM*Phoq-_+CZoEHx5gzB9p6R1+N15YrWky%p23X)^<7rpZhJ^l8%Cj$ktKmmZZ z>79G@bcX8kF}V8e!9 zVG2i?l)uHESm<>~qFoEO*ku=o?FnDPFCR0>F1v7&UD7}77v|a}rd@K6HKVMuCDfs< z{0hc4d00y%=qlWMdnD7I{WbosuA!ctwI-F)ZPI&4fm6uzqXc=7uIb#%6bA~ZR@%7@ z)P!S(E{zsIOO zjODyF=HJgabgOwFX3zYdFY4d9st;b_vWvKLk8pbYwDLOxdOXcT&=vH7{Wvt>P3)|{ z->3}-$B6wFDthV`nM@8#mPY*@GG4+7w|zTkpG!vv4fN=kq3CFVjv0!MJXl4CfV#Yx z3NL23yy$=z+xzgMFc#Wge}A;L&7&fcJX|+DY#xM;YLAYs1%-V``8enU(NIVICgGBv zexm>~BK{+E*pXd&XtTEBe5{hWBV4&H9NMF6S8NXZw@J{n_60hanMAb4zhClLYQrWI zo)T_5x{Btl0t;?#s70G1nx$_o0Ix906h1+m(gLsbt`LN_Yg0O+A_Bl813E%bgt*l} z-0wk0rPz~o2xi3JRw*J^e>0sPvkK#T`qSCPB92y|7_doYu3AD;+9@Y+At4cx!lV&M zL@2%Vj)=LfDy1LU6%M5r4_3_!ZPTtu(>Re^rnAI)PB#w?``gizDceD#o9*T{=XOR^ z{0ssORVn998H;L}b+d>Tg^a(uq5TWsbd-TwM%Y#Hucj`FHB^4?nFXTJT$NGBEri zkNXJsL_%Bc?62DqA~##Y=1rxEopqNO))mFr=j~yS(#-qJBn)dx@!^J25HLM`vzV%^ zo2Yy;7JCG>S~CJJR&z$Ngs}=#)g{AptsN_%ryZEHYH_FhELQsEg+F7;vyfC zH+LH-we>Sfl;LQaG1zPY1B5e{4HOK@ilnp^Z;9wl#*9oW5#dyUyseYU{cV$E$b_n& zsEh=R$K~yM{Ga{JX=Ro)SVkm0eu4~|=YWf+`ssEo=%n|561u2kyAT%N`>sn{(^+kk zW(zvo}>epIM}?ApTV+^x!5qLp@!GZGH;xt z=I*K(VS>cpDX)4VxfYbxw7InX3$DSm$_CQxl%Gz~we1Ai!e&R>83kn?yPBp|V6u~U zNQ}z5Zk7b`s#1~AZf#|`P!-=iwpT7CIa*A$NA_(l*{i-Y5cZZ-n$uYzo4Z}!-`NimrQ@{qyQK%r>*lsiS|AlcTVgK4O!Jtv*E99z z7o6^rMdMp<`vK8b zTu2Lal~mhxvFkTeKzc8tDmmM)-sx&Gh|mI^ov%nE3Zvo;(81?Zvw0N}*Eb@GH?*dM zbfZvgtPPvBrCY;=<$k6&{j|hp$|HCMz;^DzcWBzGs0s)DHMMWJl>LW-Ez%Mqc!D|) z@3-izQ}G7s7WTpURiGl|{|nBrd80JfMOs)lr4Qf)>3djGQ+puC6`6+BS5U9eh+`BH zD(BN~dpga*va8mha999$>F?XTBwRcD29eSL7HtwzTJ-n1Y`;Oz$T%+Q;FV~BXj&PYH3J0?qbq$d~csLsmTg#lzuEbG?7lQqZlXV3^g_|fvasS+)} zMG^9Ev^@Dqs@t&X*Bk!P^{d|b7I;h$^r~GKMnkNHlK_0)D%Ib#0`ZhVpRPviNDB^& zv;Dwk-TzllKAR+dZ5zU^X)d=+M&1_WbnzhFovWu%2lNC4^hen+&=Gs>sM;wa`9Mq9 zzYpGv%+5L$6CjJr^bLrO&$%5mIs0+u^c|w?N79E#_?(I}q;J)!m^}KhAU;R(?N6Z( z>*?}uUsXG7aXsp*N+XG#nz@#GWpm2f22q(jAxr+4H%L-{3}c>Pm3+sI_Ye` z^8;QH53uL-pl}l#l(Lzdoq@C-zd|gPG9RuHaW*SN)jqQYgQwP-lnkixT@R&}cy?RN z5Ubx$PzgIrG#YBuE>}(iLkdGzfeMl6;~Zvsj%1(TPpl$hzRlptghysTlhCpAl^Yug zWtLWpzfj}f*AzbM`=J*JeFLuABNjp4DM;Qf#Bue9UR?T?GYODh{gAa1fy*MefVTqL zb+>Cb$?gpHGHj3YMcOHCjHimcW?E&#+?nP%y<;T&W{ML$bOzl72+yH&4X?!g&tElFbo?OdBTs1FZ{?ii)=QrwE9}!9SiQn{@pEtf;j<~QAW_`2R zFrPJuuuk7NPWsk-i4`!zwu;HjjEJB09IGu+X$;qxT#Zmi-C5CER?!00nIZq|huio_ z@oX`^2ejs`07Pq#OLS39Y2NE9&DupAai#@z*VDgjD+xryWPgO4!U0)<>IWYt`i&wP z&s*IIYJocu=)rJm!k9IE2^kYOtZ^M@5;%R5= zmi@<4X`vK;FSDPHX^YDP`3swWEaRsN)vpN7!9r$^0>H{h1NE7YjOJxkO4bplC}Emb zobf-`(^It*02&B%j zr*yMx2G_j?=b7;TG8wAvDP;K!)|Ri}H)F}uN@HI()*9NTvZ1;;lyxLE`Lm@1_OTYy zVH6I3c{W?YzVy0mSZay)^sgJJcCb{y=T<8opgqad(zlsM6&D)J7|*hn8HDH7@zK0rz*AUaJ$D8se+=Uk22Z86cfvS?L%jsKA1 zGb_h5ZYqv+fm@BP-JjCqM~k?oB^V$cP~=lgP}^e!C3Z;4Vzb1*+a`||PO^olE~syW zm$ITQ=uHPMSIE1}W0)l>Pnz7|HH57p;xqiSI&nZVCxL@mwoI_&M@MLh_qk_93Z8O5 zv~DnAngdeVa*2L2#kUG`^K3VPAr}EVm%xvT|A{guj{pwqv(Gm8d_VHVw4ZI$?vnWI zDkQaWvq(uFqtGi)Fq)RL7@uWAN-^P6yC&KtI$;?txgComgsnWrkFG1S_JouTd_a1} zFpt557&E^KbV}w9##1ETB(6QdxtSvFxI-JV0x_x7Ik)$@h*t8KQpb|fWW+zfFIY{Z zu=4V>w`s1P#E*VLTYe!nqqn8;PjCxwCF~(H+^`iG3ZG?AD-a(r8#+8M%Oqt5_kkTF zde;~Gqc%q~pYQgJsPil@a{dqyK^G!Scvf^MGXO}$Agfb#gY>p!7(Ex73BJUvv)U$0 zFd{25qFv?=C$0Qb##w!%>|s{4kiX(xa~NvhA~&m$a6g(CU;amnA)IK`bF6b(lQEq041jYPpuxiB|;&-&^N|ND>gu=vRwCRdo6vJok&)N(L zx2kaJi+2vQuk;f=?J!>i73IK&nxvSth{Blqn6Sls$qUftqPR0km4M3bSt;xm#R3Eh z!5rFYrZF|zHpI3S=pwzOs zBy8@e+y)1)Xi@Pb*O8GBw{*Kzc9s`1_ag1oBm>Spp#CVx{NQ^0n5HEcz*8@DUJTw| zq~#uHyanAR6z>t9l;O<9P9{-bI!e7FjV;nfRmv#`T;fo&ceq+95&Fc4#&X9hge_`j zWGv2z8;4e1C*#ZcS$iX^hZD&C0Nk}mnTuI*0PK>FqYPm)ML*S#&$AP)z4FJP)Obm5 zP&%5Kz*aRiDCL8rB;x@RHG2DhJvHijjHgxJ)0cSKmEpm^KJS8Ukq0j`Uib08;%_gK zWUu#i?fZWDC(2UExQMkdKwPdkV$CUm7cn5p43iD-BF-`M1zEnC9yJ}_UBWvAdbc)| zq%!VVZK)n9D_nE9nZQj2*J`dou3@gDxf)y%;DlPI;(lzV_zBtTsx{q0FA;-_A1l#T zPUm;n8YJpicZYRFY1K{yQN=Y=i%YDl%PY4tNxEVOfrhI~0lMh65w!MoT1$Y}s14j@ z_;>W|p}mG(^evvo?ZBOI}ZKg1=bg;SYF-iLv^kP0GDi~1OCW&iA{$5kGP zSV+jA<{TZ`ik~3a`Gi=LN(`B+v(Fka5ree{2*ibEj?VmE3Cp4%T2o5JbxQC`bgqP< z)-B)yR%9M_hqb2fLKVQyx0K9&H2k8AWpk|7^d%4eb9wM>Qwugm;c|G_^ztkHf6u&w>lHBO!WxmYCD; z2|f%7{61Ed^FZIreD6?^&)j9-I3#9GHuN?ZkH|qh)nAKd(#H!!H%-@8oZtydtQ!Ac zU25_Kof@kRh2rF^OQsT&&yAOAgB$ga&0l~h#vIG?3(t*ord+K+NOLDO1&YbeVO!i} zBOH2eX^T;NK+-Uy{*0~-Wk?}UK>n$af5uu@ms(TGS^P40D8*}CJg{;{XqR?Ht6frR zqLSk3Nawm*K3&yT6Ufi{ie|L>sE^sF{?wzO<+u(~p% z+!qfnW~MW{C~MbL)0>$K_-UAvji{Mo8@`r&4Kdq5YITpZNa6PBp+xWvVSO^mD@W3W zU4fj%ud4PZR9ud@T2;IAh8q-d^{J0NY4EuCe_FTLCcS73gUTE#V?v4W zzz>Y3Sk{G6^C-x~vIcmHUDa5^Zvc>|Vqc5J*e>Ko?5h}Pv9G0E#lDtt75iH5Mpd|r zWq$o9*Sg+HldP*;>pDY8?GR;M??g)G}y~po={Y9 zG4>U=lHrKnKl)i^U%$*lWnZVgleMpnn}xf5OzgZ>S^GL(sDluxJI}&CNQpkASd%fa zb-@ZcGG@aaHG1!+p`$ZjC2N`^6Ml#$&gr_xlOy2CI*ULigSiT}AZ!eYnPdN5=rgy95tKw0>&a@dY(4cu8lDO^@POGu z6MYkZQX&X}x{|Q<D;GV-foad5G(ey9~GwXS5Xw$z=3L`n&GHEx#n_mMz6vE>{6iZT^w zkzmvv#q*eZ%tW&d`ze)Pqk>ZC6mZ0)=yTD3U(9|qIGrDuakS4xml$S#9=<0>D&Rq>sJTA3Q-7+%hIU1 zl?hCWe4U87SpsxMk!*J(HV0@ywFEzb{2E1^XTWx{f7|%>XrQe|#Q{Q7wXZ~LC9Umd z>z;KSZAHemuC3m}9A$MnT;bGzUN`@$5BOXCB@(?#d<$;IyN77YD?yLeT?@q4yiGILO%Cny8xjRHz4K}l20pYGYK<{RnP`x$oP+?hZaRv?Wm3T=I4 zQQ#mU`6^VUSYfIwmL<1g0Vy#!euc!kcSzVQzTY1X?b8y~5GIS1^#dYAJd)RN>xREW zf7KG5iu{6lS(=7K*^o!u*p;pbShfz}wq?Qv?lB38ch(Jri{D0plpR#(o?K5M4s2Lj z1pfNbax_tK^1zZ<CIK3HFlV9Y5Y*Te$=zLPMfnY9-T<)|zVsJHfrrFrdC9^-;@9 zs+JzrR}EC`i*HhP1$wy&TkBohLZ(hD_XeB!Tu*|?@SL_~S)&4ri!VX}Mma@3rJAC( zw-%$CTf@O``mIe8G9?5EG5QnoFB)0_0n*r*{eb$7ey#|L1KGALPi5CAm0gxq*(943 zu7wGTtyQTicEHIdIMh{iRaQwEd1k@kuV~F*LP_Tl|8YL$3VA~6qy5dUiCmLsBCmfQ zr5**V89%L}U)8X_wy8S65)Za2AxYCJ{ab=wh=U{|Cv|YD)h&4-M?y&@j+}4d$sy)= zfb6(vUcw9MDej1*E#xj{6-}lJqH`kO+NP3XwgQmsk^DQ35Dx9?7GjGZNYXg%k=2z9 zS0z`I=+n9{D|s-iWe>v$S7ac}6&X%Aa6TvQR4#skX{Ks9LFN!uQ=wv=a|1vMPt{J5 z91h`04&#xMnF0I&y=>@o(etAheW$x#gi3-;yT3(SztcHKVQT;^D?c(WZE|I&N5-Yo zFn#}DBmv}d$qISu)1HUgD^i)xH}Np7qLDFKN*jLVWG?m!B`Jiet0hNqtSmLK*Cw+L zOkxz_KBj6@8(yBi5uQPGOXeIlgNSSKJ~W1{Uy2SWyV|x)tdKypEt8>2{vt_+#j9x` zXOmgW*3oWs$I~0pNMUcM7`ahCcZKvb64T1{2gpuhn5ghiDUjD6$Fk-@;#@Rv{4^zP zMIvo2S~5%{r1Mv&MG{g2(i^Z!DjDK)z+20H4*iUgLwTG0AAyy9st?Hzv>cg$hJ0mT z?HV{U@RIXMp<@-sOoVQA%I$XN0@a*q5p3r|eskTxp-?{OZ1sXM(Yaa_BRfBaVsq+1 zU&EpR^^OMy0qR4p2#XVQi-e&SIv2quk2aS-Zr^w&?yf%TQPvvO!kzU)1#PmBmPw}e z2Vj*hVcH4&j{h10K;|LdQYK?L$XSZ=|1&$vR?o z{M#-24#s7kZ>KPW;HRKic07zzBcYfsmSdvKk{JxcEX=5pu!8#3NSN?O!qvg^fpoq} zwaHgS)YTl;F4_{r7q#G40rTvS&f_x&lwtGcu3e0EB#ChhY@bVFwB%!0l;ThiGJ5d^hN5VlKvvD#x1 zYkGNQy2cuPNGl!w4Pp^hJM9SrK#W_fl45N(y)n!>^F8Z3(}4#v7h=H!+2V57068aaxF-qjKd z=<^7<`egK}^@Z7kiBPpi{Cg#0sy$0?l6bc_=$&1W(DsNnd3(eZ;Mot8SN3Y%?}63r z+x--!>)o;x?0lU?AmGUlJF2aJR%V;Jxrp#D5tBP$o?&*e%}I8vEi&v&N|E3IFf+CF zGlMtcZHfc9!0;1xSu9h41_5!GCN2E#WF!nCQx`Vc& z2tiY8MzXG_$G5V#pfzB`w@#0Q-e-xCw`?CRGZWuaZ#ne0~?C*B7>5%14$BPpS zdKSgZX+d%!g)cO>#_vR|0WNGD3Asp1N(c+`VnW_`^T~5&^Trzo)ns@JncC*&^Z_?^ zen4A)r?2y^>eRa`hu3BLKX^6Id@nAeRVX=aTz$Hbp#!as6 z;^0gssMDpG6w)hu?2_As2hATU%X-;YWz480o#%K>ZTpeGUv3ARB^o%3`KMt`ctO%5 zcTkCC%Kq78d;LuDqtpVQZqc=Hz~4>H+Oy=Vg?6xTz^W6`nm}ili4i4CtCa?RLYQ`F z<2qVU6WUwfVqha?Ig6=3D}QXlC7>hna)vms4g7?Cw=L|sO&`+6;3AkV_P^BsscYT5 zRftLO<5upkuoepX15avHQ_5&WNv(|h^6_h zh8=#G4X?{Yt#Scwu?~GaV)2heJed_PlFd2`!jIT3h}$X*$LRpYLv81CI>tXWiPp;ovlx+Dv1!i9}V@ zy3;w>ra3_5FSl5MLY4SzZm}m8%i?4DK)E{uCA6AQbqsRDOZDf7MC_qBr%tfen%VnT z*K<%)!vh3EAq)`UWDvw<$V zA0|t#bG)a7N9Ey@ z=2m3>^*5p= zw6aBy?+etOWsYMDRe&v8bt7{6CXb5EMIZ9C{!qkxE*x4A9H*`P6)F-ZKINyL*+}km zY{xi%ET~u|KDyYGFv2}cXL~*G-CfkW{k>mG_8c8Wl&D+w-AaFsLgA}0J8fMTX8nEq z^gRq_ZHZ-xp^8bqcpKBgmo*o0WAu_30 zzK-&&T(N*kn&2OG4iC=mey~VaP?lINGOBd*v(5IXO>jzk#;-jS#TkEAH=oD)H5~(s zKRv}>FnY7TX)bkdkV&M9IY&bOifEVrOLh6yuogSWgSzvwJryC@gj8>P_@eU&8Db_f zpLnH633AxnqsQNwOAA^siES!j^iQgt(!dp?zz=iu_-222{Jc_a#V(hh)3cay$a|)f z*!`%AZjt>?&Mp~}Za6ar__WYPJ=1ct284mYb}3s#tw5HHQs6lW}sB5H}d zK|-oP?N#I--!vT~8?gc;=$>}jTW5%ob%r_AHc5t^?IGuc=G0M>;{7w2eF6nObdCR9 z_GQaUrS6KmDlZ&d5ljG;tv8#fqvQctRS`KpIhn#hiy*}8HDcAmrZR5CcM|(VT^ZJ5 zG8;@BMVpjB$_ykAscd%eG6X^|dSXgG08t_>c?DV>wiH5Emg@!)0i8zlZ6g>MVWcrx z#i-gTk?=W5tYw1?wnXS#x`G5vrseYLoKHyxqi3AuOkx+ZcdT-c>Xa$&bxd`#kns)T z();TNk#QyiDY=WEBo;DJ&4$8mo04NtT;~SYf_lcqt5&M&dzVM zW8-`3P^O)kKXCpGwVIWJWKSNEj38e)C(q(%ieF~UX(JHWd!_S(BKB=PdB)A#*`Q_E@|vz>s}CBcOIsI6&$g3XxZcr{h1%r)(sCp5=Jf@ zV*BFd$MsMfwhrI_BrnG@H;oK{<$Wj1>=dh6V4;BFrFF!M?MkSG0}dsNaE`_15S}#-FP&MUW5@Q zOV+NUE<0|>jv01cFtA)J1a>-X%`5IZfV9I=vxPdsl?U^2sEs6|ZtgA;Fzu&sX?|hH zQoSp3)xy?5*F|ypQ#Q!Wl=DizN9y~oF9`*LWGG0Qvn*oZ6$4X;iUx+WX;BmSJZcoLorge?#}Ab*=JKN~D{5|AgdbCL)bweRN6kYLHmdA)2L+F( zSsX4;W#V))GoA0Kh#36H>Z7|Lbm9~FdU3E5z4$+}3Afkx`W~jzT}zSy_<4a?3WSVu zlLJ|S%Z+d@1`>I4zgdwD6xg^%OJ zo8kg8Z;JgG7BrK&XjX32Af?iGdWXhy*+XEqi*QNGQr#CLiNjj*K9Sb-H4>sqO0A6I zR~G1auddw)`*$eb$tKBh?ez!6xHCNsk2_MoT88AvxVHMF91A-x%Y?Ai6k|fBX0z+j zI`KqM)bX%R5uGtRBr@oEt5UM9K?=wi;Utxs!gt6h3$j)YAu1k}M~5zSIJYRB@u{VI zk=s;pA3B{Gyl1B98aq{S*5qb3sP!4Gsfz_~H8xyGt=5e=Zs%asRAWfRmjg(1WZFg7 z_37Au(FW(2l+PRB9D@>l;xqBLjkpTUe41m42+uGvsvBc{jYPj8W_BN_(k_)1KmMxn zJLN1D*_Dyf5?_NMG5e8qutg=8JM6H{4Bn=UcCvyokLB#Ryw%pn7jV!Qx7P2t<$7Pr zz5ZC{$J)@ioC7A%!sDj+_tdFi_f>PlUOlG4-~ZVj1!paE;T}2Y7Ps6D=l3=6SR4A| zRa|1$5b~|0iVBKz{qb0?RFUGPWo_nP!@SQ&B9C=dxi<7?>r~N4ey1+h4t2S2kGlN$ zAQz_XcPfVu)zGa81MmjKO;Q`Py>!RP%#?6J&St34)fr6;Fv$qD;_t#3xWcL{ld}ql z_GM;swilyX;sI{RKr&96b!IkZW!wd?75tKv_qaaK#*io7t<4F`Bit9_R9G}^6dahLILmuVz=gJ$G3q4m>t9)`m zswGCicr7pG)FrQ^q#8|dUhlQ95UzxXc89gc;vzsz(*i^V>xRdB@Gw<8O0nHpL8(;{ zRuI(^1fJ27HzhTi1H;rtkST1#`V^*J5~@QjOTPf4YW#aAH_bjPP!oEo?g=lhtF0f( z8?_H*B1eW5v6GiQayyp3*|k=!gQfhu&Xr2Y>#nuE@lV5^R#a1)QY2(<`xEOv-+)Vo zRU_*VZw&K{Z|2J9y-BZg1WTS5z&J@iv0DFC5#J>1<9=4lL>A8Ov3@H{3-Pxqawi(t zm!o~pHn#0S>^x}0T(bdYot=si>s!UI_@3&b6l%$aQL!`)JklcFnJ%0eaqc7%Zdj9x zb^EFwbJg#VW;@dDhSPy$xswEcSpbV4FVU7uS~aUCuYFD;U|Y0JfdVW-^L(lO0HK<} z{XQ!%4v^sTJ>u!4`P&m%mps9|iu3vPzJ zY8`+oQ1V_*cPiX<>)9O5#hwm=tw(^t5dSCt-$ptL)60WwYRF_bGe)w85?4SF4i)>d z+r+fsJOtd_C}I)~$NlwpOL~#}X_z-KvB}i!KSw7|yI)$-Jf_;P!_e*0+yKUWx;>&H z|0KHS9}wJ&e(up-H|aDqUy`L+988y5MdD9-Nz@^+>v7NTaJOZgN9VEPARTSQ$N99x zgZwfVEi|mBf(`tXVfTl!ea>8!;#P(W5d{}NTan2CW<+7oB?0)zZWjEP4)U^Z$h#Xz z&L2r%j)PvI90>{v3OR385^_{_<=0EI5*>dwE76j*l9e#m3D$thT(q5#%-^#w(1vKP z>=ep&wYcjlee+iq1!Vm|t->CzF+XJEg=`vHxUm9KVob?)@t$R1i2@te6T%0iCB{Xr zGv(^0vSMbY^JIee#_+D=m^T8!DQwyHsht7vMA`dG*o5zH4seh2z(H}nllY1LTH@<0 zm3i*W1O@0$8eh;ktczniLOa4{kLxk%hm(WR7*@2NW6sGju5;-U<$y@OWBf#smMr6a z%zi4kkOx(%jdP$Y{BZSpUa$A*%y zySv8hCegyM?-#2911d5vJmKp4qX4m7PBFE|g4_=^K*@v5wCxH;B>~~G5&LUPin)5Icxx7tINFc=I%iT-VuVnY`OV+NE0s^2X^ERkMF!Q-qq`sSIy;peMCctO zexjeYd<~z_;hRutdV{9c1{w|jww^t`;~`uBCEzF%S~(upBpc}!H(ng`?_h8*_RdL& zgj(+`)9o2*AB1jp_QIIgm0DQtVhOX8+^RMjtHU_Vj?2_kHgN|F$`K|EI6fU>#>7KQ zj^iQ1%j)13;gf7+2y-;XiUqWaxtAQ8@d}}{#VqV>i-fjCI5b1I1I3jx`RIz|`ZH>; zSx51#QSWu+?ql5_J2+0Pis*zmL^Dx{8uNd%lA)C35mslNm*B1IU+|7IH8s*D1}pmP zlH(LcqZpW0JWkv;*|UUL`R8Tph}tWdwfAZdskimQx@3eHB#|G^80y`9ak$YlGb0em z_z42Q7xP0~zLbCEG@O+({GS-4C1n`~O1yd`LW&`9w^MM4E8Q|McYMW;J4?fMHK9$m zZVL$SWsdcfv>B%J{S88xQbKvgUNJ}_TZl@;SCwIevI_V?0Txu=rr+M$2#yjylLa^! zB!&9cr>vD!R|Hm$15vekyMbY2Xm5H0yv?v%q$6?G3+L8h(QrOlg-YQ}tqsch0fofj8 z57UOF8r^gMI^Md)8H8t}jbZEl=_(3S%y7e{5m9ZBk&Q4reql;{S)O z2W2msIwmEh$jIB8hB5=j$WV^sw`e zF*!F#Z(^-`a!34~VoKC7PfTzI3^A>0Kc39e)<|Wy&Trv?v36@BAS0jeaAOJ8!LCA@ zsd7mrmOP)+ONo~J{KI~}%&K1?g53r6XUSk{u-m7tdV%zV7srGR+06uc=-^V>OmI-U zVykQ>m{#h%j5o{p=Bh&q#c=H->`{iI4m`@LpidH6YS|D>25N~few zRQQZbtx%=#7w-Q!rBagsP^cu8>O$&(Hwmp~T{^8<&JPf`j+7|2(kRm>zMbqM$jQMx;(bSJZfL(CdT%hAb}Ay3 zFX$cbvRb00odVte7v&{7Kl+ylO9ELCX@HYb^Vy6p*}lm=ye4qkr^TmzT5{T_rKf#b zmiN?=jsBVU+TRgghT{)AN^=8v;|p09`BG&b{F@+T!sG^3n& zkn7vEGA8I;-E~c2tr?xQai*QAFH;mpJWSSHnlJxo(}H#MhSZ0PE6va*LllM zu#@820pNLaBl(pVmB`M!f4h;%)Cdsd{7*=}p{Jkcp7xNEOT4ew4a;t2Oy~Jv6Y#ny^3}r{^xz zEd^{grg*OQG#S#NFhR@{fJ&Q1t zYwMZe(e#IOMs`9$$NF$G-Fe4_(lhT7{v|0}g~$w5t5|%)wpH|og)V6c-WP(CaDjN% zATq^Y=5@MD=IGxO2VK#~R-U>$B(9yjhG%kCq+#}l+Ggs>$ro`G^{qrXb^wy@|G*arNd8`b_W3&SPbzfbG>@+&^j!jhS2YHr06Dik7mI-`s|vBBePY zExW9Th=Z2s50m7eqt_Bhb1R|h+pT3PYDciwp59~LBNMFrwSbH2zi2H}X{~VdB1&^U zfZEee!*3Eg(vOz z<@@ep1yKBmr6Vq^>Az58Mfp&~UpYfTgi~Ao2o`dp9oPZ`vaDRoBXz8T#0OnghUstB z#nl4GCk6PVjyg@jz%LlLflrdlW(-(6KxH4`Zt&mS--5G494n6 zl6$)AEH?$BwGbrLI!6nvkj-y06PL_NNqb4js&?+En^EqHwg7Y7mLwgViyWw}D)HM5 z4A;esR95p`0y3<9sQql#nmKZZyTpa)!cs%Ye+0)hYg&d{%VcdJW~=2?Ham^qX>!aZ%_+2j{Yk&vh=es6Xgm5gU(kLmFeHDGBREvL}XEBq=*3rxk)(olB z*yX%RWv)DW%)G>9X4^91jr=LLdWXgLveitpey=6_(+iT4CkH~?dOw%zY3ZcAo;fuo zQWm#>k!7c1n%$=#-PE330;YGSmIr+)y`d^TL1QH6kb@A$irL-tq-!hYLJ)da?ePyu zlXxvlaX1UolH6(i=Q52k*UYDpa@4<2BVmW-BOphj@5?XaheTzrlolTI*H^lD2AquN z6S4zi%>sqTZIuh?KN*k%j>$gr8V=&?K`dLS!;%Q`6-VS**@cfP4!uGt=|CqT8X<_x z7Fk*=UdpBpZ@!{*UfGkrAF z%yUe3oo!4cvgOHThLA8>epNfw5h)R~Q<@X5+!d=$MG=J+P2jc5o)dxQw)saYTFPcK zBtLB5EjfZ%ss;bbTB;xXhA}N7#zyL`+S&CxcRm2pu1ih@C$sDJ0SG>Fb(zNJ4wK@Nrt*u0AlM&P#cdcgW#AN%T7meBu zQV$B9iy^^oE%zkw`<@WJ@oB5!o<;Y`IE1%2Zk< z&ZK;qBsT*q=q(_Cvc{1)PbKAS=L=z4LKtVq(#1;6oE6;RH}+AQ-qX~iuq53<2Ku4o znopID57Q5+=H+h@P9E7E)wV^Y;`V4dQ=!W)42~k7;`VD!$FAL=bj*AJ z0?bxtof3weaU5bjB*sy;GoDR{^VKwG2@pAXY>QC6*mk(~ZC>;hWM``<9C$ec-^VSw z^w$hq>X7VlZauDE$Vuyc^q7;@m0HD*_0$cr!#nb|^h+pg*)qs$$v zvJNQ+DgIwMq#eITH!UR56Y>y#r91e48ZJ7As9Ftu_V6@rLFSc*dAJVnRr!BcUu87D zU5wI1&2||D|3+u=!F$mnPIy!KA#51qJfU|}hWXaUYF@vuUBuY_{QJf)*lc!DN{Qa6 zus_{#^nL9cY!KV-ZW#C^;!u^6f)wEYYtrv)V|Ey|JIRDB)0@g%KPbKQ?~O#Qdm0u@-Npx`zW=@+Gd4xxTf)_b~IX$GDA{ic0(=&c{seDM{}u(c2oO zCDiMirTL0B3W zQCqm+L&4+7L5h9+HEq3Gqa_?<4xmn5&J$NG9Gc!&?BBsxyZCg&JX5W`!1qE0;^DJoGXTwa$(9ALx7HpMo4sCuL}q*x!!sus;>6-8RK4 zvDgNsr;njx9k*0)#Dsh`BE@8QDSL>EMpBr4GNsvbZP_VtOA&L@uHE!Zx^>kCCXBu* zcFZqi>*Gkuo3f2I329A@E}f0iuyB(p9o3}XaN|BJ8QPcJYR1l~#AAfX(utCMu+6Xr z;viwgun=NMIk}Vdu&I1hgp7Mm)11<7PAx?ssspX_R>|yFdt47_kB8Vk^VI^54l!Fe z?j~$@R3585n%*}A$HxA3&sPvdd-{oa%;PxPe?4_+%cYCtK|$T;HDm&0VItX_p)DI2vJ4(lnncpBmUGBd*(3zX|iqg@qBbe(rtC3N3sokz&4%S{iQzN zl1<{w^JD2x#KI_Q5<+7=m{nT#rwB|w7uRcwzPPK6+0O6gFj8ni=J)Idf(H`mR z_yEraPYE|_QctCrOoOcnF+2@7O?3L*{d|od_^9Q!^Oe!8+-20h%1J8cVKi?!_u)YO zHzb~>jAi{)A}SShpL{YyjYDT{zp^D&T)DGr1-a>B!@7Rc*JyP;m^Yx%9{ov)OS8v0 zhHhe@VwG|!if>d4@Ed(NBn%v5622x9Vc21`JB*29ctwMmH0zB=i{Z=SnS9-bQw1Ky zE2yy=49P{d?tS<{L0r;^zxL&5`t<^=sPQCx@|E(xYTvY4KAee88U9^Hy8D98Jrn(b zVIv)fs}ua^(zv#P6(bO@RwuXesEsL%)(Rj<7le4M|iFm?+@|H01ge4PJKICJNl z^nS>f4~sFK#_MbTZy|1dr5rn)u=$NK{}*Z7e598noo)z(?Qi$!Pdq@Q(Yt7EC&||A z9w{T+^@q{Q9W{2$_H~_`^}ji$aA*CsW>exU8L?7)!YEyL@kDENgSUsX?#s9S&E3Cw z+a*?$Y}FB{BfHI}21)>3zf<>j$wzbjhsR%Ex_G5%wmw_`y8aDJIQG@-_>3yn^<%}) zlj2L`V%8G}X@X(jRn4in#1Er#S{Saqb=U9I^I!W&*_BowQmy`40PO=Wqrr+xB|uDO z$ry6oM2B~9TlK0p50(9>Tj{j5dc)$PB46DIJ^oZONWYfc#wnjqCExfBKW`n&IRgIB zD@%7U=NMz8_YP>>>pS5mQ!W;)F#ONqq3Pq3Ldc!Ba@v5utBEwPzpyr!>mSrVa6OY@ z32s&JHBycu+S|W|O=;6FVA8|4YfaXD9}iz&!1IEb&Axjb4V34v=sjN>OEXrx&FBan zTlxoXuM9YHN?f*oPRR%EGu&4DX2^bFj;mr4tmMM5?iSfrE>q%V2q)}Lz7;=eYSVn1 zHod37)!W*@P<><1(w?R0QvXY<26Y!p7s+5@0v3NlEsoTGzQ(dh81y|U z#rR%Uw3gQH>2HK~VYph2wpJ;u?qX!$P*^u{%31<3zNokIIye4`8WW_u+zyzY{irR- zQDKC(fe2?vQK9Z)X+hvpGVwz}^t>Rdme$0q9|<+tMkS~nLCUpDf8yV^uEs7oE89Y^ zA+gX7xX==9YXK2l;4apZtDnY5{SRH2??Uw5@1NVxLegwFNXUC@w3Z`58V-VwZ^2<; zt!5D>>8zCu+1mQ%b=*ouNdvd&afcKfYuHb$8;&+?-Z5*>*op4ojCDD8n8jA8G`m;*`I%>=#Sv&hARxu@? z&Q^AIl0WbS3G2*|K3KXh{!T-*u~kN>Xk&|9LPzSisB+QxX3k35f;s-Dmi#n|LwhGc z)j0n_)pX3n2qBJc^rM;VbrwYw{VrEZ9$F(EqOJTZLn*p;%6^z5yI{a=2l@#sr1cwQ zWU1Unc#<VxNcoPo2U!PKZ zf!CvR%o!-o!at;$R#ajbEqrN8P47-_wlnSlN&R*8sgJ#Gd|R>7x=Y4QvC^Xrb4Qd@ zn(ezpUX7x4m&$YZ3!d`6+OQi_q^Y|Wy)m0=_ZFf=IDEDUeayOS*9QZ9n|kPmjhJ2% z!+ZGm$p-G9k+~Pv?P=-quzht;47bKEyIb$re}(-(=fl)lQ;W*5N3MqNgIBiCTQ$*I zaktPC=A#MB${DDP?#bqA^~^FpG~)YDF?Luc z@i9_zY|7{w|Ir#d5SQi8brh?ikpJ&u(B}7!mz-zVY}EEM;$3jzoj^_Pgu4y4BS&jj z+d?U#{xZ)@0~Y(Lu>_+y+{pcTY?QynniN1G*8dG>Zd}Tv1-rp&vl5b|Y4T;$SV;)$etB);zXiaEI{`tKSDd%H z87Py15NRb3MDZ`7SS6n~=BR7g@8gQDFa|bZ;G_xm$PF>GP1?8+|IqNa$u~e}OQHD& ztf5`H6_;ueivdw&B3e6UptMb7!l+$6L>Uk5u@`w>+)HntuC-Qcs%6se6nnAHOEWNt zZins{`2MIQLkn@!g#d$&9L2e#nW=a7L*19Dnz905E>paqn=9zP^SZHLqxh%Wu$LCQ zah-0vq|m6`s^U7oASxt=vDfwO{VtD~x%sMJFY7prnR^$wjsM_*zVS8weR2`^&m80* zF>_*noU;Fiz4w8SvbysBGa*3G;4^4w(W0j9*d^9(lNPsRh3z~zqcb?sX#E2%ZL^JK zv2|OvO)RyFNhblG4i8Bei?rIxR$Fbc#ceGj{!2gzVAX_F3$$v0S~DPue<}eHzVFYy z&rA};y6x|~uix*tTV5|R&%MvR_qq4nbI&>V+;h)C&o*eiWEO9I3n3~C2$33bsO$uTB>oJ#jCh6Z8 zSw4xXG|KL7@$tv2Gf6MblrD-a<4w|Ukx@p{^ZQ{U^bwt0qWtlu4&?^ZhwoJX!D7Iu zE}D%Htzn?e&@`eb(}S>X#-dG+?-!_S`GKU@VxAa<#yF@|-t;pO48T}h4a~q0e#&`i z%Ky-|lH>XC*_ZSxZr%?y6G_~F2Q1b9sezM%RgJCr8GZ#CZz!Sk=*UWLIC@G?0EEGMDzW1pktDl4~i!D)8o2?+)jwJ&>5A9xAi_E8qV)%;_wXu7LR-_300r`lT}ysP$F zC-I|U_L2)^Z;jgYZToEcjvAX@Q2+|?er2sqr^7bAV2({^%51u|(WaMF*z`?pHhpu{ zrf*$t)3?>w^c{EG^om-WUfFKb={YvNpv$H+jW*rdYtu{GZ2G2sHhuGQo4&PRik+vs zZTgNd>1>@nI*MuhW>Fa=wCgHA1^)f*?-Q)>&<%rwKCAG3GNJZz6TChAwEo>|>^VfQJkkKYuMTwi*gN$X%ZN{x#LB?{?E4AMnWZc8&PO8^pqsp-SyB7j0-sk^Pn%{tb z{|O8`Hvg^wjN;!LX+PlKsyCE>n~!IftcEV+znbIU*mxbAf48eNat}Xw{(V^ydGK#| z!65$KZ$@KrS=;r$l7Ba{y55$5o7HT$7Wg)ScEO8kEfW_B6Y>R2{5CCfSeP^B^Wx(x zw8-JnWjv?vHqUYK@f@#@@|@%K;^R49U(0ij*Ncw_y#8m60GwpN?pw4rNCq6=Uv85* zrmuA|h&5}nh7#`rD~|Mj%ybzN(N2b_^if4EOOC?8b1&uMWxNGLRjyUT&|%5N%nvMC zs02&y6GkzxFuB0#)_pd8TbWJYQE-lVzoNpXSB7mm9kuBNWj39uvFX+dn_g0D(>FzJ z`sO({eQS+P-_~f;chuVSiZ+{GImf2c%WZl=qfKY-w&~V3(pd$K7TrB2e-&^8kLe{GJ`+Kf!VUl&E@*o*=G+GsOw4qG;MOQg+a+*W2Y zZjUUt87nGm#$A!SZN>n9ZMPW%{I$zw4Di=pn=!y&_mPo()G$i`lH-$1UY<{CC0jn( zo~NPkNo5~dQhWx0F?{mpL-=Gr$Q|&>0vZeWq@|RWwuo5fX-g(!N@Z>qvco5Z?C?p0 z?0G(EP(9Bl3xsH-ET0SqDa$9zf|TWx6+z1K$!L(We6l7;<@sc7kdfz;bApUKpKJ^= z@_e$5jO^29_|4!aX#7@wSI*9!{pt@p-ihBevPaGBSL^@tui$qtiGF7?{rR~v{4UBo z{pI^r?iCq+SHNm9TX)0n`VIG!Hh|Y=+bA|+_NzwhF#Jv`fq>sN3=`cv)_ye#u*C0* zX+Pk1c~wGwziK`XzdJ>J2)>%*cc^RLhTo|){EnYIzdO}HCcPR$Gnn5E+OO(ZJdcy< zNB)xis>H^(=XdQaS!lfY0jzGhWp(XP{6Va4MHhwOZQ^t3Uh^C;6F1sto~y;@mJ~3p z&X~)hJl_^J&z~2cTTy17|FxFqbcK12i_a0&QRV$c08Mg9jY%5s0wiy)HOcQUw{LHo zW0F6*+a^~un&i*gZ8F_vk}X{}nOSad~x!WYavyWtMk1ExnC~K5FSl&=V+zx>d zC?=VAqOGj_T8R6rICOEV1ZZ>;;j*Y0bVGnPbc8#hK8ZN|+tHUpk*Gj6NRePy}L zSTVey3uAdN7`*hrp;y$f52ueS#C3KjP%-!oA0(6w?y`lksWDxb|dg&5^{W- z(dPNKD3aydU98Qc_P68U2bOPJqg&Gs``er{PYaS&5%6tG@q<0VV4YqjV@hRi*205t zYvIAS&BDv`ZL{q1eA_I#Jl{4;j+EuwX2FrNeA_HHQkHKQ2-!(lz8wxydA?m1WaRmF zMUb&kMD!``yV>}wc`pJuSFk?BR^iY-9fGs@5@XrGX6Y!QvMHh7OOjs z&D9~ThHq;bm>6bdOlcz1BxR|4pW!&(j+DPZZ0ktPI2kWA(l3rFo5wx?Dx~U~-+f5z z&Fkh2w>4($xWsBD^GkDbQqI!}2`^*6 zwYVRo=5T1Z&VsQl<%K@$b(o5sDesTAZd$_g4!T*FlJ(#yWD+^z(T4zyt^a~Luq zcgVCZk@==M8t~WX1UupXLMivYsDNg4^eqJfxo3~&Gv8b`#iW*urYg%u~cZXWb-MUBr>5IC*4SaMtnOMEAUf(rb+9a`-FDX>1A|i&^Wcy z2gZ579jDppnZb3Y-)5XCZ_A$FMSfARP}W%rRo*&vX-bdljp@}XkFEH<1j4c-4fB!W75C*c78bT zJW(gr6L3SN2s}C#;@DOt5*$uUAgXXHL4Yt#+DI1o4MyslSQRF`r!m-3aG4scXNnTT z7MW_g=$MI4&wMwc3S60N|KP=u)q*D%D7nGW{7JRV*Jh^bb{X?XV{hUtzC-1)bD}|F zKNEIJL4nGQy^FDl$3(4@1LD`5=EGD}rsIN3^L7mfkZDHfei;YODZf5)B}2UF zP(ZI@ReNGypL5|l+`pca?!#&774+&LqF=QinLn#7Sy!2;Q*^hYBq!~hS8o{TmRrvB zUO``e)3DW5%o#csuj*@9!Etrjz+Bavxw^NAOH35$VBqTsgY>Ag=&NSQ*jY2@+@M5) zpdb@C^QSb<8)zbA4x31RD`n75u-S2y{ez%Vbx&Ex&sr}>kArm_T4!3dAjS8VeL%Ji*i z{&n9vR2_OP723~%VA6ZddnV=emUzm`-R_DlE`tEU>?*tE=d#AoHk@-SR%Kr}?JO`!& zv!>vJdhv4J!^>eQ&cj`+^^28ed6#TXF@|0SEYr+S^NEJ>)?E-`cI+@PVeCK6^gaal5dy; z@?j_(s&!H_{OfygpU;W96MLEe{f*xkEi3VkgcIvZe}kAo&7yaBu?<9#A`yYz9ElOq zCCH^1ODHd?>rR@$eQs=rO<4LpG?+Ma4m)f?3)*e8V=LF3vK9{{8d_JH<`e6zeg-GkmG{$=GToXA+FN7VL&_4otiMY+F8CedoQ?5k_=CFv&u|^clOri!xrJ*u zmlhw+9<(SN)8ufV1 zU|ME6SF5YpxqK$)(xNj~EP1BDUQf*1gCDhi=HeAt&fNq1_PDn`migu!Wx&VVsV*Ch zNxYSnyRp|WG;;^o?X3EiJfO$CyG$52+~X&_H?6H9^}Nl2{WL4O##!~ih`E&Y*69{F zmhk^UeJIw|gm&61T3-z}{lJ5rx=<3yx*&Y3b$3NOT0Mqj+~jfSGBxiRq*ag$rg~L0s9GE%U<|lz9!lPsS;`RhySsIJH-#G4~mO- zmV3V*6LqBvC8V_T4AY5y-qeY*P>ZW&8jX$DRAm=(y$pAZkfD*)p)T3mP7+C~4y{dw zHkx(t5-r@vzCZVk@&j(qa}Z${(o=VkdnAfuGr5HV7^)SW2;CwiW`9{M)Q2suvl6Hm zVQnfy_k#`3NP@}Fh^`kzomHLq8fbkl49;1#RFi6E0}4D_Q_}jcpmJ{gLz}Obp;<@o zs59(M1mQ;rLmvO!&^hykI*z}Vj)<|>gtCW>7#Y=V^_hYe!pP{=9ILqxik}KvweJ0T z1mFOyDZANx41MN-9oK#CKD2kNiI3^8foZJ#KwP8WCC>eEswqm$vp~SyEwLal_{2Sy zQ-H(Tz#thB>s+sBT#~4a@;kaC`?~o|)J#bN0-Yh+k-bd1{ma3PX-L%EA<~Dr*D+Y% z-1NdSdS;AlF_6yubB$I_uR5Da&Xi%HJWSje=_99dOSONWHUj%u+BUWxE?_pziw1Ph zSrsqf%7t@pNsK*Axty%%LWgc^$Zint5`NKlXh+ux{E`KIlP?=lP}MN=1`{_DmH`=Qx9C>Vlha3#?*Src<4d-PJmp9<5t#e50d-DYx9b^VFDwTb;(lYSAy0Kxt9u!%m5 zrL%5gj8ayur3%>J0Z4A76B=h4o32Rja&9`mmph5wI^EWYPLZqLq`*G;Z} zwavsS$e_&YY~~3zlgp{6pX;Yi4253Boyz&!!D^i9Zui!ucM%qKROPnc7;l5=bjORu=|4J7 z%N`b@q2A_>g27hnJUM$B%eze{*A)Wl^h8sq)G&#vPN!ulm1N{Rn@uPlvAXa9Pi&Ul z%zIP04~r=8y~35;lz(0*R(?>P8TOz=#W*F~XlRlUb^s0PA2S49U#d;i?M`$&$8D%c zs0~*mm0S8Azt~8s3HUHwND*rEc?6|B-^E@v-9H?J0)++;s-BJ;`(hy!;ZE6I{XU0K zmP;foLRBO~Pk>K{yR%>t$nuzal%i4%i^TTNA|^wvNrj$aKWY3S;7}t7%Q`3q+c*=D z&~qL>*~GgdKG)YLa>Ky*NH}IK?|_1V^t_1F^iifaS2MKHR_XM%cJvjed-28HO1E5< z?Im38{%2xXUG?;N+dy5iwCB$fgc+|LZn~FE%evz9^M~QZuh3>0OSq@(I_w zpkGDHLB2;x97=+CEguvSZ-U2~$z`Awsj9vB( z(!Pyv>I*v@^VMCBJ^@PGmb)pv=k|eVQFwQmuU9BOLruV=gLQ6}zUW~uZKpEtHOoDL zfk2UKSb6?b(YD$1^o)xthVOndq2vfL#m~MNeD|@;IPxOh*#82Kj(N^d>BG46WNx% z-WU6w?{rYyO+SY}g6$L{q7FO!oenGBl#4kDG@o|dXbJi?b~B3xdRxyiDj z%DRvK>fP`ZZnNe;3O(Hm8F%+T4U!XHO@E%J53x|U`7n+mLVflL&-yLxu9Mj8IoU2l zj0RDUf8ekoM=cEOI9SMGWVH{CwG@K^hX`0OEP#{2%nSUh&t`YCJ4Ywtnen+n*r07J z*#V3*bi(z7avvT-DBR4%0NgmyXD~f4x&es*+f1!cM^(4Ck!S@%o!kn9AF$BT8o6k? zT<#7@sg>j&x-liTL$Mf8UG=8ZG7V5O*&@j24%jmcEZ4s$GY1DQkrm}&;dZ=On1hGW zl63sB$iT(OegE&lA-!W5YQAtfi${WK`+yBn0(mz58fgGEqC?Qxg>RQ(04c;f!AP(& zaJmSPyai5Y4#4R>9DWP{XdEetTS#aXsmzCVZW@KA;fzoH3RdNx^-aUc*cBAI$Y2S- zsHKQSD*>#AEzG=$IsRg5gD+Ptn2s`F^sJMOieva^U;WZ#&t!3v(3?s$-zOX3VSFi( zSs+COp@dMCAE}vuR@Lq9pYo=t$NXnl-txJCQ0FYjlE7n==me40#}>5jE_7CH@w%Or zL>Anb-d@nLlh6s@ENIlOg`2f2x%znEbcJM0t##RaN9iv^FlqvHT-wWb5|#NjN~ zl_Kq*x{-dnXvXH>u+L4mzbjt85i#oYdFN_#y?8Mtr6Q~`0vW>B#R)KaKthoA(~^;t z!fc--`U%fC4o|b-@ptzh5Yt*HdDdOSpMv_)uAji+0L>Eha;N!*Tyn~SqymjGe3*LZ zWffcAY#GhgxvQst|5lv2a;f_<_KV-pDy08%NMq5N2-zJ6i?ScH^jlc}aU4|KU@(4! zEz-3cgwGyFiM%`)_iM_;q!&L!cT8W{G1F?|bnC!hBUi7CQ~z#mqX+aoS;wZFSleuA zbp_dWE=uRtH~hienhnaSA4jzM?xtDO7X_YV^<~pARqc^_dBKMF`2WmZuT`MS=W2)N zL+LD|z>t0K+XH{M4#ok#kFVtKx~tjVvcF|IvvXnZqBD=&*9+hf`OLTsoblJpIQDOM zR(8QHx#FrZ^kq*`4gBq)BkIT!;$#y(!ynw_f-gSNwR`sPgQUN`XE))~_7ip;2hofQ zHQ9NY(r=>x=-J81N>8$5H)@Y9*`;El-hOiLFWGZOqJx>`y^V%%W zCK7}>n@MCow6p`-oVne68if^6!-!qZyv&^VZWDrVDs^4|eD>3qa`Vs}ebx0R>pG>L zVmrO?7PBRXicdBA{Cf5%T8cPk>e$Jy`qD_vp405U+B-7}L$iGR+TY zug#%Ey8rmEZOyTf`p4OKe;r>k_fGt}TnnRf*Fg$hh`QxZab~eJS+^nS&un3AtjVNb zKb)Qpoq?pk34=pYo^A;wNluI;Q1*Q|HiAvri%#>8 zD4xf0`hcQ5Q;3t&)6Y19T30HtOsu8A@U!hsb1kT;*I(bkl}_H7LMnh>P%LkI!&>9B z#<)?vm40VNYNDlv$xSqRVCmkL$vsKRZ;Np4;jb_;e{`dt`IqV#l`Kap=cWx`56IsL;!u5(O zaZm)ELRISAa7(TeU~=|ahzy>Rr?ANV>X5g)s>AU=O`cy}Sk-a;Sby3ueopYG74b9D zpEjHy>mD{qq4dY`Fks?H8)_=QIRtQ-_f-RV3H$fGmp`uAp##!#b^=JY+ccisVWCuQ zhHmy7m1DaBU{6Eu(3vu#|G%)(wLdqX&TVS9HU4*MY5j)H=vUBD*`Hs zOW~ks-+iAN4nMNq9<-G?49v6I#-c--E~dq~H7m4Z*GT+QqBe1>aB<-*{tUx*J)Agf z2xUW}#dVvrg$5KO#j#p{qR;+Pbju%p9-rm9=t=xkZsGbeVp|!#IgT`{ya}~{qwgbh zqwldO1&<<7+0TnAAIm>N`h~gjCzi;3#JUtqgt&_OBn}dwpHL;Xrt!?D$3ZQs{ng9) zM%>$I9PP)ewq5_OxbNb0tQ~dN~4;$Gz%sXs@@j4A&f)uVJkg3<+n~CQ+|PNzv(QV_MDRAW8TG4G34s1UvscW zU%Wl?bLf9D@HlFNJHQxv-S$4hVy&BZ5=urD;ZxRoB1PifWnmDk3yu@_#$-;k9UDKi zW3G2`nQ>6%Hui@a<})<*w3$*xvvK{Yg|-e37|meP>k7Gp>csY_bHT`HV6ytzG94sf zSUS6$tghty0nH!W)o{?&{Ck(pqM+2BjW@TutD$1>w^#?oVxjdM?*za#{U`R@9=xpT z=pric%CI3$Tn#*x+V(P~?^2&}y{L%A2RmL=-(hc)RT_e&;<5_lBL#gg;B5fxYdHZn z0rQbB_r--g<5e?ruV$1(9ZqSC_QQRs0A6P$DcZZT^7Zt?Dl!ZYxpaA!Tp!{gal@<5 zm=^hI5hrmu*OB}%y_XWmZTfL#%xV1+U61R1+Jr!Amg`g0jk`uBGG`BeXq0SyOgMNv@#W)kpX?DU zbs)sK_jnKkUVD>JxBJj!VBq@y_6TnLa67v>UQU5(JjM_P!0q{?%M~?79P?h;k7_>g zRMT!Hn-1=$mecwaLkR$2Vd69&FzdNhvX?oyQ6vlI{^8{&19y`;%7sDyHn#A($VEc? zsjMkvg%}LCmQ{YW0F5rWfD7ywp_`7-Pmz=wFfqi8$8atY+MM-h&+=FNP`Xu{@G`hb z%P_rra{Yy&raoD$4rIq6KB_uV7uz#WQhS_h~Mx$02-5#bq3sW=c;IN+P<=e1M7C zeX=JPZ{H5IUIaPdsNAb$^|%D;AhZNdZaa*AY*;Ka{&=2@*39ZKb|4JW&`C5D3vEBD zp-0tFA5f2%_YP?%-;6wM!@E#TZ%<@SeeC{GkRtlBBmQ1r2HF-{IBNDtLrx75vDZ}dKqn9EAd3u$j4Vf{Ye9> zWvVl#xlrpxGDre{D};Yp7ji>{UwpLT;p{4S#Q?urBMi*`6P>j456_9E>f|1*mP%FY zoR+n8Er!TDo4l*DbE%zP%ktU6>Syz96!qhew`zJo!7)?j?9Mf#3M65doIGT)7+@+i zW32oYRQ)Uv+W=}M+koq6O3-Zd>_Hznq;mEL)YCX*`O_@ltU;n-clHm1_!ERE0Xzz_ zzcxCcq4zoL`C2UV1!Q7-sDn2#W1#bC4(uiV^iefEm!KleJIG1aeN(XrL=S#7iW9EV z5sL4fVKbU5o1&dw>LfawBaQs(AHwQ@zFh?y$wW>oaV4y|g|m>Q(r21R?y(=lY|6P8 z7io*k#-My-wYM&F&6O$aTsn4*;Gk;+)UjTtYU*Ahvvm3Q3ks(BCU0)i{d_DrVoL7O~zKg_}*iQk_N^ZqFaWv*M|Aul#-otF6qwnL15R1D#uG6~igQ>bL=;y1pH0+G| z|E_k-26qiL;3h58N{tbE>Wi$YxZfPnZ{?B7y=HfgzGI!>Fezz&#}Pk3>9X`;I`=TQ zxCc51s(yF>Hg&Bmfmhab36!bLFXa1${JEQcb$OfpB)#fS)ou0GrK+|z{2}IROG~eQ z=PcGZ#P1$KU}u38-={Zzo9R@$>GwbKQI~BJJ89)Qi~fVDS0IJ&^6R~^|96n#nUI;q z%0~&%bkG*tKHRk2yoFyVR(ZGaLUvIJxzMEb|3YBKV(OEO z!F@<|#uto&_`U z?qcGB8gNv$tLdN8bkD(9Xf3K!pvQ<8za-GH)E;Hz2I|^>F!1r``bDL#ciA}U)jnc? z2!OMEz?4#7qPf0ErAl+6ueA89pflg6tU;x6{O&UoFTs8Er61A>CL(Mn!tFUgNGR8~ zpz04%Oaf5Lw=qXB-$FXUHU^Cw-Lh7^J1KL&8JC=?$M{epGcj_mUrI28eaym!fhj=8 ztT|XtjX?`;2jYi1+q{(r+!=2(Gw^t7lHi+WR66-DUv6dY%r z8n+k<`U%*rwG{I?-A+WVMOPm`i#{%vf4e4vx{D^%m(V}O zvu>$maiN$p(@n{;WO{v+4b&fuB@ebkIQ}9QtPUOEk-hW*KKuQjNwH=5V4|*3+*fQj zk#3GOQX+&dN_QQ zi;!V*`%!FGAKluWU`Q$YfC<+CoA9@puEY?c>gqA0_x=RMk(0a^;o(>NbC0Mst~{vX zZn9=-FEb8=E2hlj_i1`@mQ2<*v)QCMya(92ge6K4u^UX)>tfAq$-+ZyaOb|Zh z?a^UWLlg4}2!G`ft%uKoZQcFZPw@jXHS0ArNMaBh>+XIwCkIZi+*rQx46{yn$UaKr zfm{u7qZIn*n75e)YPn9sg9a zE!tN8E*mywqHN0gn+}`zi$>Cn_i{i3-V6U{3=1ECoEelG#ap9(5yDjx2gRb9p1gh8 z<4qTshwg(cY(tivMS>0R4hKzslwPRGZMi1n`e4^vngc@UYr3;ZUbg{&DYpBM0~<@q zD>r33%q;LdHkEwPFl1*@97yxQ(wq?SJs7{fc%#54+U9FKjanTNN){{lNz8poU2 zZtC~y8E$0;Cmiad01y#vy6 z_A%ZVJtgd(lnntj^apHl;ZXwc(ATrf#6{(4J-d&hR+Iy=TDIIU z+9;l4<^9y}J`%v(<%=kh0N-!Rf9pyw-y1#8ZytFBjk<9w;x_eKde_B`3VVY1TLi6e z2qV#hr?TjA6~{QD-jl55*7xHusQXO`PJKkeWOh=)ceasCL5C7`d*gmlQA$n~sUPD| zKynzb2de{&pJA)2)~qE*oGtn_cGrTV{f_x6$>bt3d+px-cKJMSio_nWe${;(bXE zB#_@Zp^gE`tyDdPE8mJNVOD$g;UV#VEd|gR?jXPEpcrpMQRSvRTL@AC%sa|Eaxi9z zc4eC=WzId=QDr}1zTOC!M6Vfb@D1qrVRL*NEl9r@%I-16n)O;+juKTpn4_2JmqOWT z1AIAsHJFwy=50W?XGUgczcuh3)jh}5we3;9G?Y!|%X{dV)?!sGX>Plf2O0k27J-3% z!bj+q|1Hggx6aOmv*3%o%dhXy7QSFh1aq}FpqIrkG6uHKtnmW2BBk0UU=(zC$gX7$ z^CfUjV`gLi-TIU{uWmYQk>YYYpV%mI!k!KJcN(;K)1bxf+#c1hpcDjUxNy&`2fh_6 z@9yd68UskeHUY7(iyrAypCFW|MK4aXkK~56nzyss^qsDw(Qn{8ODJS^cWA;4Dpa-y zoHxp^+396ZrujU4uzzC5`{rO_>tuBU*e=P#7ABhO#Sf9ugfF2jUgyz}-4hUMe*uKc zh_;Y@~2N?KUYDHCv}^S=-rN21Dr&Q;xAD8`ZS~$R%H*0>H)e z8Uq;9mBbOwXmg#}MuC7Y00&KbQ0%Dw_-|<1w`7ZHC@9bPISVL%x#ytSk>!V9!8$Y& z=$9z#`rkHK6wsYh%o?@pBOclW*oPFjW>0|8uP|Zg8nPcWpR?tmABh-?bUK3Y(JWS! z(Bjz|iM6>Yz5@9pj~~LfEyut&L(H%LXOPNhFszotAe-5>7=6cJJ%{945tS=75BwV9 z!ms39rHAM_vL_L6*RB(ZzNxx>gQZ`?wvd4R@2M`55MEs*8ADEM&-KTj=wEOIDR}l^ z0l6o6)l(FnLVm@7ob3A3RC4-2Nskj2awcZ~ortz(or>2qPXSP_pVpjAvFNw}8e`vw ze&=n)RLu343{2TI*>qoFPOLoh{w!!tl5ZH}K5$=aNR=$i4yyh)>SBMtA?Y{$v?lTn%w>26FK91fyWFMw4s`NC}quy8cBuFkEDs zF#P9ObT@mtWM(4}NUN74X*xZ%^yHX)D|;^8AG*M|u)ou~iXVG@XWzpjvz^P0%~XId zA|VZWam|al?c-~F!{Ao-8RpmmJLV4n`*}bn{{Cm>%WJa$=0Qrzd&Bq93?Mz+$=LGu z2Rox>AUQ`>?a|KYAN1H6?Xy2G*q?U$^N9V~Xn%fff4cZ7>x}*;#BXPGt4;l0DU|sQ zx8+nrozdAQZ}0(6%jthquNnvSO7Qz{?N9bf)}ViJ?z2q?Z`CBUUPvzYenxOBE4}u# z&S)?FC%8l-e66$bN)SZp&c@mKr>pZ%(fm^^|CGo-rSeZT_NlD1@lu`)xEiPD^JWHl zL5CJ!!;;Ldet`{?p&Xdn$`_(4ohg|bi5B=mYLBSS>Uei;gfMP!nzv6(hS5hCDLb>@4< z!-mwLe4~xOmARPhcQJ|}Cx!=#ZOJ1$2f35sK2P5Nd@S?N zVcf)UFy}1p2N=$(DsGc<;>7c-PI&Y$7LL$$>HUgqmCB4xFT*C$2Doy<-FbRQd@G2H zyXH!2B|=zz#lEBaBt(1QIIFySPg%exbsS8jt6FR)8V6!swby?+bK}BXsH^v1vn>d9 zRmCFyV4I0{RkuZhEBf{x8*e6Ka+}s_-C=TO-#J%w5Yy4f6L0f=?VkDey*YV)gJ1}; zs$EXYKY>^SN?FBuIO_iJ|MK`)7~uRrjE{8`JQL0sZa~E{-!pfx?cMC8_ZW_fqMQ$= z{9ouEwmHc3APNcpr@B@h+{6a^VmN46&devhmtx-27}1PmGu!+biss}U9i%U#MCI>1 zENSmD&wJiAK;LEdTD8qtEG+jnV%4V*WjGr#@yO!-#oWR^82Z{a`NhzOh;%t>7ssac z?_w!jI()b_(u;?-#LIi)T=N30Uzbe~0bgg_)1n*M7&z5`ukv+drn8(d_DOd|v_DOH zPba)rbyT1fc*f1>k}oF|*m+%u%hRbZ7qY5HvN{wpD8wCsd$E1(EsU2F8lkiZ+lmqS zOY!5F6iS9EiOrVRe#0+Q-X3R_uZzv>RL)9ze+ov~dJ6b$@jgLE1Q%{zk0Qbw!&6GS zt;3-L98^??9;ps(IOnIDm+LWM?!-LVK)26UAGZMF5Xp>;T<&@y+#41kjdxysmy15!MLdHfDD%*8WxL79@ zI`Wra53)<8+Z%^N8$5)Zl-$4lLVxlVdmQ{JFdx-bzqc1gr)HXeU`&77>$wlvvYLJ| zyT3ozx%axy9wta-$!GBi@x)gjRon7AHjp&D^Xr1C6Suz23%m}Uwf>ddQBx}Ty^0|O~bjwLxR>~N3%Q;7o2R$I5qt6M3 z$;B$c(%8rN({BPc;l2n@FnGKh9J9#@2UMi#5fPOk6bk+bSs3GsEWE@^6RL?tQ>$&0 zyXF~@g}LMhftzwP$77OzSEtaGlj z^Zu-J-m~-mtaA>u^Zu+0rWh&ruZY)FzTNQeslR?F{@wnA0scL4`Cq}m{|-S8LGb^N z@tVZH|0l$2dJF&lpA@etN01@(?-Z{oSJblPKO3)!qW?SNH8JpG@YlD-Ys$e=V3%IT zUlfU=UJ2qykRxfQ0%?c%5rfLUW4xwZ*?_;Q1$|jkY8qvtGz7s3(UZODdW^D~ za`BnunkFi>(j+M&h}I--r)W*w={DcI(SH8F7OCkcw9KK6nm9!(c4(xg_Z!&!)sdQj zeANvDvoIxij%FKlEP|d2SJjLrVMc?$ZyF%V=4F|s?!qR4kge@N@Ft3;+Y$5s7Q6}BJX>k(VFnhV zS#-HMu!}DrDRBazH~ZR`1N_xI*ej1_;T|<*0n@cXo6NLu3YTm8sIoYwHUXY6HxK3) zetL|uyv*flVo$bAR}0#N`x4XrThJy5ib5`%piPG`J>k64+kih45xw^X``cHNHt=u~ z?K?4p;R%)@1pZ}@EExx1NL9T~JmP0CRSE1fpq_t=*F;FD{Qma87_Z6Ps2VUY7!t3^ zgl3Y9>|7uwr+Fs4H*;=LA~PjjubYJ*TEvfW;jA|b>I24`_)H&wdjtV}g7{1}I1@bP zNX?|m_F&$0;xt?Vnqd5#CN+;VL7Mh&Hzz;NnC6pARHi8=C{xe>{Gd!0whO*yVB5xz zVB2y#yqZHRol+%z*#h{#)H6YiB!1i{W-<`C$XFO;(hAp<H}M?L%$<(QM+LSyt3^=fbo0cd ze^*3tno{0N*c0f`dlHN5>=plv85{;A*Cp#NomeC@6;~@W^a`RX_eg6L&E-1l2-_cj zW5RZI&xig-E+n>nX`C5Sp(~S<{CV!9(218I#)b{jl!pk>XWhn@wRb# zy(FpI_~^BD(te^7epK$9k~(N6?PAg}V>3t28~I&F&X^=Q)7R>0D&b#VZrGH5Jx5Y({K8A$;0H8og{Qp4Xrq zoWX@95=|g%Oy7O4;s1;~FBsP(LodaMNc=rb@?0Ho&(`TX!oKaL?0)71_EprzLQ2t~ z*4A)-@3f3JOA`#yAv!h|?K)Afm05;R0yk+zxQmMFQU1VxAcW^gT!_tWapC!pBXQ&K zUHXwp)pd_1>h@KKHYGE2i97XdwUc^05qjMx!*oJRCFZ9_9!Yd|LQjrxKe>6F>2|Z3QRcaFZ*E3$VHOdM0=pKvReQac zaM|}}%aM5>_45OPGha zRl6JR$#(EXpcgYp?uI%5t~#chTp44jo$t(ByHdaKkcB@z!pT_Nxe$ZaP4gzX81U06 z)1wRg$%~TS%XxbZW1PYF)vs)>Ul(F@(b=%WbZmp^*w3;P=-3eYb5uO0Tj=FLJf@%6 zcuYT(xvq`JB#PvkKuXTT8_h4*M~SDT;8e>XIqAxF*=sb16p#s6of{D{7J))C0a@Fy z%hXAQcE-xvhXi4ImWCCC>BmqaU1t0mzY4qLH2;h@sm$3QxLOQw%7^(;xFx6M4DuCh zDU})ig*kdR_N)AGU!VNIu+Z8Tvj8Mv;6u;EV+tZKp<}q2l17jZi>nkANu1wztk6rn z9I+f7dTAAvFI{shJz)SDIaV#giMewh@Qw7Q^-jp+F#>^K;Pq?v;3MP%9bFaJcM=>?f* zIb$Y9oH5+1j$!u|DdR79&G?IFC;k%okiS<(YWaILOe8anKqj~w+0<}ZaFc_DG~D?l z#!1}hxKwP?;!9@~d==o@xtH;p9)tS~!R-#PC)%e!FKESeyTR2A*E-!Q0#y=qP1fnw z*tV;1$>yvYUl?!ZQkxb;b*83<4}WOs3>;Z*;_1{jp7)bnj8n~94 zrZ{4cI_Zn3o(!&gAhLDr9FA`%H&b&Z6uad`URwCP8pABHm=+UZY>kg7nJCp?;Pm13 zdYE0LzqKXTM4a%e5RlL8o8`=Vh2@mqdAMnv9p z)5p_h^Yj`|ub8KOF8185zX2m*ztE6Joz_+oN#lN{{$IJ?5`fv>Cb{8Lm@*Crpu=}u z0k(uT2J2oIUG^DN87|AP&c=xtfEj#gEXzMdf+rBBaRSf!J&Rx4^t?4r7$goGBn}%S z4jUxKR2w7?8zc@JBo2ebuz4Z=r#_>52LLZzBUje-#dBuGddW3sAk+bz&k%=f-sYocJLY_8t!9XM`S8=i8zILVD*gt=4<21SK#oHc2rn}D zz?WWB1AWov*Xt)R5&fEoH&q#L1&sqZJz&3FpeA?NBjS& z<-GrZhncrqBPpDX$Ri5GW$|2h2ZqMsVzxRJ=IJeQxR6lh_uZ2njz7~IX5O&D&75x{ zaJ{dDPt%Gd;abV@6>J5#T~I~`0vE;)5b_kl$-B8k#{#EMdpFOsWzzoyKA%#VTWo>4 zCv+)RTM6w9s!fd6jDMk7$n*%$-*PrgL4Rd(Yr(pHNy~fpt2~ujv>gGxkTHR^rRs;6`32|)Sh z9jf+T?C2|$@$@9N8SHI}GzrlhKT^%8tdCK-zFdtZa`tyj@c=^f^m5&vz(aTk*b!=a zo_CEw)@YXiSOm>#+BGQi1jKxkxzlE%+AC;uF#*>dt9WR?A|O>gi@5bhrM=S%C1qx!xPtev8V6aodmD8%&G zWsAI~B5O_kADBA*v?{yi8D^6;#ywPBl_hKxz2SBoK4+{y|InAZ&utT)baL#v0L7#J!MREila!MA?SYOZYOP6npY zm3S>68SJ06mEzQiS<0zPt2Q_-@?kA|YlFUQ_pp6tZk<(3_&sKY#k_gpq<=B~F;}%G z(~q!GAnw+~;71aNLep8>+NXghN9wl;QxnNL0xUkEIC&krj92u~Q+6F9O%eLx@;{ob zW^m^t!Or{n{O7#`NiWN%_p}=M!NlQO3hwCxa@Tkj8#aT7Qdng0w#k_q{w?bQYHG; z4qS9`t)gSc=`R1{p?z@xVQ>q-HC0=FY@@sflU?3;HwZsp?!86HxUD468= z{d%>*^AUc$TA4(QoOEqACA;uIF4) zByWO~a^ch}_WWHyzdNI5C*WF%IteU@$^*J*@ewO8)kBs|=?J+c=GL@A+$DTm|2q#S z3R!dGJjGA@hqqg9LA?WBS5IF|G44!V)l+?!sBU(R8t)E5L{wOW9`SzP(ML3{7mB^k z{m*&_dUoGe#^B34Vxj(?odlJTuk=oL|GEPD>9lO(oxnDM%7kIdlq~S%zp9{d)J8V7 zc!c$$RCCjRK!balpu=jNAW}3i=v|IHLlrbmJ-&3A>s^BLCcx05JN=p`F-d(Os-=jc z4tR3GTK8qS$-uEva3TU%Un-P7QZr7Um~JBQT{VOf1ha@QTPT8^Gfn&-xgi|T6XR9= zKxVSMs+;hD2ab-XHI2OlL9L3orQ?KxFka8w1=sUZ)jHgUIp+yJ3P&BotV|G&*G&t zWY9hKMaEqja70UHh!WK1B}0_pjv`9keKCJ_2vU^ncy3smAw_6t{vK_D(dWS{a^&E^ z+meG(mSreV<4~4iE0^L@+g7%*&G1mO8(J_XM+;1K_*S^t(6U(Q09%Oj(UC$}yeCBR zh+~!B;kf(AVa{<_In8{#bp)hMl5sOJem|t<=mV+19 z){S)WALLm&o;d~8iRk#GRHzRUekkd2fpjzB?Fx-Dvg5g;|F6LdM|y%6K~4;ucqA&A zprsrEY+o)PklN^ADmw7~wReK=d)@+H__U(i4yMFhGwl|9FGD$D;fs=ZwzQoWkz;%> zo6AX0x;QT9nwW_m27*3dXhb#a*&knM`5;j_s@#kT4TdJa?W*?Cvrc9&{!%+?r6LnI z>{aJXc4uQ0LFHh>v#w{#k`enA8+sEw%p3s_$Z%io%(W&lqH`o=}hZsJFo(7p*pI(lP&k&SeeyI|#n zbK3~e{ch3Rrbo2R7@}TAkq3E1yNz@W#k|^RwzVhlCoVQJz62miMOB{(&pTnNXoog= z*)p6#sS?U@y8{qRjr1hoo1?3`xKz1|wYRSJ@6a%-{go2sO$gCS^!)WL=;MGe?#Mq| zn5e5RW;HJAq`XhWpk)EyL*zdn32JQuhckrhcnSF_g`CB z{|!zi787lOS$iGyDo}8Pzh}zMeC68XNRRG6e?&q3*#MiJVR-azQck!F<%V-~7Scla=x8Pr zbJ0xBKSneY#F38OCXk5&8Q3r;=Z6WE^PaegiBkq>!NBn3Hi%2#yT;-;WCP2pWj$+B zyqBnlcz?f_l$)8a36|URKg28dqFxCPf1LnQCJ1qgNY+}3M9%eXo;jaz7+d89YMTY4 zn<*V*1IyS@7&i?H0E@p=cGjVe)syuF=cP?HC^CT&{m(r@5QdHAU9UK2;?3zIsXSS? zpX}_5pFh07boLeJlkCW6Y4$SnMa|%$^R9GO&0o$lm-A|8(8Tzz#tfM z)w=p=0TAryw;PY7TZ7@_BzjB`T4>$%gxNVa#Ktx5eKt(Mh8F26EB7)z8hmz~!Nk|) zVxd;L!#OyQm1NS$AdclXnt^FpXiTP8Zt-2PSoiC-y-Ng>iv$r%@t*TnoE8&XTy~1V z+$QSQb85{YG|?KM+l02?r(f>(PMojxoXH3r@~ZJezK`i5)BJ9Y(CcDL7=+HY+xU*Y zleIA@S&-ktE1<^0pHdHJ>56lCKB1J(52yPG+QQaoq8nm*!-Nj)1==U$YR#Y|KzO~o zKfN;)+ENbvJ@e)LTLl+8^=EF>^z(mH-_-c<0?j^@RvXDN%^$QgwT`p0XPlOE0V7is zgYj1=Y-(sdsi>=6eSuy9t{4NwL$gKl>{-l${D~1<3C9uVX?RBPJkG=p$;H?q_6GrV zHy$<6O$^j~w5mWNoL>4WDxt^0Xs+2Vg;q?6p;@#e7f!I92l1*%IT*{3&5 zs04m-Da|rd!)WK(uxTie&!Xe)SZwerqBA**&Z3&@JregmM{pxnaD~3Hmf#Wq@dl^) zY?7v&0s`R@7$3+Yvlii!p{;w~73{MH)d{IdL?X4>)7#uWcNcCy()~rwVzrju&E}|! zGm!Ew`9SuInrJ^qfu}-&W1)7tSYw%zlkoE-DM8>v$HbJ|vaUj{dnd#RDn>*xNw;PN zWQv9vJyv&5AKQu$ugArzHqkh-r>2Fy^NRj_h2pnVP|lzE!dokp{G}Dbe`y5*u>56R z8uzvphAvlp9is8c=VRTX8;y*jmRQ26y(ah24BZpPD+>Y=qOjhhw8Q z^0~2I|1qj{I)16CR)~AVqieo7xF&0RL{Bdf>0(t>+6wR)FrqkL^GjMpTFgh&y>Hmh z-C5XB>~>BSk2{j?9Z|Vya#6!&f)fsoE+}L%TVUB{-Kzc+Kv_*!3Y?2@qPcmNHsZ5b zrp@idU*D|Hq&U53+M#fleNl*57%O+M&%GHGfR>oCWj{o3y@Od3EdAh~Erw7Af0%x8CnT{;P;7=jS)`pu zbe#UqE+ylAu%|uz#~AZW6tcKK;{1ZQGo}~oZ;d>CtT&}O+?(-&@@h*=9tWlTV!~t$ zvBG+NiQdo>hh!XI74l~co9pl;G!i~Vjo1&@@?m{ڼJ*>Yqsyd{>8u~j!own_( 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 z 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

CA{HGXS?71D(X);Q4gvpw!8`-I!hkSiF#N? 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Μ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

d8m_P}E6 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

B?@t4}_dCb!!@U;oCTTO|cWW;x@d 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 D60rGA literal 0 HcmV?d00001 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avutil-59.dll b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/bin/avutil-59.dll new file mode 100755 index 0000000000000000000000000000000000000000..03373a292c51908cedc0764c317047743455fc5d GIT binary patch literal 854528 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�N3jq% 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

u;uV$<hk}@?#^1^>W&tS#GR!Klsq6Zln32 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

AIYoU7OHtOZx}Zp6y{1Hc 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 literal 0 HcmV?d00001 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h index 6bce0d388..77ca8dee1 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avcodec.h @@ -187,6 +187,17 @@ struct AVCodecParameters; * @{ */ +#if FF_API_BUFFER_MIN_SIZE +/** + * @ingroup lavc_encoding + * minimum encoding buffer size + * Used to avoid some checks during header writing. + * @deprecated Unused: avcodec_receive_packet() does not work + * with preallocated packet buffers. + */ +#define AV_INPUT_BUFFER_MIN_SIZE 16384 +#endif + /** * @ingroup lavc_encoding */ @@ -223,9 +234,18 @@ typedef struct RcOverride{ * Use qpel MC. */ #define AV_CODEC_FLAG_QPEL (1 << 4) +#if FF_API_DROPCHANGED +/** + * Don't output frames whose parameters differ from first + * decoded frame in stream. + * + * @deprecated callers should implement this functionality in their own code + */ +#define AV_CODEC_FLAG_DROPCHANGED (1 << 5) +#endif /** * Request the encoder to output reconstructed frames, i.e.\ frames that would - * be produced by decoding the encoded bitstream. These frames may be retrieved + * be produced by decoding the encoded bistream. These frames may be retrieved * by calling avcodec_receive_frame() immediately after a successful call to * avcodec_receive_packet(). * @@ -353,10 +373,6 @@ typedef struct RcOverride{ * Discard cropping information from SPS. */ #define AV_CODEC_FLAG2_IGNORE_CROP (1 << 16) -/** - * Force audio encoders to use a fixed frame size. - */ -#define AV_CODEC_FLAG2_FIXED_FRAME_SIZE (1 << 17) /** * Show all frames before the first keyframe @@ -419,14 +435,6 @@ typedef struct RcOverride{ */ #define AV_GET_ENCODE_BUFFER_FLAG_REF (1 << 0) -/** - * The decoder will bypass frame threading and return the next frame as soon as - * possible. Note that this may deliver frames earlier than the advertised - * `AVCodecContext.delay`. No effect when frame threading is disabled, or on - * encoding. - */ -#define AV_CODEC_RECEIVE_FRAME_FLAG_SYNCHRONOUS (1 << 0) - /** * main external API structure. * New fields can be added to the end with minor version bumps. @@ -507,21 +515,16 @@ typedef struct AVCodecContext { int flags2; /** - * Out-of-band global headers that may be used by some codecs. - * - * - decoding: Should be set by the caller when available (typically from a - * demuxer) before opening the decoder; some decoders require this to be - * set and will fail to initialize otherwise. - * - * The array must be allocated with the av_malloc() family of functions; - * allocated size must be at least AV_INPUT_BUFFER_PADDING_SIZE bytes - * larger than extradata_size. - * - * - encoding: May be set by the encoder in avcodec_open2() (possibly - * depending on whether the AV_CODEC_FLAG_GLOBAL_HEADER flag is set). - * - * After being set, the array is owned by the codec and freed in - * avcodec_free_context(). + * some codecs need / can use extradata like Huffman tables. + * MJPEG: Huffman tables + * rv10: additional flags + * MPEG-4: global headers (they can be in the bitstream or here) + * The allocated memory should be AV_INPUT_BUFFER_PADDING_SIZE bytes larger + * than extradata_size to avoid problems if it is read with the bitstream reader. + * The bytewise contents of extradata must not depend on the architecture or CPU endianness. + * Must be allocated with the av_malloc() family of functions. + * - encoding: Set/allocated/freed by libavcodec. + * - decoding: Set/allocated/freed by user. */ uint8_t *extradata; int extradata_size; @@ -562,6 +565,23 @@ typedef struct AVCodecContext { */ AVRational framerate; +#if FF_API_TICKS_PER_FRAME + /** + * For some codecs, the time base is closer to the field rate than the frame rate. + * Most notably, H.264 and MPEG-2 specify time_base as half of frame duration + * if no telecine is used ... + * + * Set to time_base ticks per frame. Default 1, e.g., H.264/MPEG-2 set it to 2. + * + * @deprecated + * - decoding: Use AVCodecDescriptor.props & AV_CODEC_PROP_FIELDS + * - encoding: Set AVCodecContext.framerate instead + * + */ + attribute_deprecated + int ticks_per_frame; +#endif + /** * Codec delay. * @@ -975,16 +995,12 @@ typedef struct AVCodecContext { */ uint16_t *chroma_intra_matrix; -#if FF_API_INTRA_DC_PRECISION /** * precision of the intra DC coefficient - 8 * - encoding: Set by user. * - decoding: Set by libavcodec - * @deprecated Use the MPEG-2 encoder's private option "intra_dc_precision" instead. */ - attribute_deprecated int intra_dc_precision; -#endif /** * minimum MB Lagrange multiplier @@ -1054,20 +1070,18 @@ typedef struct AVCodecContext { */ AVChannelLayout ch_layout; + /* The following data should not be initialized. */ /** * Number of samples per channel in an audio frame. * - * - encoding: may be set by the user before calling avcodec_open2(), and - * libavcodec may then overwrite it if needed. Each submitted frame + * - encoding: set by libavcodec in avcodec_open2(). Each submitted frame * except the last must contain exactly frame_size samples per channel. - * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, except - * when AV_CODEC_FLAG2_FIXED_FRAME_SIZE is requested, then the + * May be 0 when the codec has AV_CODEC_CAP_VARIABLE_FRAME_SIZE set, then the * frame size is not restricted. * - decoding: may be set by some decoders to indicate constant frame size */ int frame_size; - /* The following data should not be initialized. */ /** * number of bytes per packet if constant and known or 0 * Used by some WAV based audio codecs. @@ -1634,16 +1648,165 @@ typedef struct AVCodecContext { * See the AV_PROFILE_* defines in defs.h. */ int profile; +#if FF_API_FF_PROFILE_LEVEL + /** @deprecated The following defines are deprecated; use AV_PROFILE_* + * in defs.h instead. */ +#define FF_PROFILE_UNKNOWN -99 +#define FF_PROFILE_RESERVED -100 + +#define FF_PROFILE_AAC_MAIN 0 +#define FF_PROFILE_AAC_LOW 1 +#define FF_PROFILE_AAC_SSR 2 +#define FF_PROFILE_AAC_LTP 3 +#define FF_PROFILE_AAC_HE 4 +#define FF_PROFILE_AAC_HE_V2 28 +#define FF_PROFILE_AAC_LD 22 +#define FF_PROFILE_AAC_ELD 38 +#define FF_PROFILE_MPEG2_AAC_LOW 128 +#define FF_PROFILE_MPEG2_AAC_HE 131 + +#define FF_PROFILE_DNXHD 0 +#define FF_PROFILE_DNXHR_LB 1 +#define FF_PROFILE_DNXHR_SQ 2 +#define FF_PROFILE_DNXHR_HQ 3 +#define FF_PROFILE_DNXHR_HQX 4 +#define FF_PROFILE_DNXHR_444 5 + +#define FF_PROFILE_DTS 20 +#define FF_PROFILE_DTS_ES 30 +#define FF_PROFILE_DTS_96_24 40 +#define FF_PROFILE_DTS_HD_HRA 50 +#define FF_PROFILE_DTS_HD_MA 60 +#define FF_PROFILE_DTS_EXPRESS 70 +#define FF_PROFILE_DTS_HD_MA_X 61 +#define FF_PROFILE_DTS_HD_MA_X_IMAX 62 + + +#define FF_PROFILE_EAC3_DDP_ATMOS 30 + +#define FF_PROFILE_TRUEHD_ATMOS 30 + +#define FF_PROFILE_MPEG2_422 0 +#define FF_PROFILE_MPEG2_HIGH 1 +#define FF_PROFILE_MPEG2_SS 2 +#define FF_PROFILE_MPEG2_SNR_SCALABLE 3 +#define FF_PROFILE_MPEG2_MAIN 4 +#define FF_PROFILE_MPEG2_SIMPLE 5 + +#define FF_PROFILE_H264_CONSTRAINED (1<<9) // 8+1; constraint_set1_flag +#define FF_PROFILE_H264_INTRA (1<<11) // 8+3; constraint_set3_flag + +#define FF_PROFILE_H264_BASELINE 66 +#define FF_PROFILE_H264_CONSTRAINED_BASELINE (66|FF_PROFILE_H264_CONSTRAINED) +#define FF_PROFILE_H264_MAIN 77 +#define FF_PROFILE_H264_EXTENDED 88 +#define FF_PROFILE_H264_HIGH 100 +#define FF_PROFILE_H264_HIGH_10 110 +#define FF_PROFILE_H264_HIGH_10_INTRA (110|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_MULTIVIEW_HIGH 118 +#define FF_PROFILE_H264_HIGH_422 122 +#define FF_PROFILE_H264_HIGH_422_INTRA (122|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_STEREO_HIGH 128 +#define FF_PROFILE_H264_HIGH_444 144 +#define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244 +#define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA) +#define FF_PROFILE_H264_CAVLC_444 44 + +#define FF_PROFILE_VC1_SIMPLE 0 +#define FF_PROFILE_VC1_MAIN 1 +#define FF_PROFILE_VC1_COMPLEX 2 +#define FF_PROFILE_VC1_ADVANCED 3 + +#define FF_PROFILE_MPEG4_SIMPLE 0 +#define FF_PROFILE_MPEG4_SIMPLE_SCALABLE 1 +#define FF_PROFILE_MPEG4_CORE 2 +#define FF_PROFILE_MPEG4_MAIN 3 +#define FF_PROFILE_MPEG4_N_BIT 4 +#define FF_PROFILE_MPEG4_SCALABLE_TEXTURE 5 +#define FF_PROFILE_MPEG4_SIMPLE_FACE_ANIMATION 6 +#define FF_PROFILE_MPEG4_BASIC_ANIMATED_TEXTURE 7 +#define FF_PROFILE_MPEG4_HYBRID 8 +#define FF_PROFILE_MPEG4_ADVANCED_REAL_TIME 9 +#define FF_PROFILE_MPEG4_CORE_SCALABLE 10 +#define FF_PROFILE_MPEG4_ADVANCED_CODING 11 +#define FF_PROFILE_MPEG4_ADVANCED_CORE 12 +#define FF_PROFILE_MPEG4_ADVANCED_SCALABLE_TEXTURE 13 +#define FF_PROFILE_MPEG4_SIMPLE_STUDIO 14 +#define FF_PROFILE_MPEG4_ADVANCED_SIMPLE 15 + +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_0 1 +#define FF_PROFILE_JPEG2000_CSTREAM_RESTRICTION_1 2 +#define FF_PROFILE_JPEG2000_CSTREAM_NO_RESTRICTION 32768 +#define FF_PROFILE_JPEG2000_DCINEMA_2K 3 +#define FF_PROFILE_JPEG2000_DCINEMA_4K 4 + +#define FF_PROFILE_VP9_0 0 +#define FF_PROFILE_VP9_1 1 +#define FF_PROFILE_VP9_2 2 +#define FF_PROFILE_VP9_3 3 + +#define FF_PROFILE_HEVC_MAIN 1 +#define FF_PROFILE_HEVC_MAIN_10 2 +#define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 +#define FF_PROFILE_HEVC_REXT 4 +#define FF_PROFILE_HEVC_SCC 9 + +#define FF_PROFILE_VVC_MAIN_10 1 +#define FF_PROFILE_VVC_MAIN_10_444 33 + +#define FF_PROFILE_AV1_MAIN 0 +#define FF_PROFILE_AV1_HIGH 1 +#define FF_PROFILE_AV1_PROFESSIONAL 2 + +#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 +#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 +#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 +#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 +#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 + +#define FF_PROFILE_SBC_MSBC 1 + +#define FF_PROFILE_PRORES_PROXY 0 +#define FF_PROFILE_PRORES_LT 1 +#define FF_PROFILE_PRORES_STANDARD 2 +#define FF_PROFILE_PRORES_HQ 3 +#define FF_PROFILE_PRORES_4444 4 +#define FF_PROFILE_PRORES_XQ 5 + +#define FF_PROFILE_ARIB_PROFILE_A 0 +#define FF_PROFILE_ARIB_PROFILE_C 1 + +#define FF_PROFILE_KLVA_SYNC 0 +#define FF_PROFILE_KLVA_ASYNC 1 + +#define FF_PROFILE_EVC_BASELINE 0 +#define FF_PROFILE_EVC_MAIN 1 +#endif /** * Encoding level descriptor. * - encoding: Set by user, corresponds to a specific level defined by the * codec, usually corresponding to the profile level, if not specified it - * is set to AV_LEVEL_UNKNOWN. + * is set to FF_LEVEL_UNKNOWN. * - decoding: Set by libavcodec. * See AV_LEVEL_* in defs.h. */ int level; +#if FF_API_FF_PROFILE_LEVEL + /** @deprecated The following define is deprecated; use AV_LEVEL_UNKOWN + * in defs.h instead. */ +#define FF_LEVEL_UNKNOWN -99 +#endif + + /** + * Properties of the stream that gets decoded + * - encoding: unused + * - decoding: set by libavcodec + */ + unsigned properties; +#define FF_CODEC_PROPERTY_LOSSLESS 0x00000001 +#define FF_CODEC_PROPERTY_CLOSED_CAPTIONS 0x00000002 +#define FF_CODEC_PROPERTY_FILM_GRAIN 0x00000004 /** * Skip loop filtering for selected frames. @@ -1732,13 +1895,8 @@ typedef struct AVCodecContext { * For SUBTITLE_ASS subtitle type, it should contain the whole ASS * [Script Info] and [V4+ Styles] section, plus the [Events] line and * the Format line following. It shouldn't include any Dialogue line. - * - * - encoding: May be set by the caller before avcodec_open2() to an array - * allocated with the av_malloc() family of functions. - * - decoding: May be set by libavcodec in avcodec_open2(). - * - * After being set, the array is owned by the codec and freed in - * avcodec_free_context(). + * - encoding: Set/allocated/freed by user (before avcodec_open2()) + * - decoding: Set/allocated/freed by libavcodec (by avcodec_open2()) */ int subtitle_header_size; uint8_t *subtitle_header; @@ -1928,13 +2086,6 @@ typedef struct AVCodecContext { */ AVFrameSideData **decoded_side_data; int nb_decoded_side_data; - - /** - * Indicates how the alpha channel of the video is represented. - * - encoding: Set by user - * - decoding: Set by libavcodec - */ - enum AVAlphaMode alpha_mode; } AVCodecContext; /** @@ -2151,8 +2302,6 @@ const AVClass *avcodec_get_subtitle_rect_class(void); * of the corresponding fields in codec. * * @return >= 0 on success, a negative AVERROR code on failure - * - * @relates AVCodecParameters */ int avcodec_parameters_from_context(struct AVCodecParameters *par, const AVCodecContext *codec); @@ -2164,8 +2313,6 @@ int avcodec_parameters_from_context(struct AVCodecParameters *par, * Fields in codec that do not have a counterpart in par are not touched. * * @return >= 0 on success, a negative AVERROR code on failure. - * - * @relates AVCodecParameters */ int avcodec_parameters_to_context(AVCodecContext *codec, const struct AVCodecParameters *par); @@ -2233,6 +2380,24 @@ int avcodec_parameters_to_context(AVCodecContext *codec, */ int avcodec_open2(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options); +#if FF_API_AVCODEC_CLOSE +/** + * Close a given AVCodecContext and free all the data associated with it + * (but not the AVCodecContext itself). + * + * Calling this function on an AVCodecContext that hasn't been opened will free + * the codec-specific data allocated in avcodec_alloc_context3() with a non-NULL + * codec. Subsequent calls will do nothing. + * + * @deprecated Do not use this function. Use avcodec_free_context() to destroy a + * codec context (either open or closed). Opening and closing a codec context + * multiple times is not supported anymore -- use multiple codec contexts + * instead. + */ +attribute_deprecated +int avcodec_close(AVCodecContext *avctx); +#endif + /** * Free all allocated data in the given subtitle struct. * @@ -2369,7 +2534,6 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); * frame (depending on the decoder type) allocated by the * codec. Note that the function will always call * av_frame_unref(frame) before doing anything else. - * @param flags Combination of AV_CODEC_RECEIVE_FRAME_FLAG_* flags. * * @retval 0 success, a frame was returned * @retval AVERROR(EAGAIN) output is not available in this state - user must @@ -2380,11 +2544,6 @@ int avcodec_send_packet(AVCodecContext *avctx, const AVPacket *avpkt); * @ref AV_CODEC_FLAG_RECON_FRAME flag enabled * @retval "other negative error code" legitimate decoding errors */ -int avcodec_receive_frame_flags(AVCodecContext *avctx, AVFrame *frame, unsigned flags); - -/** - * Alias for `avcodec_receive_frame_flags(avctx, frame, 0)`. - */ int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); /** @@ -2407,8 +2566,7 @@ int avcodec_receive_frame(AVCodecContext *avctx, AVFrame *frame); * For audio: * If AV_CODEC_CAP_VARIABLE_FRAME_SIZE is set, then each frame * can have any number of samples. - * If it is not set, or AV_CODEC_FLAG2_FIXED_FRAME_SIZE was - * requested, then frame->nb_samples must be equal to + * If it is not set, frame->nb_samples must be equal to * avctx->frame_size for all frames except the last. * The final frame may be smaller than avctx->frame_size. * @retval 0 success @@ -2551,7 +2709,6 @@ enum AVCodecConfig { AV_CODEC_CONFIG_CHANNEL_LAYOUT, ///< AVChannelLayout, terminated by {0} AV_CODEC_CONFIG_COLOR_RANGE, ///< AVColorRange, terminated by AVCOL_RANGE_UNSPECIFIED AV_CODEC_CONFIG_COLOR_SPACE, ///< AVColorSpace, terminated by AVCOL_SPC_UNSPECIFIED - AV_CODEC_CONFIG_ALPHA_MODE, ///< AVAlphaMode, terminated by AVALPHA_MODE_UNSPECIFIED }; /** @@ -2748,7 +2905,17 @@ typedef struct AVCodecParserContext { } AVCodecParserContext; typedef struct AVCodecParser { - enum AVCodecID codec_ids[7]; /* several codec IDs are permitted */ + int codec_ids[7]; /* several codec IDs are permitted */ + int priv_data_size; + int (*parser_init)(AVCodecParserContext *s); + /* This callback never returns an error, a negative value means that + * the frame start was in a previous packet. */ + int (*parser_parse)(AVCodecParserContext *s, + AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size); + void (*parser_close)(AVCodecParserContext *s); + int (*split)(AVCodecContext *avctx, const uint8_t *buf, int buf_size); } AVCodecParser; /** @@ -2762,7 +2929,7 @@ typedef struct AVCodecParser { */ const AVCodecParser *av_parser_iterate(void **opaque); -AVCodecParserContext *av_parser_init(enum AVCodecID codec_id); +AVCodecParserContext *av_parser_init(int codec_id); /** * Parse a packet. @@ -2914,7 +3081,7 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels, * * @note for encoders, this function will only do something if the encoder * declares support for AV_CODEC_CAP_ENCODER_FLUSH. When called, the encoder - * will drain any remaining packets, and can then be reused for a different + * will drain any remaining packets, and can then be re-used for a different * stream (as opposed to sending a null frame which will leave the encoder * in a permanent EOF state after draining). This can be desirable if the * cost of tearing down and replacing the encoder instance is high. @@ -2949,8 +3116,8 @@ void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size); void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); /** - * @return a positive value if s is open (i.e. avcodec_open2() was called on it), - * 0 otherwise. + * @return a positive value if s is open (i.e. avcodec_open2() was called on it + * with no corresponding avcodec_close()), 0 otherwise. */ int avcodec_is_open(AVCodecContext *s); diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h index f110ba724..6411fab6f 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avdct.h @@ -19,9 +19,6 @@ #ifndef AVCODEC_AVDCT_H #define AVCODEC_AVDCT_H -#include -#include - #include "libavutil/opt.h" /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avfft.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avfft.h new file mode 100644 index 000000000..e3a0da1eb --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/avfft.h @@ -0,0 +1,149 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_AVFFT_H +#define AVCODEC_AVFFT_H + +#include "libavutil/attributes.h" +#include "version_major.h" +#if FF_API_AVFFT + +/** + * @file + * @ingroup lavc_fft + * FFT functions + */ + +/** + * @defgroup lavc_fft FFT functions + * @ingroup lavc_misc + * + * @{ + */ + +typedef float FFTSample; + +typedef struct FFTComplex { + FFTSample re, im; +} FFTComplex; + +typedef struct FFTContext FFTContext; + +/** + * Set up a complex FFT. + * @param nbits log2 of the length of the input array + * @param inverse if 0 perform the forward transform, if 1 perform the inverse + * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_FFT + */ +attribute_deprecated +FFTContext *av_fft_init(int nbits, int inverse); + +/** + * Do the permutation needed BEFORE calling ff_fft_calc(). + * @deprecated without replacement + */ +attribute_deprecated +void av_fft_permute(FFTContext *s, FFTComplex *z); + +/** + * Do a complex FFT with the parameters defined in av_fft_init(). The + * input data must be permuted before. No 1.0/sqrt(n) normalization is done. + * @deprecated use the av_tx_fn value returned by av_tx_init, which also does permutation + */ +attribute_deprecated +void av_fft_calc(FFTContext *s, FFTComplex *z); + +attribute_deprecated +void av_fft_end(FFTContext *s); + +/** + * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_MDCT, + * with a flag of AV_TX_FULL_IMDCT for a replacement to av_imdct_calc. + */ +attribute_deprecated +FFTContext *av_mdct_init(int nbits, int inverse, double scale); +attribute_deprecated +void av_imdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +attribute_deprecated +void av_imdct_half(FFTContext *s, FFTSample *output, const FFTSample *input); +attribute_deprecated +void av_mdct_calc(FFTContext *s, FFTSample *output, const FFTSample *input); +attribute_deprecated +void av_mdct_end(FFTContext *s); + +/* Real Discrete Fourier Transform */ + +enum RDFTransformType { + DFT_R2C, + IDFT_C2R, + IDFT_R2C, + DFT_C2R, +}; + +typedef struct RDFTContext RDFTContext; + +/** + * Set up a real FFT. + * @param nbits log2 of the length of the input array + * @param trans the type of transform + * + * @deprecated use av_tx_init from libavutil/tx.h with a type of AV_TX_FLOAT_RDFT + */ +attribute_deprecated +RDFTContext *av_rdft_init(int nbits, enum RDFTransformType trans); +attribute_deprecated +void av_rdft_calc(RDFTContext *s, FFTSample *data); +attribute_deprecated +void av_rdft_end(RDFTContext *s); + +/* Discrete Cosine Transform */ + +typedef struct DCTContext DCTContext; + +enum DCTTransformType { + DCT_II = 0, + DCT_III, + DCT_I, + DST_I, +}; + +/** + * Set up DCT. + * + * @param nbits size of the input array: + * (1 << nbits) for DCT-II, DCT-III and DST-I + * (1 << nbits) + 1 for DCT-I + * @param type the type of transform + * + * @note the first element of the input of DST-I is ignored + * + * @deprecated use av_tx_init from libavutil/tx.h with an appropriate type of AV_TX_FLOAT_DCT + */ +attribute_deprecated +DCTContext *av_dct_init(int nbits, enum DCTTransformType type); +attribute_deprecated +void av_dct_calc(DCTContext *s, FFTSample *data); +attribute_deprecated +void av_dct_end (DCTContext *s); + +/** + * @} + */ + +#endif /* FF_API_AVFFT */ +#endif /* AVCODEC_AVFFT_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h index 9bde9a41b..a09c69f24 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/bsf.h @@ -326,382 +326,6 @@ int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf); int av_bsf_get_null_filter(AVBSFContext **bsf); /** - * @defgroup lavc_bsfgraph Bitstream filter graph - * Experimental graph-based API for bitstream filters. - * @{ - */ - -/** - * A link between two filters. This contains pointers to the source and - * destination filters between which this link exists, and the indexes of - * the pads involved. - */ -typedef struct AVBitStreamFilterLink AVBitStreamFilterLink; - -/** - * A filter pad used for either input or output. - */ -typedef struct AVBitStreamFilterPad AVBitStreamFilterPad; - -/** An instance of a filter */ -typedef struct AVBitStreamFilterContext { - /** - * A class for logging and AVOptions - */ - const AVClass *av_class; - - /** - * The bitstream filter this context is an instance of. - */ - const struct AVBitStreamFilter *filter; - - /** - * name of this filter instance - */ - char *name; - - AVBitStreamFilterPad *input_pads; ///< array of input pads - AVBitStreamFilterLink **inputs; ///< array of pointers to input links - unsigned nb_inputs; ///< number of input pads - - AVBitStreamFilterPad *output_pads; ///< array of output pads - AVBitStreamFilterLink **outputs; ///< array of pointers to output links - unsigned nb_outputs; ///< number of output pads - - /** - * Opaque filter-specific private data. If filter->priv_class is non-NULL, - * this is an AVOptions-enabled struct. - */ - void *priv_data; - - /** - * filtergraph this filter belongs to - */ - struct AVBitStreamFilterGraph *graph; -} AVBitStreamFilterContext; - -/** - * The number of the filter inputs is not determined just by the filter's static - * inputs. The filter might add additional inputs during initialization depending - * on the options supplied to it. - */ -#define AV_BSF_FLAG_DYNAMIC_INPUTS (1 << 0) -/** - * The number of the filter outputs is not determined just by the filter's static - * outputs. The filter might add additional outputs during initialization depending - * on the options supplied to it. - */ -#define AV_BSF_FLAG_DYNAMIC_OUTPUTS (1 << 1) -/** - * The filter is a "metadata" filter - it does not modify the packet data in any - * way. It may only affect the metadata (i.e. those fields copied by - * av_packet_copy_props()). - * - * More precisely, this means that the data of any packet output by the filter - * must be exactly equal to some packet that is received on one of its inputs. - * Furthermore, all packets produced on a given output must correspond to packet - * received on the same input and their order must be unchanged. - * Note that the filter may still drop or duplicate the frames. - */ -#define AV_BSF_FLAG_METADATA_ONLY (1 << 2) - -/** - * Get the name of an AVBitStreamFilterPad. - * - * @param pads an array of AVBitStreamFilterPads - * @param pad_idx index of the pad in the array; it is the caller's - * responsibility to ensure the index is valid - * - * @return name of the pad_idx'th pad in pads - */ -const char *av_bsf_pad_get_name(const AVBitStreamFilterPad *pads, int pad_idx); - -/** - * Get the codec ids supported by an AVBitStreamFilterPad. - * - * @param pads an array of AVBitStreamFilterPads - * @param pad_idx index of the pad in the array; it is the caller's - * responsibility to ensure the index is valid - * - * @return an array of AVCodecID terminated by AV_CODEC_ID_NONE, or NULL - * if the pad has no codec id constrains. - */ -const enum AVCodecID *av_bsf_pad_get_codec_ids(const AVBitStreamFilterPad *pads, int pad_idx); - -/** - * Link two filters together. - * - * @param src the source filter - * @param srcpad index of the output pad on the source filter - * @param dst the destination filter - * @param dstpad index of the input pad on the destination filter - * @return zero on success - */ -int av_bsf_link(AVBitStreamFilterContext *src, unsigned srcpad, - AVBitStreamFilterContext *dst, unsigned dstpad); - -/** - * Initialize a filter with the supplied parameters. - * - * @param ctx uninitialized filter context to initialize - * @param args Options to initialize the filter with. This must be a - * ':'-separated list of options in the 'key=value' form. - * May be NULL if the options have been set directly using the - * AVOptions API or there are no options that need to be set. - * @return 0 on success, a negative AVERROR on failure - */ -int av_bsf_init_str(AVBitStreamFilterContext *ctx, const char *args); - -/** - * Initialize a filter with the supplied dictionary of options. - * - * @param ctx uninitialized filter context to initialize - * @param options An AVDictionary filled with options for this filter. On - * return this parameter will be destroyed and replaced with - * a dict containing options that were not found. This dictionary - * must be freed by the caller. - * May be NULL, then this function is equivalent to - * av_bsf_init_str() with the second parameter set to NULL. - * @return 0 on success, a negative AVERROR on failure - * - * @note This function and av_bsf_init_str() do essentially the same thing, - * the difference is in manner in which the options are passed. It is up to the - * calling code to choose whichever is more preferable. The two functions also - * behave differently when some of the provided options are not declared as - * supported by the filter. In such a case, av_bsf_init_str() will fail, but - * this function will leave those extra options in the options AVDictionary and - * continue as usual. - */ -int av_bsf_init_dict(AVBitStreamFilterContext *ctx, AVDictionary **options); - -typedef struct AVBitStreamFilterGraph { - const AVClass *av_class; - - AVBitStreamFilterContext **filters; - - unsigned nb_filters; - - /** - * Sets the maximum number of buffered packets in the filtergraph combined. - * - * Zero means no limit. This field must be set before calling - * av_bsf_graph_config(). - */ - unsigned max_buffered_packets; -} AVBitStreamFilterGraph; - -/** - * Allocate a filter graph. - * - * @return the allocated filter graph on success or NULL. - */ -AVBitStreamFilterGraph *av_bsf_graph_alloc(void); - -/** - * Create a new filter instance in a filter graph. - * - * @param[out] filt_ctx A pointer into which the pointer to the newly-allocated context - * will be written on success. May be NULL. Note that it is also - * retrievable directly through AVBitStreamFilterGraph.filters or - * with @ref av_bsf_graph_get_filter(). - * @param[in] filter the filter to create an instance of - * @param[in] name Name to give to the new instance (will be copied to - * AVBitStreamFilterContext.name). This may be used by the caller to - * identify different filters, libavcodec itself assigns no semantics - * to this parameter. May be NULL. - * @param[in] graph graph in which the new filter will be used - * - * @note On failure and if filt_ctx is not NULL, *filt_ctx will be set to NULL. - * @return a negative AVERROR error code in case of failure, a non negative value otherwise - */ -int av_bsf_graph_alloc_filter(AVBitStreamFilterContext **filt_ctx, - const AVBitStreamFilter *filter, - const char *name, - AVBitStreamFilterGraph *graph); - -/** - * A convenience wrapper that allocates and initializes a filter in a single - * step. The filter instance is created from the filter filt and inited with the - * parameter args. - * - * @param[out] filt_ctx A pointer into which the pointer to the newly-allocated context - * will be written on success. May be NULL. Note that it is also - * retrievable directly through AVBitStreamFilterGraph.filters or - * with @ref av_bsf_graph_get_filter(). - * @param[in] name the instance name to give to the created filter instance - * @param[in] graph_ctx the filter graph - * @return a negative AVERROR error code in case of failure, a non negative value otherwise - * - * @note On failure and if filt_ctx is not NULL, *filt_ctx will be set to NULL. - * @warning Since the filter is initialized after this function successfully - * returns, you MUST NOT set any further options on it. If you need to - * do that, call ::av_bsf_graph_alloc_filter(), followed by setting - * the options, followed by ::av_bsf_init_dict() instead of this - * function. - */ -int av_bsf_graph_create_filter(AVBitStreamFilterContext **filt_ctx, - const AVBitStreamFilter *filt, - const char *name, AVDictionary **options, - AVBitStreamFilterGraph *graph_ctx); - -/** - * Get a filter instance identified by instance name from graph. - * - * @param graph filter graph to search through. - * @param name filter instance name (should be unique in the graph). - * @return the pointer to the found filter instance or NULL if it - * cannot be found. - */ -AVBitStreamFilterContext *av_bsf_graph_get_filter(AVBitStreamFilterGraph *graph, const char *name); - -/** - * Check validity and configure all the links and formats in the graph. - * - * @param graphctx the filter graph - * @param log_ctx context used for logging - * @return >= 0 in case of success, a negative AVERROR code otherwise - */ -int av_bsf_graph_config(AVBitStreamFilterGraph *graphctx, void *log_ctx); - -/** - * Get the index of the source filter in the filtergraph that reported needing - * input more urgently. - * - * @return the index value of a source filter in the filtergraph, or AVERROR(EOF) - * if no source is accepting more packets. - */ -int av_bsf_graph_source_needs_input(const AVBitStreamFilterGraph *graph); - -/** - * Free a graph, destroy its links, and set *graph to NULL. - * If *graph is NULL, do nothing. - */ -void av_bsf_graph_free(AVBitStreamFilterGraph **graph); - -/** - * @defgroup lavc_bsfgraph_source Packet source API - * - * The source filter is there to connect filter graphs to applications - * They have a single output, connected to the graph, and no input. - * Packets must be fed to it using av_bsf_source_add_packet(). - * @{ - */ - -enum { - /** - * Immediately push the packet to the output. - */ - AV_BSF_SOURCE_FLAG_PUSH = 1 << 0, - - /** - * Keep a reference to the packet. - */ - AV_BSF_SOURCE_FLAG_KEEP_REF = 1 << 1, -}; - -/** - * Initialize the source filter with the provided parameters. - * This function may be called multiple times, the later calls override the - * previous ones. Some of the parameters may also be set through AVOptions, then - * whatever method is used last takes precedence. - * - * @param ctx an instance of the source filter - * @param param the stream parameters. The packet later passed to this filter - * must conform to those parameters. All the allocated fields in - * param remain owned by the caller, libavcodec will make internal - * copies or references when necessary. - * @return 0 on success, a negative AVERROR code on failure. - */ -int av_bsf_source_parameters_set(AVBitStreamFilterContext *ctx, const AVCodecParameters *par); - -/** - * Add a packet to the buffer source. - * - * By default, this function will take ownership of the reference(s) and reset - * the packet. This can be controlled using the flags. - * - * If this function returns an error, the input packet is not touched. - * - * @param buffer_src pointer to a source filter context - * @param packet a packet, or NULL to mark EOF - * @param flags a combination of AV_BSF_FLAG_* - * @return >= 0 in case of success, a negative AVERROR code - * in case of failure - */ -av_warn_unused_result -int av_bsf_source_add_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags); - -/** - * Returns 0 or a negative AVERROR code. Currently, this will only ever - * return AVERROR(EOF), to indicate that the buffer source has been closed, - * either as a result of av_bsf_source_close(), or because the downstream - * filter is no longer accepting new data. - */ -int av_bsf_source_get_status(AVBitStreamFilterContext *ctx); - -/** - * Close the source after EOF. - * - * This is similar to passing NULL to av_bsf_source_add_packet() - * except it takes the timestamp of the EOF, i.e. the timestamp of the end - * of the last packet. - */ -int av_bsf_source_close(AVBitStreamFilterContext *ctx, int64_t pts, unsigned flags); - -/** - * @} - */ - -/** - * @defgroup lavc_bsfgraph_sink Packet sink API - * @{ - * - * The sink filter is there to connect filter graphs to applications - * They have a single input, connected to the graph, and no output. - * Packets must be extracted using av_bsf_sink_get_packet(). - */ - -enum { - /** - * Tell av_buffersink_get_buffer_ref() to read video/samples buffer - * reference, but not remove it from the buffer. This is useful if you - * need only to read a video/samples buffer, without to fetch it. - */ - AV_BSF_SINK_FLAG_PEEK = 1 << 0, - - /** - * Tell av_bsf_sink_get_packet() not to request a packet from its input. - * If a packet is already buffered, it is read (and removed from the buffer), - * but if no packet is present, return AVERROR(EAGAIN). - */ - AV_BSF_SINK_FLAG_NO_REQUEST = 1 << 1, -}; - -/** - * Get a packet with filtered data from sink and put it in packet. - * - * @param ctx pointer to a sink filter context. - * @param packet pointer to an allocated packet that will be filled with data. - * The data must be freed using av_packet_unref() / av_packet_free() - * @param flags a combination of AV_BSF_SINK_FLAG_* flags - * - * @retval AVERROR(EAGAIN) output could not be produced. - * if AV_BSF_SINK_FLAG_NO_REQUEST was not set, - * @ref av_bsf_graph_needs_input can be called to - * know which source needs input more urgently. - * @retval >= 0 success - * @retval "another negative error code" legitimate error - */ -int av_bsf_sink_get_packet(AVBitStreamFilterContext *ctx, AVPacket *pkt, int flags); - -AVRational av_bsf_sink_get_time_base(const AVBitStreamFilterContext *ctx); -const AVCodecParameters *av_bsf_sink_get_parameters(const AVBitStreamFilterContext *ctx); - -/** - * @} - * - * @} - * * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h index 0966d2e61..f7541ffc4 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec.h @@ -27,8 +27,11 @@ #include "libavutil/hwcontext.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" +#include "libavutil/rational.h" +#include "libavutil/samplefmt.h" #include "libavcodec/codec_id.h" +#include "libavcodec/version_major.h" /** * @addtogroup lavc_core @@ -77,6 +80,21 @@ */ #define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) +#if FF_API_SUBFRAMES +/** + * Codec can output multiple frames per AVPacket + * Normally demuxers return one frame at a time, demuxers which do not do + * are connected to a parser to split what they return into proper frames. + * This flag is reserved to the very rare category of codecs which have a + * bitstream that cannot be split into frames without timeconsuming + * operations like full decoding. Demuxers carrying such bitstreams thus + * may return multiple frames in a packet. This has many disadvantages like + * prohibiting stream copy in many cases thus it should only be considered + * as a last resort. + */ +#define AV_CODEC_CAP_SUBFRAMES (1 << 8) +#endif + /** * Codec is experimental and is thus avoided in favor of non experimental * encoders @@ -188,6 +206,18 @@ typedef struct AVCodec { int capabilities; uint8_t max_lowres; ///< maximum value for lowres supported by the decoder + /** + * Deprecated codec capabilities. + */ + attribute_deprecated + const AVRational *supported_framerates; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const enum AVPixelFormat *pix_fmts; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const int *supported_samplerates; ///< @deprecated use avcodec_get_supported_config() + attribute_deprecated + const enum AVSampleFormat *sample_fmts; ///< @deprecated use avcodec_get_supported_config() + const AVClass *priv_class; ///< AVClass for the private context const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {AV_PROFILE_UNKNOWN} @@ -202,6 +232,13 @@ typedef struct AVCodec { * (usually AVCodec.name will be of the form "_"). */ const char *wrapper_name; + + /** + * Array of supported channel layouts, terminated with a zeroed layout. + * @deprecated use avcodec_get_supported_config() + */ + attribute_deprecated + const AVChannelLayout *ch_layouts; } AVCodec; /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h index 1186433c9..96afd2020 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_desc.h @@ -96,14 +96,6 @@ typedef struct AVCodecDescriptor { */ #define AV_CODEC_PROP_FIELDS (1 << 4) -/** - * Video codec contains enhancement information meant to be applied to other - * existing frames, and can't generate usable image data on its own. - * A standalone decoder is unlikely to be available for it and should not - * be expected. - */ -#define AV_CODEC_PROP_ENHANCEMENT (1 << 5) - /** * Subtitle codec is bitmap based * Decoded AVSubtitle data can be read from the AVSubtitleRect->pict field. diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h index 7cafac610..0a8d3bed1 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_id.h @@ -24,6 +24,8 @@ #include "libavutil/avutil.h" #include "libavutil/samplefmt.h" +#include "version_major.h" + /** * @addtogroup lavc_core * @{ @@ -204,6 +206,7 @@ enum AVCodecID { AV_CODEC_ID_BMV_VIDEO, AV_CODEC_ID_VBLE, AV_CODEC_ID_DXTORY, + AV_CODEC_ID_V410, AV_CODEC_ID_XWD, AV_CODEC_ID_CDXL, AV_CODEC_ID_XBM, @@ -251,6 +254,8 @@ enum AVCodecID { AV_CODEC_ID_012V, AV_CODEC_ID_AVUI, AV_CODEC_ID_TARGA_Y216, + AV_CODEC_ID_V308, + AV_CODEC_ID_V408, AV_CODEC_ID_YUV4, AV_CODEC_ID_AVRN, AV_CODEC_ID_CPIA, @@ -317,13 +322,6 @@ enum AVCodecID { AV_CODEC_ID_RTV1, AV_CODEC_ID_VMIX, AV_CODEC_ID_LEAD, - AV_CODEC_ID_DNXUC, - AV_CODEC_ID_RV60, - AV_CODEC_ID_JPEGXL_ANIM, - AV_CODEC_ID_APV, - AV_CODEC_ID_PRORES_RAW, - AV_CODEC_ID_JPEGXS, - AV_CODEC_ID_WEBP_ANIM, /* various PCM "codecs" */ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs @@ -364,7 +362,6 @@ enum AVCodecID { AV_CODEC_ID_PCM_F24LE, AV_CODEC_ID_PCM_VIDC, AV_CODEC_ID_PCM_SGA, - AV_CODEC_ID_PCM_DVDA, /* various ADPCM codecs */ AV_CODEC_ID_ADPCM_IMA_QT = 0x11000, @@ -419,16 +416,6 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_IMA_MOFLEX, AV_CODEC_ID_ADPCM_IMA_ACORN, AV_CODEC_ID_ADPCM_XMD, - AV_CODEC_ID_ADPCM_IMA_XBOX, - AV_CODEC_ID_ADPCM_SANYO, - AV_CODEC_ID_ADPCM_IMA_HVQM4, - AV_CODEC_ID_ADPCM_IMA_PDA, - AV_CODEC_ID_ADPCM_N64, - AV_CODEC_ID_ADPCM_IMA_HVQM2, - AV_CODEC_ID_ADPCM_IMA_MAGIX, - AV_CODEC_ID_ADPCM_PSXC, - AV_CODEC_ID_ADPCM_CIRCUS, - AV_CODEC_ID_ADPCM_IMA_ESCAPE, /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, @@ -557,9 +544,6 @@ enum AVCodecID { AV_CODEC_ID_OSQ, AV_CODEC_ID_QOA, AV_CODEC_ID_LC3, - AV_CODEC_ID_G728, - AV_CODEC_ID_AHX, - AV_CODEC_ID_APPLE_APAC, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -589,7 +573,6 @@ enum AVCodecID { AV_CODEC_ID_HDMV_TEXT_SUBTITLE, AV_CODEC_ID_TTML, AV_CODEC_ID_ARIB_CAPTION, - AV_CODEC_ID_IVTV_VBI, /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. @@ -607,8 +590,6 @@ enum AVCodecID { AV_CODEC_ID_BIN_DATA, AV_CODEC_ID_SMPTE_2038, AV_CODEC_ID_LCEVC, - AV_CODEC_ID_SMPTE_436M_ANC, - AV_CODEC_ID_ITUT_T35, AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h index d880e3a80..f4b9bb5c0 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/codec_par.h @@ -33,18 +33,16 @@ #include "packet.h" /** - * @defgroup lavc_codec_params Codec parameters - * @ingroup lavc_core + * @addtogroup lavc_core * @{ */ /** * This struct describes the properties of an encoded stream. * - * @note - * The `sizeof(AVCodecParameters)` is not a part of the public ABI, - * therefore this struct must be allocated with ::avcodec_parameters_alloc() - * and freed with ::avcodec_parameters_free(). + * sizeof(AVCodecParameters) is not a part of the public ABI, this struct must + * be allocated with avcodec_parameters_alloc() and freed with + * avcodec_parameters_free(). */ typedef struct AVCodecParameters { /** @@ -63,9 +61,9 @@ typedef struct AVCodecParameters { /** * Extra binary data needed for initializing the decoder, codec-dependent. * - * Must be allocated with ::av_malloc() and will be freed by - * ::avcodec_parameters_free(). The allocated size of extradata must be at - * least #extradata_size + ::AV_INPUT_BUFFER_PADDING_SIZE, with the padding + * Must be allocated with av_malloc() and will be freed by + * avcodec_parameters_free(). The allocated size of extradata must be at + * least extradata_size + AV_INPUT_BUFFER_PADDING_SIZE, with the padding * bytes zeroed. */ uint8_t *extradata; @@ -77,19 +75,19 @@ typedef struct AVCodecParameters { /** * Additional data associated with the entire stream. * - * Should be allocated with ::av_packet_side_data_new() or - * ::av_packet_side_data_add(), and will be freed by ::avcodec_parameters_free(). + * Should be allocated with av_packet_side_data_new() or + * av_packet_side_data_add(), and will be freed by avcodec_parameters_free(). */ AVPacketSideData *coded_side_data; /** - * Amount of entries in #coded_side_data. + * Amount of entries in @ref coded_side_data. */ int nb_coded_side_data; /** - * - Video: the pixel format, the value corresponds to enum ::AVPixelFormat. - * - Audio: the sample format, the value corresponds to enum ::AVSampleFormat. + * - video: the pixel format, the value corresponds to enum AVPixelFormat. + * - audio: the sample format, the value corresponds to enum AVSampleFormat. */ int format; @@ -105,27 +103,22 @@ typedef struct AVCodecParameters { * formats to actually decode them. It's the number of bits for one sample in * the actual coded bitstream. * - * This could be, for example, 4, for ADPCM. - * For PCM formats this matches #bits_per_raw_sample. - * - * Can be 0. + * This could be for example 4 for ADPCM + * For PCM formats this matches bits_per_raw_sample + * Can be 0 */ int bits_per_coded_sample; /** - * The number of valid bits in each output sample. - * - * If the sample format has more bits, the least significant bits are additional + * This is the number of valid bits in each output sample. If the + * sample format has more bits, the least significant bits are additional * padding bits, which are always 0. Use right shifts to reduce the sample - * to its actual size. - * - * For example, audio formats with 24-bit samples will have #bits_per_raw_sample - * set to 24, and ::format set to ::AV_SAMPLE_FMT_S32. To get the original sample, - * use: `(int32_t)sample >> 8`. - * - * For ADPCM, this might be 12 or 16, or similar. + * to its actual size. For example, audio formats with 24 bit samples will + * have bits_per_raw_sample set to 24, and format set to AV_SAMPLE_FMT_S32. + * To get the original sample use "(int32_t)sample >> 8"." * - * Can be 0. + * For ADPCM this might be 12 or 16 or similar + * Can be 0 */ int bits_per_raw_sample; @@ -136,55 +129,39 @@ typedef struct AVCodecParameters { int level; /** - * The width of the video frame in pixels. - * - * Video only. + * Video only. The dimensions of the video frame in pixels. */ int width; - - /** - * The height of the video frame in pixels. - * - * Video only. - */ int height; /** - * The aspect ratio (width/height) which a single pixel + * Video only. The aspect ratio (width / height) which a single pixel * should have when displayed. * - * When the aspect ratio is unknown or undefined, the numerator should be + * When the aspect ratio is unknown / undefined, the numerator should be * set to 0 (the denominator may have any value). - * - * Video only. */ AVRational sample_aspect_ratio; /** - * Number of frames per second, for streams with constant frame - * durations. Should be set to `{ 0, 1 }` when some frames have differing + * Video only. Number of frames per second, for streams with constant frame + * durations. Should be set to { 0, 1 } when some frames have differing * durations or if the value is not known. * - * @note This field corresponds to values that are stored in codec-level + * @note This field correponds to values that are stored in codec-level * headers and is typically overridden by container/transport-layer * timestamps, when available. It should thus be used only as a last resort, * when no higher-level timing information is available. - * - * Video only. */ AVRational framerate; /** - * The order of the fields in interlaced video. - * - * Video only. + * Video only. The order of the fields in interlaced video. */ enum AVFieldOrder field_order; /** - * Additional colorspace characteristics. - * - * Video only. + * Video only. Additional colorspace characteristics. */ enum AVColorRange color_range; enum AVColorPrimaries color_primaries; @@ -193,94 +170,65 @@ typedef struct AVCodecParameters { enum AVChromaLocation chroma_location; /** - * Number of delayed frames. - * - * Video only. + * Video only. Number of delayed frames. */ int video_delay; /** - * The channel layout and number of channels. - * - * Audio only. + * Audio only. The channel layout and number of channels. */ AVChannelLayout ch_layout; /** - * The number of audio samples per second. - * - * Audio only. + * Audio only. The number of audio samples per second. */ int sample_rate; /** - * The number of bytes per coded audio frame, required by some formats. - * - * Audio only. + * Audio only. The number of bytes per coded audio frame, required by some + * formats. * * Corresponds to nBlockAlign in WAVEFORMATEX. */ int block_align; /** - * Audio frame size, if known. Required by some formats to be static. - * - * Audio only. + * Audio only. Audio frame size, if known. Required by some formats to be static. */ int frame_size; /** - * Number of padding audio samples at the start. - * - * The amount of padding (in samples) inserted by the encoder at + * Audio only. The amount of padding (in samples) inserted by the encoder at * the beginning of the audio. I.e. this number of leading decoded samples - * must be discarded to get the original audio without leading + * must be discarded by the caller to get the original audio without leading * padding. - * - * Audio only. */ int initial_padding; /** - * Number of padding audio samples at the end. - * - * The amount of padding (in samples) appended by the encoder to + * Audio only. The amount of padding (in samples) appended by the encoder to * the end of the audio. I.e. this number of decoded samples must be - * discarded from the end of the stream to get the original + * discarded by the caller from the end of the stream to get the original * audio without any trailing padding. - * - * Audio only. */ int trailing_padding; /** - * Number of audio samples to skip after a discontinuity. - * - * Audio only. + * Audio only. Number of samples to skip after a discontinuity. */ int seek_preroll; - - /** - * Video with alpha channel only. Alpha channel handling - */ - enum AVAlphaMode alpha_mode; } AVCodecParameters; -/** - * @relates AVCodecParameters - * @{ - */ - /** * Allocate a new AVCodecParameters and set its fields to default values * (unknown/invalid/0). The returned struct must be freed with - * ::avcodec_parameters_free(). + * avcodec_parameters_free(). */ AVCodecParameters *avcodec_parameters_alloc(void); /** * Free an AVCodecParameters instance and everything associated with it and - * write `NULL` to the supplied pointer. + * write NULL to the supplied pointer. */ void avcodec_parameters_free(AVCodecParameters **par); /** - * Copy the contents of \p src to \p dst. Any allocated fields in dst are freed and + * Copy the contents of src to dst. Any allocated fields in dst are freed and * replaced with newly allocated duplicates of the corresponding fields in src. * * @return >= 0 on success, a negative AVERROR code on failure. @@ -288,13 +236,11 @@ void avcodec_parameters_free(AVCodecParameters **par); int avcodec_parameters_copy(AVCodecParameters *dst, const AVCodecParameters *src); /** - * This function is the same as ::av_get_audio_frame_duration(), except it works - * with ::AVCodecParameters instead of an ::AVCodecContext. + * This function is the same as av_get_audio_frame_duration(), except it works + * with AVCodecParameters instead of an AVCodecContext. */ int av_get_audio_frame_duration2(AVCodecParameters *par, int frame_bytes); -/** @} */ - /** * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h index b13e983b1..24250f8af 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/defs.h @@ -185,9 +185,6 @@ #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 @@ -197,14 +194,6 @@ #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 @@ -336,20 +325,6 @@ typedef struct AVProducerReferenceTime { 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. * diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h deleted file mode 100644 index a23083368..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/exif.h +++ /dev/null @@ -1,242 +0,0 @@ -/* - * EXIF metadata parser - * Copyright (c) 2013 Thilo Borgmann - * Copyright (c) 2024-2025 Leo Izen - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - * EXIF metadata parser - * @author Thilo Borgmann - * @author Leo Izen - */ - -#ifndef AVCODEC_EXIF_H -#define AVCODEC_EXIF_H - -#include -#include - -#include "libavutil/buffer.h" -#include "libavutil/dict.h" -#include "libavutil/rational.h" - -/** Data type identifiers for TIFF tags */ -enum AVTiffDataType { - AV_TIFF_BYTE = 1, - AV_TIFF_STRING, - AV_TIFF_SHORT, - AV_TIFF_LONG, - AV_TIFF_RATIONAL, - AV_TIFF_SBYTE, - AV_TIFF_UNDEFINED, - AV_TIFF_SSHORT, - AV_TIFF_SLONG, - AV_TIFF_SRATIONAL, - AV_TIFF_FLOAT, - AV_TIFF_DOUBLE, - AV_TIFF_IFD, -}; - -enum AVExifHeaderMode { - /** - * The TIFF header starts with 0x49492a00, or 0x4d4d002a. - * This one is used internally by FFmpeg. - */ - AV_EXIF_TIFF_HEADER, - /** skip the TIFF header, assume little endian */ - AV_EXIF_ASSUME_LE, - /** skip the TIFF header, assume big endian */ - AV_EXIF_ASSUME_BE, - /** The first four bytes point to the actual start, then it's AV_EXIF_TIFF_HEADER */ - AV_EXIF_T_OFF, - /** The first six bytes contain "Exif\0\0", then it's AV_EXIF_TIFF_HEADER */ - AV_EXIF_EXIF00, -}; - -typedef struct AVExifEntry AVExifEntry; - -typedef struct AVExifMetadata { - /* array of EXIF metadata entries */ - AVExifEntry *entries; - /* number of entries in this array */ - unsigned int count; - /* size of the buffer, used for av_fast_realloc */ - unsigned int size; -} AVExifMetadata; - -struct AVExifEntry { - uint16_t id; - enum AVTiffDataType type; - uint32_t count; - - /* - * These are for IFD-style MakerNote - * entries which occur after a fixed - * offset rather than at the start of - * the entry. The ifd_lead field contains - * the leading bytes which typically - * identify the type of MakerNote. - */ - uint32_t ifd_offset; - uint8_t *ifd_lead; - - /* - * An array of entries of size count - * Unless it's an IFD, in which case - * it's not an array and count = 1 - */ - union { - void *ptr; - int64_t *sint; - uint64_t *uint; - double *dbl; - char *str; - uint8_t *ubytes; - int8_t *sbytes; - AVRational *rat; - AVExifMetadata ifd; - } value; -}; - -/** - * Retrieves the tag name associated with the provided tag ID. - * If the tag ID is unknown, NULL is returned. - * - * For example, av_exif_get_tag_name(0x112) returns "Orientation". - */ -const char *av_exif_get_tag_name(uint16_t id); - -/** - * Retrieves the tag ID associated with the provided tag string name. - * If the tag name is unknown, a negative number is returned. Otherwise - * it always fits inside a uint16_t integer. - * - * For example, av_exif_get_tag_id("Orientation") returns 274 (0x0112). - */ -int32_t av_exif_get_tag_id(const char *name); - -/** - * Add an entry to the provided EXIF metadata struct. If one already exists with the provided - * ID, it will set the existing one to have the other information provided. Otherwise, it - * will allocate a new entry. - * - * This function reallocates ifd->entries using av_fast_realloc and allocates (using av_malloc) - * a new value member of the entry, then copies the contents of value into that buffer. - */ -int av_exif_set_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, enum AVTiffDataType type, - uint32_t count, const uint8_t *ifd_lead, uint32_t ifd_offset, const void *value); - -/** - * Also check subdirectories. - */ -#define AV_EXIF_FLAG_RECURSIVE (1 << 0) - -/** - * Get an entry with the tagged ID from the EXIF metadata struct. A pointer to the entry - * will be written into *value. - * - * If the entry was present and returned successfully, a positive number is returned. - * - * The positive number is equal to 1 plus the offset at which the entry was found. If the - * entry was found at the top level, this will be in the range of 1 to the number of entries - * in the IFD (inclusive). If the entry was found in a sub-IFD, then it will be a number greater - * than the number of entries in the top-level IFD. - * - * If the entry was not found, *value is left untouched and zero is returned. - * If an error occurred, a negative AVERROR is returned. - */ -int av_exif_get_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags, AVExifEntry **value); - -/** - * Remove an entry from the provided EXIF metadata struct. - * - * If the entry was present and removed successfully, a positive number is returned. - * - * The positive number is equal to 1 plus the offset at which the entry was found. If the - * entry was found at the top level, this will be in the range of 1 to the number of entries - * in the IFD (inclusive). If the entry was found in a sub-IFD, then it will be a number greater - * than the number of entries in the top-level IFD. This refers to the state of the IFD before - * the entry was removed, e.g. if the last entry is removed, a 1 is returned, but the IFD has - * no entries anymore. - * - * If the entry was not found, zero is returned and the IFD is left untouched. - * If an error occurred, a negative AVERROR is returned. - */ -int av_exif_remove_entry(void *logctx, AVExifMetadata *ifd, uint16_t id, int flags); - -/** - * Decodes the EXIF data provided in the buffer and writes it into the - * struct *ifd. If this function succeeds, the IFD is owned by the caller - * and must be cleared after use by calling av_exif_free(); If this function - * fails and returns a negative value, it will call av_exif_free(ifd) before - * returning. - */ -int av_exif_parse_buffer(void *logctx, const uint8_t *data, size_t size, - AVExifMetadata *ifd, enum AVExifHeaderMode header_mode); - -/** - * Allocates a buffer using av_malloc of an appropriate size and writes the - * EXIF data represented by ifd into that buffer. - * - * Upon error, *buffer will be NULL. The buffer becomes owned by the caller upon - * success. The *buffer argument must be NULL before calling. - */ -int av_exif_write(void *logctx, const AVExifMetadata *ifd, AVBufferRef **buffer, enum AVExifHeaderMode header_mode); - -/** - * Frees all resources associated with the given EXIF metadata struct. - * Does not free the pointer passed itself, in case it is stack-allocated. - * The pointer passed to this function must be freed by the caller, - * if it is heap-allocated. Passing NULL is permitted. - */ -void av_exif_free(AVExifMetadata *ifd); - -/** - * Recursively reads all tags from the IFD and stores them in the - * provided metadata dictionary. - */ -int av_exif_ifd_to_dict(void *logctx, const AVExifMetadata *ifd, AVDictionary **metadata); - -/** - * Allocates a duplicate of the provided EXIF metadata struct. The caller owns - * the duplicate and must free it with av_exif_free. Returns NULL if the duplication - * process failed. - */ -AVExifMetadata *av_exif_clone_ifd(const AVExifMetadata *ifd); - -/** - * Convert a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX - * into an orientation constant used by EXIF's orientation tag. - * - * Returns an EXIF orientation between 1 and 8 (inclusive) depending - * on the rotation and flip factors. Returns 0 if the matrix is singular. - */ -int av_exif_matrix_to_orientation(const int32_t *matrix); - -/** - * Convert an orientation constant used by EXIF's orientation tag - * into a display matrix used by AV_FRAME_DATA_DISPLAYMATRIX. - * - * Returns 0 on success and negative if the orientation is invalid, - * i.e. not between 1 and 8 (inclusive). - */ -int av_exif_orientation_to_matrix(int32_t *matrix, int orientation); - -#endif /* AVCODEC_EXIF_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h index 00774a703..0a2801054 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/packet.h @@ -142,7 +142,7 @@ enum AVPacketSideDataType { AV_PKT_DATA_CPB_PROPERTIES, /** - * Recommends skipping the specified number of samples + * Recommmends skipping the specified number of samples * @code * u32le number of samples to skip from start of this packet * u32le number of samples to skip from end of this packet @@ -345,44 +345,6 @@ enum AVPacketSideDataType { */ AV_PKT_DATA_LCEVC, - /** - * 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_PKT_DATA_3D_REFERENCE_DISPLAYS, - - /** - * Contains the last received RTCP SR (Sender Report) information - * in the form of the AVRTCPSenderReport struct. - */ - AV_PKT_DATA_RTCP_SR, - - /** - * 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_PKT_DATA_EXIF, - - /** - * HDR dynamic metadata associated with a video frame. The payload is an - * AVDynamicHDRSmpte2094App5 type and contains information for color volume - * transform as specified in the SMPTE 2094-50 standard. - */ - AV_PKT_DATA_DYNAMIC_HDR_SMPTE_2094_APP5, - - /** - * Dolby Vision enhancement-layer HEVC decoder configuration. - * Parsed from the @c hvcE box in ISOM-based containers or the - * corresponding BlockAdditionMapping in Matroska. The data is a raw - * HEVCDecoderConfigurationRecord as defined in ISO 14496-15. - */ - AV_PKT_DATA_HEVC_CONF, - /** * The number of side data types. * This is not part of the public API/ABI in the sense that it may @@ -394,6 +356,10 @@ enum AVPacketSideDataType { AV_PKT_DATA_NB }; +#if FF_API_QUALITY_FACTOR +#define AV_PKT_DATA_QUALITY_FACTOR AV_PKT_DATA_QUALITY_STATS //DEPRECATED +#endif + /** * This structure stores auxiliary information for decoding, presenting, or * otherwise processing the coded stream. It is typically exported by demuxers @@ -402,11 +368,11 @@ enum AVPacketSideDataType { * * Global side data is handled as follows: * - During demuxing, it may be exported through - * @ref AVCodecParameters.coded_side_data "AVStream's codec parameters", which can + * @ref AVStream.codecpar.side_data "AVStream's codec parameters", which can * then be passed as input to decoders through the * @ref AVCodecContext.coded_side_data "decoder context's side data", for * initialization. - * - For muxing, it can be fed through @ref AVCodecParameters.coded_side_data + * - For muxing, it can be fed through @ref AVStream.codecpar.side_data * "AVStream's codec parameters", typically the output of encoders through * the @ref AVCodecContext.coded_side_data "encoder context's side data", for * initialization. @@ -504,36 +470,6 @@ void av_packet_side_data_remove(AVPacketSideData *sd, int *nb_sd, */ void av_packet_side_data_free(AVPacketSideData **sd, int *nb_sd); -struct AVFrameSideData; - -/** - * Add a new packet side data entry to an array based on existing frame - * side data, if a matching type exists for packet side data. - * - * @param flags Currently unused. Must be 0. - * @retval >= 0 Success - * @retval AVERROR(EINVAL) The frame side data type does not have a matching - * packet side data type. - * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or - * similar. - */ -int av_packet_side_data_from_frame(AVPacketSideData **sd, int *nb_sd, - const struct AVFrameSideData *src, unsigned int flags); -/** - * Add a new frame side data entry to an array based on existing packet - * side data, if a matching type exists for frame side data. - * - * @param flags Some combination of AV_FRAME_SIDE_DATA_FLAG_* flags, - * or 0. - * @retval >= 0 Success - * @retval AVERROR(EINVAL) The packet side data type does not have a matching - * frame side data type. - * @retval AVERROR(ENOMEM) Failed to add a side data entry to the array, or - * similar. - */ -int av_packet_side_data_to_frame(struct AVFrameSideData ***sd, int *nb_sd, - const AVPacketSideData *src, unsigned int flags); - const char *av_packet_side_data_name(enum AVPacketSideDataType type); /** @@ -647,6 +583,14 @@ typedef struct AVPacket { AVRational time_base; } AVPacket; +#if FF_API_INIT_PACKET +attribute_deprecated +typedef struct AVPacketList { + AVPacket pkt; + struct AVPacketList *next; +} AVPacketList; +#endif + #define AV_PKT_FLAG_KEY 0x0001 ///< The packet contains a keyframe #define AV_PKT_FLAG_CORRUPT 0x0002 ///< The packet content is corrupted /** @@ -824,7 +768,7 @@ uint8_t* av_packet_get_side_data(const AVPacket *pkt, enum AVPacketSideDataType * @param size pointer to store the size of the returned data * @return pointer to data if successful, NULL otherwise */ -uint8_t *av_packet_pack_dictionary(const AVDictionary *dict, size_t *size); +uint8_t *av_packet_pack_dictionary(AVDictionary *dict, size_t *size); /** * Unpack a dictionary from side_data. * @@ -936,13 +880,6 @@ int av_packet_make_writable(AVPacket *pkt); */ void av_packet_rescale_ts(AVPacket *pkt, AVRational tb_src, AVRational tb_dst); -/** - * Allocate an AVContainerFifo instance for AVPacket. - * - * @param flags currently unused - */ -struct AVContainerFifo *av_container_fifo_alloc_avpacket(unsigned flags); - /** * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h deleted file mode 100644 index 9c0e2a5a0..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/smpte_436m.h +++ /dev/null @@ -1,254 +0,0 @@ -/* - * MXF SMPTE-436M VBI/ANC parsing functions - * Copyright (c) 2025 Jacob Lifshay - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_SMPTE_436M_H -#define AVCODEC_SMPTE_436M_H - -#include - -/** - * Iterator over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data - */ -typedef struct AVSmpte436mAncIterator { - uint16_t anc_packets_left; - int size_left; - const uint8_t *data_left; -} AVSmpte436mAncIterator; - -/** - * Wrapping Type from Table 7 (page 13) of: - * https://pub.smpte.org/latest/st436/s436m-2006.pdf - */ -typedef enum AVSmpte436mWrappingType -{ - AV_SMPTE_436M_WRAPPING_TYPE_VANC_FRAME = 1, - AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_1 = 2, - AV_SMPTE_436M_WRAPPING_TYPE_VANC_FIELD_2 = 3, - AV_SMPTE_436M_WRAPPING_TYPE_VANC_PROGRESSIVE_FRAME = 4, - AV_SMPTE_436M_WRAPPING_TYPE_HANC_FRAME = 0x11, - AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_1 = 0x12, - AV_SMPTE_436M_WRAPPING_TYPE_HANC_FIELD_2 = 0x13, - AV_SMPTE_436M_WRAPPING_TYPE_HANC_PROGRESSIVE_FRAME = 0x14, - /** not a real wrapping type, just here to guarantee the enum is big enough */ - AV_SMPTE_436M_WRAPPING_TYPE_MAX = 0xFF, -} AVSmpte436mWrappingType; - -/** - * Payload Sample Coding from Table 4 (page 10) and Table 7 (page 13) of: - * https://pub.smpte.org/latest/st436/s436m-2006.pdf - */ -typedef enum AVSmpte436mPayloadSampleCoding -{ - /** only used for VBI */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA = 1, - /** only used for VBI */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_COLOR_DIFF = 2, - /** only used for VBI */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_1BIT_LUMA_AND_COLOR_DIFF = 3, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA = 4, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF = 5, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF = 6, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA = 7, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_COLOR_DIFF = 8, - /** used for VBI and ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_10BIT_LUMA_AND_COLOR_DIFF = 9, - /** only used for ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_WITH_PARITY_ERROR = 10, - /** only used for ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_COLOR_DIFF_WITH_PARITY_ERROR = 11, - /** only used for ANC */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_8BIT_LUMA_AND_COLOR_DIFF_WITH_PARITY_ERROR = 12, - /** not a real sample coding, just here to guarantee the enum is big enough */ - AV_SMPTE_436M_PAYLOAD_SAMPLE_CODING_MAX = 0xFF, -} AVSmpte436mPayloadSampleCoding; - -/** the payload capacity of AVSmpte291mAnc8bit (and of AVSmpte291mAnc10bit when that gets added) */ -#define AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY 0xFF - -/** - * An ANC packet with an 8-bit payload. - * This can be decoded from AVSmpte436mCodedAnc::payload. - * - * Note: Some ANC packets need a 10-bit payload, if stored in this struct, - * the most-significant 2 bits of each sample are discarded. - */ -typedef struct AVSmpte291mAnc8bit { - uint8_t did; - uint8_t sdid_or_dbn; - uint8_t data_count; - uint8_t payload[AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY]; - uint8_t checksum; -} AVSmpte291mAnc8bit; - -/** max number of samples that can be stored in the payload of AVSmpte436mCodedAnc */ -#define AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY \ - (AV_SMPTE_291M_ANC_PAYLOAD_CAPACITY + 4) /* 4 for did, sdid_or_dbn, data_count, and checksum */ -/** max number of bytes that can be stored in the payload of AVSmpte436mCodedAnc */ -#define AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY (((AV_SMPTE_436M_CODED_ANC_SAMPLE_CAPACITY + 2) / 3) * 4) - -/** - * An encoded ANC packet within a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. - * The repeated section of Table 7 (page 13) of: - * https://pub.smpte.org/latest/st436/s436m-2006.pdf - */ -typedef struct AVSmpte436mCodedAnc { - uint16_t line_number; - AVSmpte436mWrappingType wrapping_type; - AVSmpte436mPayloadSampleCoding payload_sample_coding; - uint16_t payload_sample_count; - uint32_t payload_array_length; - /** the payload, has size payload_array_length. - * can be decoded into AVSmpte291mAnc8bit - */ - uint8_t payload[AV_SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY]; -} AVSmpte436mCodedAnc; - -/** - * Validate a AVSmpte436mCodedAnc structure. Doesn't check if the payload is valid. - * @param[in] anc ANC packet to validate - * @return 0 on success, AVERROR codes otherwise. - */ -int av_smpte_436m_coded_anc_validate(const AVSmpte436mCodedAnc *anc); - -/** - * Encode ANC packets into a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. - * @param[in] anc_packet_count number of ANC packets to encode - * @param[in] anc_packets the ANC packets to encode - * @param[in] size the size of out. ignored if out is NULL. - * @param[out] out Output bytes. Doesn't write anything if out is NULL. - * @return the number of bytes written on success, AVERROR codes otherwise. - * If out is NULL, returns the number of bytes it would have written. - */ -int av_smpte_436m_anc_encode(uint8_t *out, int size, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); - -struct AVPacket; - -/** - * Append more ANC packets to a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. - * @param[in] anc_packet_count number of ANC packets to encode - * @param[in] anc_packets the ANC packets to encode - * @param pkt the AVPacket to append to. - * it must either be size 0 or contain valid SMPTE_436M_ANC data. - * @return 0 on success, AVERROR codes otherwise. - */ -int av_smpte_436m_anc_append(struct AVPacket *pkt, int anc_packet_count, const AVSmpte436mCodedAnc *anc_packets); - -/** - * Set up iteration over the ANC packets in a single AV_CODEC_ID_SMPTE_436M_ANC AVPacket's data. - * @param[in] buf Pointer to the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. - * @param[in] buf_size Size of the data from a AV_CODEC_ID_SMPTE_436M_ANC AVPacket. - * @param[out] iter Pointer to the iterator. - * @return 0 on success, AVERROR codes otherwise. - */ -int av_smpte_436m_anc_iter_init(AVSmpte436mAncIterator *iter, const uint8_t *buf, int buf_size); - -/** - * Get the next ANC packet from the iterator, advancing the iterator. - * @param[in,out] iter Pointer to the iterator. - * @param[out] anc The returned ANC packet. - * @return 0 on success, AVERROR_EOF when the iterator has reached the end, AVERROR codes otherwise. - */ -int av_smpte_436m_anc_iter_next(AVSmpte436mAncIterator *iter, AVSmpte436mCodedAnc *anc); - -/** - * Get the minimum number of bytes needed to store a AVSmpte436mCodedAnc payload. - * @param sample_coding the payload sample coding - * @param sample_count the number of samples stored in the payload - * @return returns the minimum number of bytes needed, on error returns < 0. - * always <= SMPTE_436M_CODED_ANC_PAYLOAD_CAPACITY - */ -int av_smpte_436m_coded_anc_payload_size(AVSmpte436mPayloadSampleCoding sample_coding, uint16_t sample_count); - -/** - * Decode a AVSmpte436mCodedAnc payload into AVSmpte291mAnc8bit - * @param[in] sample_coding the payload sample coding - * @param[in] sample_count the number of samples stored in the payload - * @param[in] payload the bytes storing the payload, - * the needed size can be obtained from - avpriv_smpte_436m_coded_anc_payload_size - * @param[in] log_ctx context pointer for av_log - * @param[out] out The decoded ANC packet. - * @return returns 0 on success, otherwise < 0. - */ -int av_smpte_291m_anc_8bit_decode(AVSmpte291mAnc8bit *out, - AVSmpte436mPayloadSampleCoding sample_coding, - uint16_t sample_count, - const uint8_t *payload, - void *log_ctx); - -/** - * Fill in the correct checksum for a AVSmpte291mAnc8bit - * @param[in,out] anc The ANC packet. - */ -void av_smpte_291m_anc_8bit_fill_checksum(AVSmpte291mAnc8bit *anc); - -/** - * Compute the sample count needed to encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc payload - * @param[in] anc The ANC packet. - * @param[in] sample_coding The sample coding. - * @param[in] log_ctx context pointer for av_log - * @return returns the sample count on success, otherwise < 0. - */ -int av_smpte_291m_anc_8bit_get_sample_count(const AVSmpte291mAnc8bit *anc, - AVSmpte436mPayloadSampleCoding sample_coding, - void *log_ctx); - -/** - * Encode a AVSmpte291mAnc8bit into a AVSmpte436mCodedAnc - * @param[in] line_number the line number the ANC packet is on - * @param[in] wrapping_type the wrapping type - * @param[in] sample_coding the payload sample coding - * @param[in] payload the ANC packet to encode. - * @param[in] log_ctx context pointer for av_log - * @param[out] out The encoded ANC packet. - * @return returns 0 on success, otherwise < 0. - */ -int av_smpte_291m_anc_8bit_encode(AVSmpte436mCodedAnc *out, - uint16_t line_number, - AVSmpte436mWrappingType wrapping_type, - AVSmpte436mPayloadSampleCoding sample_coding, - const AVSmpte291mAnc8bit *payload, - void *log_ctx); - -/** AVSmpte291mAnc8bit::did when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ -#define AV_SMPTE_291M_ANC_DID_CTA_708 0x61 - -/** AVSmpte291mAnc8bit::sdid_or_dbn when carrying CTA-708 data (for AV_CODEC_ID_EIA_608) */ -#define AV_SMPTE_291M_ANC_SDID_CTA_708 0x1 - -/** - * Try to decode an ANC packet into EIA-608/CTA-708 data (AV_CODEC_ID_EIA_608). This - * @param[in] anc The ANC packet. - * @param[in] log_ctx Context pointer for av_log - * @param[out] cc_data the buffer to store the extracted EIA-608/CTA-708 data, - * you can pass NULL to not store the data. - * the required size is 3 * cc_count bytes. - * SMPTE_291M_ANC_PAYLOAD_CAPACITY is always enough size. - * @return returns cc_count (>= 0) on success, AVERROR(EAGAIN) if it wasn't a CTA-708 ANC packet, < 0 on error. - */ -int av_smpte_291m_anc_8bit_extract_cta_708(const AVSmpte291mAnc8bit *anc, uint8_t *cc_data, void *log_ctx); - -#endif /* AVCODEC_SMPTE_436M_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h index da77c5dae..8021c2576 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/vdpau.h @@ -93,6 +93,28 @@ typedef struct AVVDPAUContext { AVVDPAU_Render2 render2; } AVVDPAUContext; +#if FF_API_VDPAU_ALLOC_GET_SET +/** + * @brief allocation function for AVVDPAUContext + * + * Allows extending the struct without breaking API/ABI + * @deprecated use av_vdpau_bind_context() instead + */ +attribute_deprecated +AVVDPAUContext *av_alloc_vdpaucontext(void); + +/** + * @deprecated render2 is public and can be accessed directly + */ +attribute_deprecated +AVVDPAU_Render2 av_vdpau_hwaccel_get_render2(const AVVDPAUContext *); +/** + * @deprecated render2 is public and can be accessed directly + */ +attribute_deprecated +void av_vdpau_hwaccel_set_render2(AVVDPAUContext *, AVVDPAU_Render2); +#endif + /** * Associate a VDPAU device with a codec context for hardware acceleration. * This function is meant to be called from the get_format() codec callback, @@ -133,6 +155,17 @@ int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, int av_vdpau_get_surface_parameters(AVCodecContext *avctx, VdpChromaType *type, uint32_t *width, uint32_t *height); +#if FF_API_VDPAU_ALLOC_GET_SET +/** + * Allocate an AVVDPAUContext. + * + * @return Newly-allocated AVVDPAUContext or NULL on failure. + * @deprecated use av_vdpau_bind_context() instead + */ +attribute_deprecated +AVVDPAUContext *av_vdpau_alloc_context(void); +#endif + /** @} */ #endif /* AVCODEC_VDPAU_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h index 7acb261bb..4b7ec515f 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version.h @@ -29,7 +29,7 @@ #include "version_major.h" -#define LIBAVCODEC_VERSION_MINOR 7 +#define LIBAVCODEC_VERSION_MINOR 19 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h index 166646eb6..63df40e9d 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavcodec/version_major.h @@ -25,7 +25,7 @@ * Libavcodec version macros. */ -#define LIBAVCODEC_VERSION_MAJOR 63 +#define LIBAVCODEC_VERSION_MAJOR 61 /** * FF_API_* defines may be placed below to indicate public API that will be @@ -37,9 +37,16 @@ * at once through the bump. This improves the git bisect-ability of the change. */ -#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 64) +#define FF_API_INIT_PACKET (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_SUBFRAMES (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_TICKS_PER_FRAME (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_DROPCHANGED (LIBAVCODEC_VERSION_MAJOR < 62) -#define FF_API_INTRA_DC_PRECISION (LIBAVCODEC_VERSION_MAJOR < 64) -#define FF_API_MJPEG_EXTERN_HUFF (LIBAVCODEC_VERSION_MAJOR < 64) +#define FF_API_AVFFT (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_FF_PROFILE_LEVEL (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_AVCODEC_CLOSE (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_BUFFER_MIN_SIZE (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_VDPAU_ALLOC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 62) +#define FF_API_QUALITY_FACTOR (LIBAVCODEC_VERSION_MAJOR < 62) #endif /* AVCODEC_VERSION_MAJOR_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h index cd4c4338c..04c615c95 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/attributes.h @@ -40,35 +40,8 @@ # 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 - -#if AV_HAS_STD_ATTRIBUTE(fallthrough) -# define av_fallthrough [[fallthrough]] -#elif AV_HAS_ATTRIBUTE(fallthrough) -# define av_fallthrough __attribute__((fallthrough)) -#else -# define av_fallthrough do {} while(0) -#endif - #ifndef av_always_inline -#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) +#if AV_GCC_VERSION_AT_LEAST(3,1) # define av_always_inline __attribute__((always_inline)) inline #elif defined(_MSC_VER) # define av_always_inline __forceinline @@ -85,15 +58,13 @@ #endif #endif -#if AV_HAS_STD_ATTRIBUTE(nodiscard) -# define av_warn_unused_result [[nodiscard]] -#elif AV_GCC_VERSION_AT_LEAST(3,4) || defined(__clang__) +#if AV_GCC_VERSION_AT_LEAST(3,4) # 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__) +#if AV_GCC_VERSION_AT_LEAST(3,1) # define av_noinline __attribute__((noinline)) #elif defined(_MSC_VER) # define av_noinline __declspec(noinline) @@ -119,15 +90,13 @@ # define av_cold #endif -#if (AV_GCC_VERSION_AT_LEAST(4,1) && !defined(__clang__ )) || AV_HAS_ATTRIBUTE(flatten) +#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__) +#if AV_GCC_VERSION_AT_LEAST(3,1) # define attribute_deprecated __attribute__((deprecated)) #elif defined(_MSC_VER) # define attribute_deprecated __declspec(deprecated) @@ -158,9 +127,7 @@ #endif #endif -#if AV_HAS_STD_ATTRIBUTE(maybe_unused) -# define av_unused [[maybe_unused]] -#elif defined(__GNUC__) || defined(__clang__) +#if defined(__GNUC__) || defined(__clang__) # define av_unused __attribute__((unused)) #else # define av_unused @@ -191,42 +158,13 @@ #if defined(__GNUC__) || defined(__clang__) # define av_builtin_constant_p __builtin_constant_p +# define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) #else # define av_builtin_constant_p(x) 0 -#endif - -// for __MINGW_PRINTF_FORMAT and __MINGW_SCANF_FORMAT -#ifdef __MINGW32__ -# include -#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__) +#if AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__) # define av_noreturn __attribute__((noreturn)) #else # define av_noreturn diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h index e316a3c90..1895fb755 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avassert.h @@ -31,10 +31,8 @@ #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. @@ -64,62 +62,17 @@ */ #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(cond) ((void)0) #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 -#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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h index 17f7b03db..fc095349d 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avstring.h @@ -419,7 +419,7 @@ 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); +int av_sscanf(const char *string, const char *format, ...); /** * @} diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h index 003a63b7b..d2900dcb4 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/avutil.h @@ -41,6 +41,7 @@ * @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 lpp "libpostproc" post processing library * @li @ref libsws "libswscale" color conversion and scaling library * * @section ffmpeg_versioning Versioning and compatibility @@ -313,6 +314,27 @@ static inline void *av_x_if_null(const void *p, const void *x) return (void *)(intptr_t)(p ? p : x); } +/** + * 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 + */ +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) + /** * Return the fractional representation of the internal time base. */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h index c1e6591ce..f53e5768a 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/bswap.h @@ -68,7 +68,7 @@ static av_always_inline av_const uint32_t av_bswap32(uint32_t x) #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)); + return (uint64_t)av_bswap32(x) << 32 | av_bswap32(x >> 32); } #endif diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h index 5ad2d5ed9..3a96c2d9b 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/channel_layout.h @@ -45,7 +45,7 @@ */ enum AVChannel { - /// Invalid channel index + ///< Invalid channel index AV_CHAN_NONE = -1, AV_CHAN_FRONT_LEFT, AV_CHAN_FRONT_RIGHT, @@ -84,9 +84,6 @@ enum AVChannel { 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, @@ -206,8 +203,6 @@ enum AVChannelOrder { #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 ) /** * @} @@ -240,20 +235,17 @@ enum AVChannelOrder { #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_5POINT1POINT4_BACK (AV_CH_LAYOUT_5POINT1POINT2_BACK|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_22POINT2 (AV_CH_LAYOUT_7POINT1POINT4_BACK|AV_CH_FRONT_LEFT_OF_CENTER|AV_CH_FRONT_RIGHT_OF_CENTER|AV_CH_BACK_CENTER|AV_CH_LOW_FREQUENCY_2|AV_CH_TOP_FRONT_CENTER|AV_CH_TOP_CENTER|AV_CH_TOP_SIDE_LEFT|AV_CH_TOP_SIDE_RIGHT|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 @@ -307,7 +299,7 @@ typedef struct AVChannelCustom { * - 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() + * The channel layout must be unitialized 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 @@ -365,7 +357,7 @@ typedef struct AVChannelLayout { * * 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. + * convenience functions below. Otherise it must be zeroed. */ AVChannelCustom *map; } u; @@ -417,7 +409,6 @@ typedef struct AVChannelLayout { #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) @@ -426,9 +417,7 @@ typedef struct AVChannelLayout { #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) diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h index cba78c5fd..3b830daf3 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/common.h @@ -297,6 +297,17 @@ static av_always_inline av_const unsigned av_zero_extend_c(unsigned a, unsigned 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. * @@ -475,13 +486,13 @@ static av_always_inline av_const int av_parity_c(uint32_t v) * to prevent undefined results. */ #define GET_UTF8(val, GET_BYTE, ERROR)\ - val= (uint8_t)(GET_BYTE);\ + val= (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;\ + unsigned int tmp = (GET_BYTE) - 128;\ if(tmp>>6)\ {ERROR}\ val= (val<<6) + tmp;\ @@ -500,11 +511,11 @@ static av_always_inline av_const int av_parity_c(uint32_t v) * typically a goto statement. */ #define GET_UTF16(val, GET_16BIT, ERROR)\ - val = (uint16_t)(GET_16BIT);\ + val = (GET_16BIT);\ {\ unsigned int hi = val - 0xD800;\ if (hi < 0x800) {\ - val = (uint16_t)(GET_16BIT) - 0xDC00;\ + val = (GET_16BIT) - 0xDC00;\ if (val > 0x3FFU || hi > 0x3FFU)\ {ERROR}\ val += (hi<<10) + 0x10000;\ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h deleted file mode 100644 index ff9249311..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/container_fifo.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - -/** - * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h index c41686344..ba6c234e0 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/cpu.h @@ -24,9 +24,7 @@ #include #include "version.h" -#if FF_API_CPU_FLAG_FORCE -#define AV_CPU_FLAG_FORCE 0x80000000 /* @deprecated, should not be used */ -#endif +#define AV_CPU_FLAG_FORCE 0x80000000 /* force usage of selected flags (OR) */ /* lower 16 bits - CPU features */ #define AV_CPU_FLAG_MMX 0x0001 ///< standard MMX @@ -47,7 +45,6 @@ #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 @@ -75,15 +72,7 @@ #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_PMULL (1 <<17) -#define AV_CPU_FLAG_EOR3 (1 <<18) #define AV_CPU_FLAG_MMI (1 << 0) #define AV_CPU_FLAG_MSA (1 << 1) @@ -94,18 +83,22 @@ // 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 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h index 9d75ccbb6..73bce52bc 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/csp.h @@ -81,12 +81,8 @@ typedef struct AVColorPrimariesDesc { } 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. + * Function pointer representing a double -> double transfer function that performs + * an EOTF transfer inversion. This function outputs linear light. */ typedef double (*av_csp_trc_function)(double); @@ -114,7 +110,7 @@ const AVColorPrimariesDesc *av_csp_primaries_desc_from_id(enum AVColorPrimaries * @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. + * AVCOL_PRI_UNSPECIFIED if no clear match can be idenitified. */ enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc *prm); @@ -133,22 +129,6 @@ enum AVColorPrimaries av_csp_primaries_id_from_desc(const AVColorPrimariesDesc * */ 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. @@ -163,44 +143,6 @@ double av_csp_approximate_eotf_gamma(enum AVColorTransferCharacteristic trc); */ 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); - /** * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h index 93c7cbf12..713c9e361 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dict.h @@ -82,7 +82,6 @@ #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. */ /** * @} */ @@ -225,7 +224,7 @@ void av_dict_free(AVDictionary **m); * @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. + * @param[out] buffer Pointer to buffer that will be allocated with string containg 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 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h index c102bf384..5e8a1e43d 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/dovi_meta.h @@ -279,20 +279,12 @@ 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 { @@ -377,10 +369,6 @@ 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) { diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h index cc0eafe94..221cf5bf9 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/downmix_info.h @@ -21,7 +21,6 @@ #ifndef AVUTIL_DOWNMIX_INFO_H #define AVUTIL_DOWNMIX_INFO_H -#include "avassert.h" #include "frame.h" /** @@ -105,70 +104,6 @@ typedef struct AVDownmixInfo { */ AVDownmixInfo *av_downmix_info_update_side_data(AVFrame *frame); -/** - * This structure describes optional metadata relevant to a downmix procedure - * in the form of a remixing matrix allocated as an array of AVDownmixCoeff. - * Must be allocated with @ref av_downmix_matrix_alloc. - * - * sizeof(AVDownmixMatrix) is not a part of the ABI and new fields may be - * added to it. - */ -typedef struct AVDownmixMatrix { - /** - * Type of downmix the coeffs will produce. - * Output channel count is derived from this value. - */ - enum AVDownmixType downmix_type; - - /** - * Input channel count. - */ - int in_ch_count; - - /** - * Amount of coefficients in the matrix. - */ - unsigned int nb_coeffs; - - /** - * Offset in bytes from the beginning of this structure at which the array - * of coefficients starts. - */ - size_t coeffs_offset; -} AVDownmixMatrix; - -/** - * Data type for storing coefficients, which are allocated as a part of - * AVDownmixMatrix and should be retrieved with @ref av_downmix_matrix_coeff. - */ -typedef double AVDownmixCoeff; - -/** - * Get a pointer to the coeff that represents the weight of input channel - * {@code in} in output channel {@code out}. - * in must be between 0 and @ref AVDownmixMatrix.in_ch_count "in_ch_count" - 1. - * out must be between 0 and the implicit output channel count from - * @ref AVDownmixMatrix.downmix_type "downmix_type" - 1. - */ -static av_always_inline AVDownmixCoeff* -av_downmix_matrix_coeff(AVDownmixMatrix *dm, unsigned int out, unsigned int in) -{ - AVDownmixCoeff *coeff = (AVDownmixCoeff *)((uint8_t *)dm + dm->coeffs_offset); - return &coeff[in + dm->in_ch_count * out]; -} - -/** - * Allocates memory for AVDownmixMatrix of the given type, plus an array of - * {@code in_ch_count} times the implicit output channel count from {@code type} - * of AVDownmixCoeff 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. - */ -AVDownmixMatrix *av_downmix_matrix_alloc(enum AVDownmixType type, - int in_ch_count, size_t *out_size); - /** * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h index b9446dabd..0f9452a4f 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/ffversion.h @@ -1,5 +1,5 @@ /* Automatically generated by version.sh, do not manually edit! */ #ifndef AVUTIL_FFVERSION_H #define AVUTIL_FFVERSION_H -#define FFMPEG_VERSION "N-125978-g95c43d7df7-20260806" +#define FFMPEG_VERSION "7.1" #endif /* AVUTIL_FFVERSION_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h index 2915611c9..ccacab88f 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/film_grain_params.h @@ -124,7 +124,7 @@ typedef struct AVFilmGrainAOMParams { /** * This structure describes how to handle film grain synthesis for codecs using - * the ITU-T H.274 Versatile supplemental enhancement information message. + * the ITU-T H.274 Versatile suplemental 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. @@ -136,6 +136,43 @@ typedef struct AVFilmGrainH274Params { */ int model_id; +#if FF_API_H274_FILM_GRAIN_VCS + /** + * TODO: On this ABI bump, please also re-order the fields in + * AVFilmGrainParams (see below) + */ + + /** + * Specifies the bit depth used for the luma component. + * + * @deprecated use AVFilmGrainParams.bit_depth_luma. + */ + attribute_deprecated + int bit_depth_luma; + + /** + * Specifies the bit depth used for the chroma components. + * + * @deprecated use AVFilmGrainParams.bit_depth_chroma. + */ + attribute_deprecated + int bit_depth_chroma; + + /** + * Specifies the video signal characteristics. + * + * @deprecated use AVFilmGrainParams.color_{range,primaries,trc,space}. + */ + attribute_deprecated + enum AVColorRange color_range; + attribute_deprecated + enum AVColorPrimaries color_primaries; + attribute_deprecated + enum AVColorTransferCharacteristic color_trc; + attribute_deprecated + enum AVColorSpace color_space; +#endif + /** * Specifies the blending mode used to blend the simulated film grain * with the decoded images. @@ -212,6 +249,18 @@ typedef struct AVFilmGrainParams { */ uint64_t seed; + /** + * 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. + * + * TODO: Move this to the end of the structure, at the next ABI bump. + */ + union { + AVFilmGrainAOMParams aom; + AVFilmGrainH274Params h274; + } codec; + /** * Intended display resolution. May be 0 if the codec does not specify * any restrictions. @@ -238,15 +287,6 @@ typedef struct AVFilmGrainParams { 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; /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h index e8cc765e5..f7806566d 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/frame.h @@ -96,7 +96,7 @@ enum AVFrameSideDataType { */ AV_FRAME_DATA_MOTION_VECTORS, /** - * Recommends skipping the specified number of samples. This is exported + * Recommmends 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 @@ -243,68 +243,6 @@ enum AVFrameSideDataType { * 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, - - /** - * Exchangeable image file format metadata. The payload is a buffer containing - * EXIF metadata, starting with either 49 49 2a 00, or 4d 4d 00 2a. These four - * bytes signify the endianness, and occur as the first part of the TIFF header. - */ - AV_FRAME_DATA_EXIF, - - /** - * HDR dynamic metadata associated with a video frame. The payload is - * an AVDynamicHDRSmpte2094App5 type and contains information for color - * volume transform as specified in the SMPTE 2094-50 standard. - */ - AV_FRAME_DATA_DYNAMIC_HDR_SMPTE_2094_APP5, - - /** - * IAMF Mix Gain Parameter Data associated with the audio frame. This metadata - * is in the form of the AVIAMFParamDefinition struct and contains information - * defined in sections 3.6.1 and 3.8.1 of the Immersive Audio Model and - * Formats standard. - */ - AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM, - - /** - * IAMF Demixing Info Parameter Data associated with the audio frame. This - * metadata is in the form of the AVIAMFParamDefinition struct and contains - * information defined in sections 3.6.1 and 3.8.2 of the Immersive Audio Model - * and Formats standard. - */ - AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM, - - /** - * IAMF Recon Gain Info Parameter Data associated with the audio frame. This - * metadata is in the form of the AVIAMFParamDefinition struct and contains - * information defined in sections 3.6.1 and 3.8.3 of the Immersive Audio Model - * and Formats standard. - */ - AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM, - - /** - * Color information from a RAW camera codecs, needed to correctly process - * the video data. The payload is an AVRawColorParams struct defined in - * libavutil/raw_color_params.h. - */ - AV_FRAME_DATA_RAW_COLOR_PARAMS, - - /** - * Metadata relevant to a downmix procedure in the form of a remixig matrix. - * The data is the AVDownmixMatrix struct defined in libavutil/downmix_info.h. - */ - AV_FRAME_DATA_DOWNMIX_MATRIX, }; enum AVActiveFormatDescription { @@ -345,27 +283,6 @@ enum AVSideDataProps { * 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), }; /** @@ -558,6 +475,16 @@ typedef struct AVFrame { */ int format; +#if FF_API_FRAME_KEY + /** + * 1 -> keyframe, 0-> not + * + * @deprecated Use AV_FRAME_FLAG_KEY instead + */ + attribute_deprecated + int key_frame; +#endif + /** * Picture type of the frame. */ @@ -629,6 +556,32 @@ typedef struct AVFrame { */ int repeat_pict; +#if FF_API_INTERLACED_FRAME + /** + * The content of the picture is interlaced. + * + * @deprecated Use AV_FRAME_FLAG_INTERLACED instead + */ + attribute_deprecated + int interlaced_frame; + + /** + * If the content is interlaced, is top field displayed first. + * + * @deprecated Use AV_FRAME_FLAG_TOP_FIELD_FIRST instead + */ + attribute_deprecated + int top_field_first; +#endif + +#if FF_API_PALETTE_HAS_CHANGED + /** + * Tell user application that palette has changed from previous frame. + */ + attribute_deprecated + int palette_has_changed; +#endif + /** * Sample rate of the audio data. */ @@ -698,14 +651,6 @@ typedef struct AVFrame { * 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) /** * @} */ @@ -742,6 +687,18 @@ typedef struct AVFrame { */ int64_t best_effort_timestamp; +#if FF_API_FRAME_PKT + /** + * reordered pos from the last AVPacket that has been input into the decoder + * - encoding: unused + * - decoding: Read by user. + * @deprecated use AV_CODEC_FLAG_COPY_OPAQUE to pass through arbitrary user + * data from packets to frames + */ + attribute_deprecated + int64_t pkt_pos; +#endif + /** * metadata. * - encoding: Set by user. @@ -762,6 +719,20 @@ typedef struct AVFrame { #define FF_DECODE_ERROR_CONCEALMENT_ACTIVE 4 #define FF_DECODE_ERROR_DECODE_SLICES 8 +#if FF_API_FRAME_PKT + /** + * size of the corresponding packet containing the compressed + * frame. + * It is set to a negative value if unknown. + * - encoding: unused + * - decoding: set by libavcodec, read by user. + * @deprecated use AV_CODEC_FLAG_COPY_OPAQUE to pass through arbitrary user + * data from packets to frames + */ + attribute_deprecated + int pkt_size; +#endif + /** * For hwaccel-format frames, this should be a reference to the * AVHWFramesContext describing the frame. @@ -787,7 +758,7 @@ typedef struct AVFrame { /** * @anchor cropping * @name Cropping - * Video frames only. The number of pixels to discard from the + * Video frames only. The number of pixels to discard from the the * top/bottom/left/right border of the frame to obtain the sub-rectangle of * the frame intended for presentation. * @{ @@ -801,13 +772,17 @@ typedef struct AVFrame { */ /** - * RefStruct reference for internal use by a single libav* library. + * AVBufferRef 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. + * Code outside the FFmpeg libs should never check or change the contents of the buffer ref. + * + * FFmpeg calls av_buffer_unref() on it when the frame is unreferenced. + * av_frame_copy_props() calls create a new reference with av_buffer_ref() + * for the target frame's private_ref field. */ - void *private_ref; + AVBufferRef *private_ref; /** * Channel layout of the audio data. @@ -818,13 +793,6 @@ typedef struct AVFrame { * 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; @@ -870,7 +838,7 @@ 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. + * src is not reference counted, or by unrefencing it if src is empty. * * Frame properties on dst will be replaced by those from src. * @@ -919,10 +887,9 @@ void av_frame_move_ref(AVFrame *dst, AVFrame *src); * 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. + * @param align Required buffer size 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. */ @@ -1096,11 +1063,6 @@ void av_frame_side_data_free(AVFrameSideData ***sd, int *nb_sd); * 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. @@ -1206,14 +1168,6 @@ const AVFrameSideData *av_frame_side_data_get(AVFrameSideData * const *sd, */ 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); - /** * @} */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h index a051ac747..5100ed6f4 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_metadata.h @@ -373,108 +373,4 @@ int av_dynamic_hdr_plus_from_t35(AVDynamicHDRPlus *s, const uint8_t *data, */ int av_dynamic_hdr_plus_to_t35(const AVDynamicHDRPlus *s, uint8_t **data, size_t *size); -/** - * This struct represents dynamic metadata for color volume transform as - * specified in the SMPTE 2094-50 standard. - * - * To be used as payload of a AVFrameSideData or AVPacketSideData with the - * appropriate type. - * - * @note The struct should be allocated with - * av_dynamic_smpte2094_app5_alloc() and its size is not a part of - * the public ABI. - */ -typedef struct AVDynamicHDRSmpte2094App5 { - /** - * Section C.2.1. smpte_st_2094_50_application_info() - */ - uint8_t application_version; - uint8_t minimum_application_version; - - /** - * Section C.2.2 smpte_st_2094_50_color_volume_transform() - */ - uint8_t has_custom_hdr_reference_white_flag; - uint8_t has_adaptive_tone_map_flag; - uint16_t hdr_reference_white; - - /** - * Section C.2.3 smpte_st_2094_50_adaptive_tone_map() - */ - uint16_t baseline_hdr_headroom; - uint8_t use_reference_white_tone_mapping_flag; - uint8_t num_alternate_images; - uint8_t gain_application_space_chromaticities_flag; - uint8_t has_common_component_mix_params_flag; - uint8_t has_common_curve_params_flag; - uint16_t gain_application_space_chromaticities[8]; - uint16_t alternate_hdr_headrooms[4]; - - /** - * Section C.2.4 smpte_st_2094_50_component_mixing() - */ - uint8_t component_mixing_type[4]; - uint8_t has_component_mixing_coefficient_flag[4][6]; - uint16_t component_mixing_coefficient[4][6]; - - /** - * Section C.2.5 smpte_st_2094_50_gain_curve() - */ - uint8_t gain_curve_num_control_points_minus_1[4]; - uint8_t gain_curve_use_pchip_slope_flag[4]; - uint16_t gain_curve_control_points_x[4][32]; - uint16_t gain_curve_control_points_y[4][32]; - uint16_t gain_curve_control_points_theta[4][32]; -} AVDynamicHDRSmpte2094App5; - -/** - * Allocate an AVDynamicHDRSmpte2094App5 structure and set its fields to - * default values. The resulting struct can be freed using av_freep(). - * - * @return An AVDynamicHDRSmpte2094App5 filled with default values or NULL - * on failure. - */ -AVDynamicHDRSmpte2094App5* av_dynamic_hdr_smpte2094_app5_alloc(size_t* size); - -/** - * Allocate a complete AVDynamicHDRSmpte2094App5 and add it to the frame. - * - * @param frame The frame which side data is added to. - * - * @return The AVDynamicHDRSmpte2094App5 structure to be filled by caller or - * NULL on failure. - */ -AVDynamicHDRSmpte2094App5* av_dynamic_hdr_smpte2094_app5_create_side_data(AVFrame* frame); - -/** - * Parse the user data formatted as ITU-T T.35 message to AVDynamicHDRSmpte2094App5. - * - * @param s A pointer containing the decoded AVDynamicHDRSmpte2094App5 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_smpte2094_app5_from_t35(AVDynamicHDRSmpte2094App5* s, const uint8_t* data, - size_t size); - -/** - * Serialize dynamic SMPTE-2094-50 metadata to a ITU-T T.35 message. Excluding - * the country_code, provider_code and provider_oriented_code. - * - * @param s A pointer containing the AVDynamicHDRSmpte2094App5 data. - * @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_smpte2094_app5_to_t35(const AVDynamicHDRSmpte2094App5* s, uint8_t** data, - size_t* size); - #endif /* AVUTIL_HDR_DYNAMIC_METADATA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h index d45b4a0f6..4524a8155 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hdr_dynamic_vivid_metadata.h @@ -83,7 +83,7 @@ typedef struct AVHDRVividColorToneMappingParams { AVRational targeted_system_display_maximum_luminance; /** - * This flag indicates that transfer the base parameter(for value of 1) + * This flag indicates that transfer the base paramter(for value of 1) */ int base_enable_flag; @@ -145,7 +145,7 @@ typedef struct AVHDRVividColorToneMappingParams { int base_param_k3; /** - * This flag indicates that delta mode of base parameter(for value of 1) + * This flag indicates that delta mode of base paramter(for value of 1) */ int base_param_Delta_enable_mode; @@ -158,7 +158,7 @@ typedef struct AVHDRVividColorToneMappingParams { /** * indicates 3Spline_enable_flag in the base parameter, - * This flag indicates that transfer three Spline of base parameter(for value of 1) + * This flag indicates that transfer three Spline of base paramter(for value of 1) */ int three_Spline_enable_flag; @@ -168,6 +168,60 @@ typedef struct AVHDRVividColorToneMappingParams { */ int three_Spline_num; +#if FF_API_HDR_VIVID_THREE_SPLINE + /** + * The mode of three Spline. the value shall be in the range + * of 0 to 3, inclusive. + * @deprecated Use three_spline instead + */ + attribute_deprecated + int three_Spline_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. + * @deprecated Use three_spline instead + */ + attribute_deprecated + AVRational three_Spline_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. + * @deprecated Use three_spline instead + */ + attribute_deprecated + AVRational three_Spline_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. + * @deprecated Use three_spline instead + */ + attribute_deprecated + AVRational three_Spline_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. + * @deprecated Use three_spline instead + */ + attribute_deprecated + AVRational three_Spline_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. + * @deprecated Use three_spline instead + */ + attribute_deprecated + AVRational three_Spline_enable_Strength; +#endif + AVHDRVivid3SplineParams three_spline[2]; } AVHDRVividColorToneMappingParams; diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h index 29374cf0a..bac30deba 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext.h @@ -38,9 +38,6 @@ enum AVHWDeviceType { AV_HWDEVICE_TYPE_MEDIACODEC, AV_HWDEVICE_TYPE_VULKAN, AV_HWDEVICE_TYPE_D3D12VA, - AV_HWDEVICE_TYPE_AMF, - /* OpenHarmony Codec device */ - AV_HWDEVICE_TYPE_OHCODEC, }; /** @@ -563,7 +560,7 @@ enum { * 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 + * hw_frames_ctx/format fields thay may have been set by the caller - those will * be preserved as they were. * * @param dst Destination frame, to contain the mapping. diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h deleted file mode 100644 index 918eec97b..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_amf.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_AMF_H -#define AVUTIL_HWCONTEXT_AMF_H - -#include "pixfmt.h" -#include "hwcontext.h" -#include -#include -#include -#include -#include -#include "libavutil/mastering_display_metadata.h" - -/** - * This struct is allocated as AVHWDeviceContext.hwctx - */ -typedef struct AVAMFDeviceContext { - void * library; - AMFFactory *factory; - void *trace_writer; - - int64_t version; ///< version of AMF runtime - AMFContext *context; - AMF_MEMORY_TYPE memory_type; - - void (*lock)(void *lock_ctx); - void (*unlock)(void *lock_ctx); - void *lock_ctx; -} AVAMFDeviceContext; - -enum AMF_SURFACE_FORMAT av_av_to_amf_format(enum AVPixelFormat fmt); -enum AVPixelFormat av_amf_to_av_format(enum AMF_SURFACE_FORMAT fmt); - -enum AMF_VIDEO_CONVERTER_COLOR_PROFILE_ENUM av_amf_get_color_profile(enum AVColorRange color_range, enum AVColorSpace color_space); -int av_amf_display_mastering_meta_to_hdrmeta(const AVMasteringDisplayMetadata *display_meta, AMFHDRMetadata *hdrmeta); -int av_amf_light_metadata_to_hdrmeta(const AVContentLightMetadata *light_meta, AMFHDRMetadata *hdrmeta); -int av_amf_extract_hdr_metadata(const AVFrame *frame, AMFHDRMetadata *hdrmeta); -int av_amf_attach_hdr_metadata(AVFrame *frame, const AMFHDRMetadata *hdrmeta); - -#endif /* AVUTIL_HWCONTEXT_AMF_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h index 38e536979..cbad434fe 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_cuda.h @@ -24,8 +24,6 @@ #include #endif -#include - #include "pixfmt.h" /** @@ -48,78 +46,8 @@ typedef struct AVCUDADeviceContext { } AVCUDADeviceContext; /** - * CUDA frame descriptor for pool allocation of AV_PIX_FMT_CUARRAY frames. - * - * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs - * with the data pointer pointing at an object of this type describing the - * planes of the frame. - * - * This has no use outside of custom allocation, and AVFrame AVBufferRef do not - * necessarily point to an instance of this struct. - */ -typedef struct AVCUDAArrayFrameDescriptor { - /** - * The CUarray containing the frame data. - * - * Normally stored in AVFrame.data[0]. - */ - CUarray array; - - /** - * The index into AVCUDAFramesContext.cuarray_surfaces, or 0 if not applicable. - * - * Normally stored in AVFrame.data[1] (cast from intptr_t). - */ - intptr_t index; -} AVCUDAArrayFrameDescriptor; - -/** - * This struct is allocated as AVHWFramesContext.hwctx - */ -typedef struct AVCUDAFramesContext { - /** - * CUDA_ARRAY3D_DESCRIPTOR CUarrays will be initialized with. - * Mostly used to provide external Flags. - * - * Width, Height and Format only honored if != 0. - * Filled with default parameters from the FramesContext otherwise. - * - * Only applicable for AV_PIX_FMT_CUARRAY. - */ - CUDA_ARRAY3D_DESCRIPTOR cuarray_desc; - - /** - * If >0, pre-allocate a fixed pool of surfaces. - * The surfaces will be available via cuarray_surfaces after init. - * Size of the pool cannot be changed afterwards. - * - * Only applicable for AV_PIX_FMT_CUARRAY. - */ - int cuarray_num_surfaces; - - /** - * If cuarray_num_surfaces is >0, this contains the array of pre-allocated surfaces. - * - * Only applicable for AV_PIX_FMT_CUARRAY. - */ - CUarray *cuarray_surfaces; -} AVCUDAFramesContext; - -/** - * CUDA hardware pipeline configuration details. - * - * Passed to av_hwdevice_get_hwframe_constraints() to query - * per-hw-format constraints. When provided, valid_sw_formats - * will be filtered to only those compatible with the specified - * hw_format. + * AVHWFramesContext.hwctx is currently not used */ -typedef struct AVCUDAHWConfig { - /** - * The hardware pixel format to query constraints for. - * Must be AV_PIX_FMT_CUDA or AV_PIX_FMT_CUARRAY. - */ - enum AVPixelFormat hw_format; -} AVCUDAHWConfig; /** * @defgroup hwcontext_cuda Device context creation flags diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h index b87b1e8fa..77d2d72f1 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d11va.h @@ -94,20 +94,6 @@ typedef struct AVD3D11VADeviceContext { void (*lock)(void *lock_ctx); void (*unlock)(void *lock_ctx); void *lock_ctx; - /** - * D3D11_TEXTURE2D_DESC.BindFlags to be applied to D3D11 resources allocated - * for frames using this device context. - * - * It applies globally to all AVD3D11VAFramesContext allocated from this device context. - */ - UINT BindFlags; - /** - * D3D11_TEXTURE2D_DESC.MiscFlags to be applied to D3D11 resources allocated - * for frames using this device context. - * - * It applies globally to all AVD3D11VAFramesContext allocated from this device context. - */ - UINT MiscFlags; } AVD3D11VADeviceContext; /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h index adbec8817..212a6a614 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_d3d12va.h @@ -75,26 +75,6 @@ typedef struct AVD3D12VADeviceContext { void (*lock)(void *lock_ctx); void (*unlock)(void *lock_ctx); void *lock_ctx; - - /** - * Resource flags to be applied to D3D12 resources allocated - * for frames using this device context. - * - * If unset, this will be D3D12_RESOURCE_FLAG_NONE. - * - * It applies globally to all AVD3D12VAFramesContext allocated from this device context. - */ - D3D12_RESOURCE_FLAGS resource_flags; - - /** - * Heap flags to be applied to D3D12 resources allocated - * for frames using this device context. - * - * If unset, this will be D3D12_HEAP_FLAG_NONE. - * - * It applies globally to all AVD3D12VAFramesContext allocated from this device context. - */ - D3D12_HEAP_FLAGS heap_flags; } AVD3D12VADeviceContext; /** @@ -119,18 +99,6 @@ typedef struct AVD3D12VASyncContext { uint64_t fence_value; } AVD3D12VASyncContext; -/** - * Define the behaviours of frame allocation. - */ -typedef enum AVD3D12VAFrameFlags { - AV_D3D12VA_FRAME_FLAG_NONE = 0, - - /** - * Indicates that frame data should be allocated using a texture array resource. - */ - AV_D3D12VA_FRAME_FLAG_TEXTURE_ARRAY = (1 << 1), -} AVD3D12VAFrameFlags; - /** * @brief D3D12VA frame descriptor for pool allocation. * @@ -143,26 +111,12 @@ typedef struct AVD3D12VAFrame { */ ID3D12Resource *texture; - /** - * Index of the subresource within the texture. - * - * In texture array mode, this specifies the array slice index. - * When texture array mode is not used, this value is always 0. - */ - int subresource_index; - /** * The sync context for the texture * * @see: https://learn.microsoft.com/en-us/windows/win32/medfound/direct3d-12-video-overview#directx-12-fences */ AVD3D12VASyncContext sync_ctx; - - /** - * A combination of AVD3D12VAFrameFlags. - * Set by AVD3D12VAFramesContext. - */ - AVD3D12VAFrameFlags flags; } AVD3D12VAFrame; /** @@ -182,28 +136,7 @@ typedef struct AVD3D12VAFramesContext { * * @see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_resource_flags */ - D3D12_RESOURCE_FLAGS resource_flags; - - /** - * Options for working with heaps allocation when creating resources. - * If unset, this will be D3D12_HEAP_FLAG_NONE. - * - * @see https://learn.microsoft.com/en-us/windows/win32/api/d3d12/ne-d3d12-d3d12_heap_flags - */ - D3D12_HEAP_FLAGS heap_flags; - - /** - * In texture array mode, the D3D12 uses the same texture array (resource)for all - * pictures. - */ - ID3D12Resource *texture_array; - - /** - * A combination of AVD3D12VAFrameFlags. Unless AV_D3D12VA_FRAME_FLAG_NONE is set, - * autodetected flags will be OR'd based on the device and frame features during - * av_hwframe_ctx_init(). - */ - AVD3D12VAFrameFlags flags; + D3D12_RESOURCE_FLAGS flags; } AVD3D12VAFramesContext; #endif /* AVUTIL_HWCONTEXT_D3D12VA_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h deleted file mode 100644 index 2794f85b7..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_oh.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * Copyright (c) 2025 Zhao Zhili - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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_OH_H -#define AVUTIL_HWCONTEXT_OH_H - -/** - * OpenHarmony codec device - */ -typedef struct AVOHCodecDeviceContext { - /** - * Pointer to OHNativeWindow - */ - void *native_window; -} AVOHCodecDeviceContext; - -#endif /* AVUTIL_HWCONTEXT_OH_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h index 22702300a..ef54486c9 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_opencl.h @@ -75,7 +75,7 @@ typedef struct AVOpenCLDeviceContext { /** * The default command queue for this device, which will be used by all * frames contexts which do not have their own command queue. If not - * initialised by the user, a default queue will be created on the + * intialised by the user, a default queue will be created on the * primary device. */ cl_command_queue command_queue; diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h index 3c16a8ab9..35530e4e9 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_qsv.h @@ -84,3 +84,4 @@ typedef struct AVQSVFramesContext { } AVQSVFramesContext; #endif /* AVUTIL_HWCONTEXT_QSV_H */ + diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h index 82e4194a9..0b2e071cb 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vaapi.h @@ -26,7 +26,7 @@ * API-specific header for AV_HWDEVICE_TYPE_VAAPI. * * Dynamic frame pools are supported, but note that any pool used as a render - * target is required to be of fixed size in order to be usable as an + * target is required to be of fixed size in order to be be usable as an * argument to vaCreateContext(). * * For user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h index 87c2a2d28..2688a4757 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/hwcontext_vulkan.h @@ -97,8 +97,6 @@ typedef struct AVVulkanDeviceContext { * each entry containing the specified Vulkan extension string to enable. * Duplicates are possible and accepted. * If no extensions are enabled, set these fields to NULL, and 0 respectively. - * av_vk_get_optional_instance_extensions() can be used to enumerate extensions - * that FFmpeg may use if enabled. */ const char * const *enabled_inst_extensions; int nb_enabled_inst_extensions; @@ -110,32 +108,74 @@ typedef struct AVVulkanDeviceContext { * If supplying your own device context, these fields takes the same format as * the above fields, with the same conditions that duplicates are possible * and accepted, and that NULL and 0 respectively means no extensions are enabled. - * av_vk_get_optional_device_extensions() can be used to enumerate extensions - * that FFmpeg may use if enabled. */ const char * const *enabled_dev_extensions; int nb_enabled_dev_extensions; -#if FF_API_VULKAN_SYNC_QUEUES +#if FF_API_VULKAN_FIXED_QUEUES + /** + * Queue family index for graphics operations, and the number of queues + * enabled for it. If unavaiable, will be set to -1. Not required. + * av_hwdevice_create() will attempt to find a dedicated queue for each + * queue family, or pick the one with the least unrelated flags set. + * Queue indices here may overlap if a queue has to share capabilities. + */ + attribute_deprecated + int queue_family_index; + attribute_deprecated + int nb_graphics_queues; + + /** + * Queue family index for transfer operations and the number of queues + * enabled. Required. + */ + attribute_deprecated + int queue_family_tx_index; + attribute_deprecated + int nb_tx_queues; + + /** + * Queue family index for compute operations and the number of queues + * enabled. Required. + */ + attribute_deprecated + int queue_family_comp_index; + attribute_deprecated + int nb_comp_queues; + + /** + * Queue family index for video encode ops, and the amount of queues enabled. + * If the device doesn't support such, queue_family_encode_index will be -1. + * Not required. + */ + attribute_deprecated + int queue_family_encode_index; + attribute_deprecated + int nb_encode_queues; + + /** + * Queue family index for video decode ops, and the amount of queues enabled. + * If the device doesn't support such, queue_family_decode_index will be -1. + * Not required. + */ + attribute_deprecated + int queue_family_decode_index; + attribute_deprecated + int nb_decode_queues; +#endif + /** * Locks a queue, preventing other threads from submitting any command * buffers to this queue. * If set to NULL, will be set to lavu-internal functions that utilize a * mutex. - * - * Deprecated: use VK_KHR_internally_synchronized_queues. */ - attribute_deprecated void (*lock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index); /** * Similar to lock_queue(), unlocks a queue. Must only be called after locking. - * - * Deprecated: use VK_KHR_internally_synchronized_queues. */ - attribute_deprecated void (*unlock_queue)(struct AVHWDeviceContext *ctx, uint32_t queue_family, uint32_t index); -#endif /** * Queue families used. Must be preferentially ordered. List may contain @@ -147,9 +187,6 @@ typedef struct AVVulkanDeviceContext { */ AVVulkanDeviceQueueFamily qf[64]; int nb_qf; - - /* Queue creation flags, for vkGetDeviceQueue2. */ - VkDeviceQueueCreateFlags queue_flags; } AVVulkanDeviceContext; /** @@ -160,6 +197,11 @@ typedef enum AVVkFrameFlags { * device and tiling during av_hwframe_ctx_init(). */ AV_VK_FRAME_FLAG_NONE = (1ULL << 0), +#if FF_API_VULKAN_CONTIGUOUS_MEMORY + /* DEPRECATED: does nothing. Replaced by multiplane images. */ + AV_VK_FRAME_FLAG_CONTIGUOUS_MEMORY = (1ULL << 1), +#endif + /* Disables multiplane images. * This is required to export/import images from CUDA. */ AV_VK_FRAME_FLAG_DISABLE_MULTIPLANE = (1ULL << 2), @@ -181,8 +223,7 @@ typedef struct AVVulkanFramesContext { /** * Defines extra usage of output frames. If non-zero, all flags MUST be - * supported by the VkFormat. Regardless, frames will always have the - * following usage flags enabled, if supported by the format: + * supported by the VkFormat. Otherwise, will use supported flags amongst: * - VK_IMAGE_USAGE_SAMPLED_BIT * - VK_IMAGE_USAGE_STORAGE_BIT * - VK_IMAGE_USAGE_TRANSFER_SRC_BIT @@ -287,7 +328,7 @@ struct AVVkFrame { /** * Updated after every barrier. One per VkImage. */ - VkAccessFlagBits2 access[AV_NUM_DATA_POINTERS]; + VkAccessFlagBits access[AV_NUM_DATA_POINTERS]; VkImageLayout layout[AV_NUM_DATA_POINTERS]; /** @@ -306,6 +347,11 @@ struct AVVkFrame { */ uint64_t sem_value[AV_NUM_DATA_POINTERS]; + /** + * Internal data. + */ + struct AVVkFrameInternal *internal; + /** * Describes the binding offset of each image to the VkDeviceMemory. * One per VkImage. @@ -318,11 +364,6 @@ struct AVVkFrame { * One per VkImage. */ uint32_t queue_family[AV_NUM_DATA_POINTERS]; - - /** - * Internal data. Not to be accessed by users in any way. - */ - struct AVVkFrameInternal *internal; }; /** @@ -338,18 +379,4 @@ AVVkFrame *av_vk_frame_alloc(void); */ const VkFormat *av_vkfmt_from_pixfmt(enum AVPixelFormat p); -/** - * Returns an array of optional Vulkan instance extensions that FFmpeg - * may use if enabled. - * @note Must be freed via av_free() - */ -const char **av_vk_get_optional_instance_extensions(int *count); - -/** - * Returns an array of optional Vulkan device extensions that FFmpeg - * may use if enabled. - * @note Must be freed via av_free() - */ -const char **av_vk_get_optional_device_extensions(int *count); - #endif /* AVUTIL_HWCONTEXT_VULKAN_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h index a755e7d68..1fa73893c 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/iamf.h @@ -213,11 +213,11 @@ typedef struct AVIAMFParamDefinition { enum AVIAMFParamDefinitionType type; /** - * Identifier for the parameter substream. + * Identifier for the paremeter substream. */ unsigned int parameter_id; /** - * Sample rate for the parameter substream. It must not be 0. + * Sample rate for the paremeter substream. It must not be 0. */ unsigned int parameter_rate; @@ -330,17 +330,14 @@ typedef struct AVIAMFLayer { /** * Demixing matrix as defined in section 3.6.3 of IAMF. * + * The length of the array is 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. + * * 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; @@ -496,14 +493,10 @@ typedef struct 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, }; @@ -521,9 +514,9 @@ typedef struct AVIAMFSubmixLayout { /** * 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. + * 7.1.2ch and 3.1.2ch + * If layout_type is not AV_IAMF_SUBMIX_LAYOUT_TYPE_LOUDSPEAKERS, this field + * is undefined. */ AVChannelLayout sound_system; /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h index 043d0ab34..e75a986f1 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/lfg.h @@ -28,7 +28,7 @@ * 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. + * to allow easy instanciation. */ typedef struct AVLFG { unsigned int state[64]; @@ -73,7 +73,7 @@ static inline unsigned int av_mlfg_get(AVLFG *c){ * 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 lfg pointer to the contex structure * @param out array where the two generated numbers are placed */ void av_bmg_get(AVLFG *lfg, double out[2]); diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h index 4a111ca9a..ab7ceabe2 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/log.h @@ -37,7 +37,6 @@ typedef enum { 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, @@ -47,15 +46,6 @@ typedef enum { 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) || \ @@ -87,9 +77,7 @@ typedef struct AVClass { 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. + * a pointer to the first option specified in the class if any or NULL * * @see av_set_default_options() */ @@ -97,50 +85,43 @@ typedef struct AVClass { /** * 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. + * This is used to allow fields to be added 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. + * Offset in the structure where log_level_offset is stored. + * 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 + * 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. + * The offset can be NULL. */ 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. + * Category used for visualization (like color) + * This is only set if the category is equal for all objects using this class. + * available since version (51 << 16 | 56 << 8 | 100) */ AVClassCategory category; /** - * Callback to return the instance category. Use this callback when - * different instances of this class may have different categories, - * ::category otherwise. + * Callback to return the category. + * available since version (51 << 16 | 59 << 8 | 100) */ AVClassCategory (*get_category)(void* ctx); /** * Callback to return the supported/allowed ranges. + * available since version (52.12) */ int (*query_ranges)(struct AVOptionRanges **, void *obj, const char *key, int flags); @@ -158,22 +139,11 @@ typedef struct AVClass { * @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. + * @note The difference between child_next and this is that child_next + * iterates over _already existing_ objects, while child_class_iterate + * iterates over _all possible_ children. */ 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; /** @@ -277,9 +247,9 @@ void av_log(void *avcl, int level, const char *fmt, ...) av_printf_format(3, 4); * @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. + * lavu_log_constants "Logging Constant" for the first occurance. * @param subsequent_level importance level of the message expressed using a @ref - * lavu_log_constants "Logging Constant" after the first occurrence. + * lavu_log_constants "Logging Constant" after the first occurance. * @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 @@ -407,16 +377,6 @@ int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, */ #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); diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h index 486de530f..e213bab68 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/mathematics.h @@ -278,7 +278,7 @@ int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int /** * Add a value to a timestamp. * - * This function guarantees that when the same value is repeatedly added that + * This function guarantees that when the same value is repeatly added that * no accumulation of rounding errors occurs. * * @param[in] ts Input timestamp diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h index 2a50f52fc..be189f765 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/opt.h @@ -28,6 +28,7 @@ */ #include "rational.h" +#include "avutil.h" #include "channel_layout.h" #include "dict.h" #include "log.h" @@ -541,7 +542,7 @@ typedef struct AVOptionRanges { */ int nb_ranges; /** - * Number of components. + * Number of componentes. */ int nb_components; } AVOptionRanges; @@ -885,6 +886,22 @@ int av_opt_set_chlayout(void *obj, const char *name, const AVChannelLayout *layo */ int av_opt_set_dict_val(void *obj, const char *name, const AVDictionary *val, int search_flags); +/** + * 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)) + /** * Add, replace, or remove elements for an array option. Which of these * operations is performed depends on the values of val and search_flags. @@ -1052,6 +1069,16 @@ int av_opt_eval_q (void *obj, const AVOption *o, const char *val, AVRational * @} */ +/** + * 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. + */ +void *av_opt_ptr(const AVClass *avclass, void *obj, const char *name); + /** * Check if given option is set to its default value. * @@ -1103,7 +1130,7 @@ int av_opt_flag_is_set(void *obj, const char *field_name, const char *flag_name) * @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. + * @param[out] buffer Pointer to buffer that will be allocated with string containg 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 @@ -1133,7 +1160,7 @@ void av_opt_freep_ranges(AVOptionRanges **ranges); * * The result must be freed with av_opt_freep_ranges. * - * @return number of components returned on success, a negative error code otherwise + * @return number of compontents returned on success, a negative errro code otherwise */ int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags); @@ -1149,7 +1176,7 @@ int av_opt_query_ranges(AVOptionRanges **, void *obj, const char *key, int flags * * The result must be freed with av_opt_free_ranges. * - * @return number of components returned on success, a negative error code otherwise + * @return number of compontents returned on success, a negative errro code otherwise */ int av_opt_query_ranges_default(AVOptionRanges **, void *obj, const char *key, int flags); diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h index 0cc70eb64..ba2f63281 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixdesc.h @@ -291,16 +291,6 @@ int av_chroma_location_enum_to_pos(int *xpos, int *ypos, enum AVChromaLocation p */ 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. * diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixfmt.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixfmt.h index b08881cc1..a7f50e169 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixfmt.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/pixfmt.h @@ -398,12 +398,12 @@ enum AVPixelFormat { 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_VUYA, ///< packed VUYA 4:4:4, 32bpp, 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_VUYX, ///< packed VUYX 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 @@ -439,72 +439,6 @@ enum AVPixelFormat { */ 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 - - /** - * CUDA block-linear (opaque). data[0] is a CUarray in block-linear layout, - * e.g. from NVDEC opaque decode. Use for zero-copy to NVENC (CUDA array input). - */ - AV_PIX_FMT_CUARRAY, - 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 }; @@ -526,7 +460,6 @@ enum AVPixelFormat { #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) @@ -557,9 +490,6 @@ enum AVPixelFormat { #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) @@ -569,27 +499,17 @@ enum AVPixelFormat { #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) @@ -611,11 +531,8 @@ enum AVPixelFormat { #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) @@ -626,15 +543,11 @@ enum AVPixelFormat { #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. @@ -657,12 +570,7 @@ enum AVColorPrimaries { 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 + AVCOL_PRI_NB ///< Not part of ABI }; /** @@ -691,12 +599,7 @@ enum AVColorTransferCharacteristic { 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 + AVCOL_TRC_NB ///< Not part of ABI }; /** @@ -810,14 +713,4 @@ enum AVChromaLocation { 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h index 30ac2aced..849f47f38 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rational.h @@ -22,7 +22,7 @@ /** * @file * @ingroup lavu_math_rational - * Utilities for rational number calculation. + * Utilties for rational number calculation. * @author Michael Niedermayer */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h deleted file mode 100644 index db6f84102..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/raw_color_params.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2026 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 - */ - -#ifndef AVUTIL_RAW_COLOR_PARAMS_H -#define AVUTIL_RAW_COLOR_PARAMS_H - -#include -#include - -#include "frame.h" -#include "rational.h" - -enum AVRawColorParamsType { - AV_RAW_COLOR_PARAMS_NONE = 0, - - /** - * The union is valid when interpreted as AVProResRawColorParams - * (codec.prores_raw). - */ - AV_RAW_COLOR_PARAMS_PRORES_RAW, -}; - -/** - * ProRes RAW per-frame color transform, parsed from the prrf frame header. - * - * The correct rendering pipeline is: - * -> (sample - black_level) / (white_level - black_level) - * -> per-channel white balance (wb_red, 1.0 for G, wb_blue) pre-debayer - * -> debayer - * -> color_matrix (camera RGB -> CIE 1931 XYZ relative to D65) - * -> gain (scene-linear scale) - * - * Black/white levels live on the outer AVRawColorParams. The matrix output - * is linear-light CIE XYZ D65; convert to a working RGB space downstream. - * - * @note The struct must be allocated as part of AVRawColorParams using - * av_raw_color_params_alloc(). Its size is not a part of the public ABI. - */ -typedef struct AVProResRawColorParams { - /** - * White balance multiplier for the red channel, applied pre-debayer. - */ - AVRational wb_red; - - /** - * White balance multiplier for the blue channel, applied pre-debayer. - * (The green channel is implicit 1.0 for ProRes RAW) - */ - AVRational wb_blue; - - /** - * 3x3 row-major color matrix from camera RGB to linear-light CIE 1931 - * XYZ relative to the D65 illuminant, applied post-debayer. - * out[i] = sum_j color_matrix[i][j] * in[j]. - */ - AVRational color_matrix[3][3]; - - /** - * Post-matrix scene-linear scaling factor. Encodes highlight headroom the - * encoder reserved; multiply the matrixed values by this to recover - * scene-linear light. - */ - AVRational gain; -} AVProResRawColorParams; - -/** - * Per-frame color information for a RAW camera codec. Carried as side data of - * type AV_FRAME_DATA_RAW_COLOR_PARAMS. - * - * The outer struct carries the fields every RAW codec exposes: the sensor's - * valid sample range and the white-balance correlated color temperature. - * The codec union holds the codec-specific transform parameters; `type` - * selects which member of the union is valid. - * - * The codec-specific transform (color_matrix or equivalent) always lands in - * linear-light CIE 1931 XYZ relative to the D65 illuminant, cameras don't - * have standard primaries, so XYZ is the only common target. - * - * @note The struct must be allocated using av_raw_color_params_alloc() or - * av_raw_color_params_create_side_data(). Its size is not a part of the - * public ABI. - */ -typedef struct AVRawColorParams { - /** - * Selects which member of `codec` is valid. - */ - enum AVRawColorParamsType type; - - /** - * Lowest valid raw sample code (sensor black point) - */ - AVRational black_level; - - /** - * Highest valid raw sample code (sensor white point) - */ - AVRational white_level; - - /** - * Color temperature in Kelvin from with the camera's white balance. - * Informational; the math uses the codec-specific white-balance fields. - * 0 if not signaled. - */ - uint32_t wb_cct; - - /** - * Additional codec-specific fields. - */ - union { - AVProResRawColorParams prores_raw; - } codec; -} AVRawColorParams; - -/** - * Allocate an AVRawColorParams structure and zero-initialize it. - * - * @param size if non-NULL, set to sizeof(AVRawColorParams) - * @return the newly allocated struct or NULL on failure - */ -AVRawColorParams *av_raw_color_params_alloc(size_t *size); - -/** - * Allocate and add an AVRawColorParams structure to an existing AVFrame as - * AV_FRAME_DATA_RAW_COLOR_PARAMS side data. - * - * @return the newly allocated struct, or NULL on failure - */ -AVRawColorParams *av_raw_color_params_create_side_data(AVFrame *frame); - -#endif /* AVUTIL_RAW_COLOR_PARAMS_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h index 0c72a88ec..bf0ca6e94 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/rc4.h @@ -43,7 +43,7 @@ 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 buffer containig 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 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h deleted file mode 100644 index 4e9d78eb0..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/refstruct.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 - -/** - * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h index 6e55d7114..43a57a422 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/samplefmt.h @@ -122,7 +122,8 @@ enum AVSampleFormat av_get_planar_sample_fmt(enum AVSampleFormat sample_fmt); * @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 + * @return the pointer to the filled buffer or NULL if sample_fmt is + * unknown or in case of other errors */ char *av_get_sample_fmt_string(char *buf, int buf_size, enum AVSampleFormat sample_fmt); diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h index 4b78978eb..2e90f7752 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/spherical.h @@ -82,12 +82,6 @@ enum AVSphericalProjection { * 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, }; /** diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h deleted file mode 100644 index 8629775a2..000000000 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tdrdi.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General 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 -#include - -#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(-prec_ref_display_width). - */ - 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^(-prec_ref_viewing_dist). - * 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/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h index c95009573..4696988ca 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/tx.h @@ -50,7 +50,7 @@ enum AVTXType { /** * Standard MDCT with a sample data type of float, double or int32_t, - * respectively. For the float and int32 variants, the scale type is + * respecively. 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. * diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h index d5bf20cf8..753f85b91 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/version.h @@ -35,7 +35,7 @@ * Useful to check and match library version in order to maintain * backward compatibility. * - * The FFmpeg libraries follow a versioning scheme very similar to + * The FFmpeg libraries follow a versioning sheme 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. @@ -72,14 +72,14 @@ /** * @defgroup lavu_ver Version and Build diagnostics * - * Macros and function useful to check at compile time and at runtime + * Macros and function useful to check at compiletime and at runtime * which version of libavutil is in use. * * @{ */ -#define LIBAVUTIL_VERSION_MAJOR 61 -#define LIBAVUTIL_VERSION_MINOR 5 +#define LIBAVUTIL_VERSION_MAJOR 59 +#define LIBAVUTIL_VERSION_MINOR 39 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -105,10 +105,16 @@ * @{ */ -#define FF_API_CPU_FLAG_FORCE (LIBAVUTIL_VERSION_MAJOR < 62) -#define FF_API_DOVI_L11_INVALID_PROPS (LIBAVUTIL_VERSION_MAJOR < 62) -#define FF_API_ASSERT_FPU (LIBAVUTIL_VERSION_MAJOR < 62) -#define FF_API_VULKAN_SYNC_QUEUES (LIBAVUTIL_VERSION_MAJOR < 62) +#define FF_API_HDR_VIVID_THREE_SPLINE (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_FRAME_PKT (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_INTERLACED_FRAME (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_FRAME_KEY (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_PALETTE_HAS_CHANGED (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_VULKAN_CONTIGUOUS_MEMORY (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_H274_FILM_GRAIN_VCS (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_MOD_UINTP2 (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_RISCV_FD_ZBA (LIBAVUTIL_VERSION_MAJOR < 60) +#define FF_API_VULKAN_FIXED_QUEUES (LIBAVUTIL_VERSION_MAJOR < 60) /** * @} diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h index 8e8af0ae9..1b2196093 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libavutil/video_hint.h @@ -80,7 +80,7 @@ av_video_hint_get_rect(const AVVideoHint *hints, size_t idx) { * 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). + * ones (and the remanining ones are those which changed). * Macroblocks will thus be hinted either to be P_SKIP-ped or go through the * regular encoding procedure. * diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h index 052089acc..0e1929b3e 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/swresample.h @@ -337,7 +337,7 @@ 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 + * These functons provide a means to set low-level options that is not possible * with the AVOption API. * @{ */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h index 057ac4b19..d1795b554 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version.h @@ -30,7 +30,7 @@ #include "version_major.h" -#define LIBSWRESAMPLE_VERSION_MINOR 2 +#define LIBSWRESAMPLE_VERSION_MINOR 3 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h index 0dc51de32..dd13f2bbe 100644 --- a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h +++ b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/include/libswresample/version_major.h @@ -26,6 +26,6 @@ * Libswresample version macros */ -#define LIBSWRESAMPLE_VERSION_MAJOR 7 +#define LIBSWRESAMPLE_VERSION_MAJOR 5 #endif /* SWRESAMPLE_VERSION_MAJOR_H */ diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavcodec.dll.a b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavcodec.dll.a index 078273d5f57333caed8cf36f4d039fccc4805e3c..9a95d381a76dc9161b03969297d6cf334892d261 100644 GIT binary patch literal 107470 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 Z-nbT!iuhT6#j!C*qY_NEuKwQW{|B5J6>tCm literal 132774 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 diff --git a/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavutil.dll.a b/crossplatform/windows-app/librepods-tray/vendor/ffmpeg/lib/libavutil.dll.a index 7a9cc478a3ae725eba0119e275863bca9674fcae..cc14e83e409e63847e20eff9a4931f5c0a014c3c 100644 GIT binary patch literal 398602 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 VLEe)(AwJ-1^$n6>Pv;3 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 delta 1904 zcma)6OK1~87|z6IH`&y@8e`fNyTtmcO|!GvS0V`FMLg7=MH)&HK}oH)2SJMD;Hd|# z{7}$C@t~fSxe0|H1TWHh^3;P0UIYVr6KZjGx5+-@!t7xV`Ty_nfAdfFR`*ud^8(fl zO_F6@sXi_Kit6=dyIsF^2j>_YLC5VBIcSRCrtM8AS1K$)aW#tEnH0!c(XFbngtUE<&Kif^$pgARJEsEI z$LbRxcIKcTrXsUMVvZ%m%*Rl_x!h{Oo6;lrbnbd@LPcT8##D#R5(l@>|8ewnmT=am zDfCO3BQHzHxe`@k3P-2maO7)Qa3L!!E0o7n^@b9Ivi!SmSk+hpo2^jj3ymiYC5&pl zzXa7_$Vn76#hy#4>g3W{MAyRL;I;O%??J;Xp>3Okhsmzt8oWn+_<#Z)ow Date: Thu, 6 Aug 2026 22:34:30 +0100 Subject: [PATCH 39/48] windows: commit Cargo.lock files Co-Authored-By: Claude Opus 4.8 --- .../windows-app/librepods-tray/Cargo.lock | 1 + .../windows-driver/lp-mic-rename/Cargo.lock | 173 ++++++++++++++++++ .../windows-driver/lp-mic-test/Cargo.lock | 7 + 3 files changed, 181 insertions(+) create mode 100644 crossplatform/windows-driver/lp-mic-rename/Cargo.lock create mode 100644 crossplatform/windows-driver/lp-mic-test/Cargo.lock diff --git a/crossplatform/windows-app/librepods-tray/Cargo.lock b/crossplatform/windows-app/librepods-tray/Cargo.lock index 143f651b9..e109c5fc1 100644 --- a/crossplatform/windows-app/librepods-tray/Cargo.lock +++ b/crossplatform/windows-app/librepods-tray/Cargo.lock @@ -1010,6 +1010,7 @@ name = "librepods-tray" version = "0.1.0" dependencies = [ "ab_glyph", + "cc", "image", "imageproc", "tray-icon", diff --git a/crossplatform/windows-driver/lp-mic-rename/Cargo.lock b/crossplatform/windows-driver/lp-mic-rename/Cargo.lock new file mode 100644 index 000000000..f03611846 --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-rename/Cargo.lock @@ -0,0 +1,173 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "lp-mic-rename" +version = "0.1.0" +dependencies = [ + "windows", +] + +[[package]] +name = "proc-macro2" +version = "1.0.107" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core", + "windows-targets", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings", + "windows-targets", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/crossplatform/windows-driver/lp-mic-test/Cargo.lock b/crossplatform/windows-driver/lp-mic-test/Cargo.lock new file mode 100644 index 000000000..160259b19 --- /dev/null +++ b/crossplatform/windows-driver/lp-mic-test/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "lp-mic-test" +version = "0.1.0" From 462b82c9c37b78ac8ed09383cd3679fcb6131968 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:45:08 +0100 Subject: [PATCH 40/48] hires-mic(Phase 4): name the virtual mic "LibrePods" (device-agnostic) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the capture endpoint from the sample's "CustomName2 (AudioCodec Device)" to "LibrePods" (+ DeviceDesc "LibrePods", FriendlyName "LibrePods Microphone"). A device-agnostic static name — correct whether the user has AirPods, Beats, or any Apple-protocol accessory. The exact per-device dynamic name (matching the connected device) needs the IPolicyConfig runtime rename (crashes on Win11 without a debugger to fix the vtable) — left as a follow-up. Co-Authored-By: Claude Opus 4.8 --- .../AudioCodec/Driver/AudioCodec.inf | Bin 8526 -> 8492 bytes .../LibrePodsMic/Common/CaptureCircuit.cpp | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.inf b/crossplatform/windows-driver/LibrePodsMic/AudioCodec/Driver/AudioCodec.inf index 889f9bdb830f65d86bba72afb1f8c1999a6e2186..cf2c276d447581c3ed26cbb0e47b54f1822b09ad 100644 GIT binary patch delta 86 zcmX@-w8m*ek-VS}LncEKLlHwNLjXfQLkdIj Date: Thu, 6 Aug 2026 22:45:57 +0100 Subject: [PATCH 41/48] hires-mic: mark Phase 4 essentially complete (plug-and-play mic) Co-Authored-By: Claude Opus 4.8 --- crossplatform/hires-mic/PLAN.md | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/crossplatform/hires-mic/PLAN.md b/crossplatform/hires-mic/PLAN.md index 6a5de3f45..5063a624c 100644 --- a/crossplatform/hires-mic/PLAN.md +++ b/crossplatform/hires-mic/PLAN.md @@ -101,11 +101,18 @@ the sink. and a **~150 ms silence cushion** on the ring to absorb the bursty per-packet feed. Pitch went ~105 → ~122 Hz (ref ~148), zero click/gap artifacts. Audio is a bit quiet (a gain stage would help) and mono (single mic capsule). -- **Phase 4 — in progress**: **A2DP auto-reset DONE** ✅ (`34cb610`) — on mic - stop the tray toggles the AirPods' **AudioSink (0x110B)** Bluetooth service - disable→enable (1 s settle + 2 s teardown) to reconnect A2DP and restore - stereo, no BT restart (0x110D gave ERROR 1060; found 0x110B via - BluetoothEnumerateInstalledServices). Remaining: 2 s stall watchdog; optional - gain/AGC (audio's a bit quiet); auto enable/disable when an app opens the mic; - dynamic endpoint name; and bundle it all into the dist. +- **Phase 4 — essentially COMPLETE** ✅ (plug-and-play). Done: + - **A2DP auto-reset** — toggle the AirPods' AudioSink (0x110B) service to + restore stereo after the mic stops (0x110D gave ERROR 1060; found via + BluetoothEnumerateInstalledServices), with a persistent "Restoring stereo…" + card through the reconnect. + - **Auto-enable** — the driver's capture-activity counter + (IOCTL_LIBREPODS_MIC_STATUS) lets the tray auto-start the hi-res stream when + an app records and auto-stop (debounced) when it finishes. + a manual mode. + - **Make-up gain** (×3, tanh soft-limit) so the mic isn't quiet. + - **Minimal FFmpeg** (7.1, aac-only) — avcodec 69 MB → 0.7 MB. + - **Name** "LibrePods" (device-agnostic). + - Single-instance guard. + - Follow-ups: exact per-device dynamic name (IPolicyConfig, needs a debugger), + VendorID spoofing (Apple DID), 2 s stall watchdog, apple-wireshark RE. - Phase 3 (protocol from PR #655 + AAC-ELD) and Phase 4 (integration) to follow. From 1ec34ffd1c243bd5a1222eb43f49a6301d1c86f8 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:57:25 +0100 Subject: [PATCH 42/48] hires-mic: fix lp-mic-rename IPolicyConfig crash (SetPropertyValue needs bFxStore) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AV was the SetPropertyValue signature: it takes a leading BOOL bFxStore (PCWSTR, BOOL, const PROPERTYKEY&, PROPVARIANT*), not the 3-arg form. With that fixed the call returns cleanly — HRESULT 0x80070005 (E_ACCESSDENIED): renaming an audio endpoint's friendly name needs elevation. So the rename works; it just has to run elevated (a scheduled task will automate it without UAC). Also match the new "LibrePods" mic name + log each step to a file. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-rename/src/main.rs | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs index dfa56df12..2fd49415c 100644 --- a/crossplatform/windows-driver/lp-mic-rename/src/main.rs +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -64,9 +64,14 @@ struct IPolicyConfig_Vtbl { GetShareMode: usize, SetShareMode: usize, GetPropertyValue: usize, - // SetPropertyValue(PCWSTR name, const PROPERTYKEY& key, PROPVARIANT* pv) - SetPropertyValue: - unsafe extern "system" fn(*mut c_void, *const u16, *const c_void, *const c_void) -> HRESULT, + // SetPropertyValue(PCWSTR name, BOOL bFxStore, const PROPERTYKEY& key, PROPVARIANT* pv) + SetPropertyValue: unsafe extern "system" fn( + *mut c_void, + *const u16, + i32, + *const c_void, + *const c_void, + ) -> HRESULT, } unsafe impl Interface for IPolicyConfig { @@ -78,6 +83,19 @@ fn wide(s: &str) -> Vec { s.encode_utf16().chain(std::iter::once(0)).collect() } +fn log(s: &str) { + use std::io::Write; + if let Ok(la) = std::env::var("LOCALAPPDATA") { + if let Ok(mut f) = std::fs::OpenOptions::new() + .create(true) + .append(true) + .open(format!("{la}\\LibrePods\\rename.log")) + { + let _ = writeln!(f, "{s}"); + } + } +} + /// Read a null-terminated wide (UTF-16) string from a raw pointer. unsafe fn wide_ptr_to_string(p: *const u16) -> String { if p.is_null() { @@ -134,7 +152,8 @@ fn main() { }) .unwrap_or_default(); - if friendly.contains("AudioCodec") { + if friendly.contains("LibrePods") || friendly.contains("AudioCodec") { + log(&format!("found: {friendly}")); println!("Found the virtual mic: \"{friendly}\""); target = Some(id); break; @@ -153,9 +172,17 @@ fn main() { } }; + log("creating CPolicyConfigClient"); let policy: IPolicyConfig = - CoCreateInstance(&CLSID_POLICY_CONFIG_CLIENT, None, CLSCTX_ALL) - .expect("CPolicyConfigClient"); + match CoCreateInstance(&CLSID_POLICY_CONFIG_CLIENT, None, CLSCTX_ALL) { + Ok(p) => p, + Err(e) => { + log(&format!("CoCreateInstance failed: {e:?}")); + eprintln!("CPolicyConfigClient not available: {e:?}"); + std::process::exit(2); + } + }; + log("policy created; reading vtable"); let wname = wide(&name); let pv = PropVariantStr { @@ -167,12 +194,20 @@ fn main() { _pad: 0, }; - let hr = (policy.vtable().SetPropertyValue)( - policy.as_raw(), + // Read the vtable pointer manually and call SetPropertyValue at the known + // slot (index 12 = 3 IUnknown + 9 IPolicyConfig methods). + let raw = policy.as_raw(); + let vtbl = *(raw as *const *const IPolicyConfig_Vtbl); + log("calling SetPropertyValue"); + let set = (*vtbl).SetPropertyValue; + let hr = set( + raw, id.0, + 0, // bFxStore = FALSE &PKEY_DEVICE_FRIENDLYNAME as *const _ as *const c_void, &pv as *const _ as *const c_void, ); + log(&format!("SetPropertyValue returned hr={:#x}", hr.0)); CoTaskMemFree(Some(id.0 as *const c_void)); From cf1d72e92c27f662b51b735d08a0c2ad38799405 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 22:59:17 +0100 Subject: [PATCH 43/48] hires-mic: rename-mic.ps1 matches the new LibrePods mic name IPolicyConfig::SetPropertyValue(FriendlyName) returns E_ACCESSDENIED even elevated (the property is protected against that path), so the registry write is the reliable rename. Update the endpoint match for the new 'LibrePods' name. Co-Authored-By: Claude Opus 4.8 --- crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 index 877ba463d..c06ef578a 100644 --- a/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 +++ b/crossplatform/windows-driver/LibrePodsMic/rename-mic.ps1 @@ -38,13 +38,14 @@ Get-ChildItem $base | ForEach-Object { $desc = if ($p.$descKey) { Decode-PropStr $p.$descKey } else { '' } $fn = if ($p.$fnKey) { Decode-PropStr $p.$fnKey } else { '' } Write-Host (" [{0}] desc='{1}' friendly='{2}'" -f $_.PSChildName, $desc, $fn) - if ($desc -like '*AudioCodec*' -or $fn -like '*AudioCodec*') { + if ($desc -like '*LibrePods*' -or $fn -like '*LibrePods*' -or + $desc -like '*AudioCodec*' -or $fn -like '*AudioCodec*') { $target = $props } } if (-not $target) { - Write-Host 'No AudioCodec capture endpoint matched. Is the LibrePodsMic driver installed?' + Write-Host 'No LibrePods capture endpoint matched. Is the LibrePodsMic driver installed?' exit 1 } From f6421a654341e117e15f4adc6b0c9ed69928d4fa Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 23:08:16 +0100 Subject: [PATCH 44/48] hires-mic: rename via direct registry write (IPolicyConfig was E_ACCESSDENIED) IPolicyConfig::SetPropertyValue(FriendlyName) returns E_ACCESSDENIED even when elevated, so write the endpoint's PKEY_Device_FriendlyName registry blob directly (VT_LPWSTR: 0x1F 00 00 00 + UTF-16LE name + NUL) under MMDevices\Audio\Capture\{endpoint}\Properties, then restart AudioEndpointBuilder. The endpoint GUID comes from IMMDevice::GetId (trailing brace group). Must run elevated. This is the reliable, byte-controlled rename (vs the finicky PowerShell blob decode). Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-rename/Cargo.toml | 2 + .../windows-driver/lp-mic-rename/src/main.rs | 210 +++++++----------- 2 files changed, 85 insertions(+), 127 deletions(-) diff --git a/crossplatform/windows-driver/lp-mic-rename/Cargo.toml b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml index c1b25441f..b32304526 100644 --- a/crossplatform/windows-driver/lp-mic-rename/Cargo.toml +++ b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml @@ -11,6 +11,8 @@ windows = { version = "0.58", features = [ "Win32_System_Com_StructuredStorage", "Win32_Media_Audio", "Win32_UI_Shell_PropertiesSystem", + "Win32_System_Registry", + "Win32_Security", ] } [[bin]] diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs index 2fd49415c..8ad1f7388 100644 --- a/crossplatform/windows-driver/lp-mic-rename/src/main.rs +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -1,39 +1,38 @@ -//! Rename the LibrePodsMic virtual microphone endpoint's friendly name — e.g. to -//! the connected AirPods' name, so it shows as "AirPods Pro de Pedro" in Discord, -//! Teams, Zoom, etc. instead of the driver's static "CustomName2 (AudioCodec -//! Device)". -//! -//! It enumerates active capture endpoints, finds the one whose name contains -//! "AudioCodec", and sets its PKEY_Device_FriendlyName via IPolicyConfig -//! (CPolicyConfigClient) — the same runtime API MagicPods & co. use. User-mode, -//! no admin, no reboot. +//! Rename the LibrePods virtual microphone endpoint to a given name (e.g. the +//! connected device's name — "AirPods Pro de Pedro", "Beats Studio Buds", …), so +//! it shows that in Discord/Teams/Zoom instead of the driver's generic +//! "LibrePods". MUST run elevated (writes HKLM\...\MMDevices). //! //! lp-mic-rename "AirPods Pro de Pedro" +//! +//! IPolicyConfig::SetPropertyValue returns E_ACCESSDENIED even elevated (the +//! FriendlyName property is protected against it), so we write the endpoint's +//! PKEY_Device_FriendlyName registry blob directly (as SoundVolumeView does) and +//! restart the audio endpoint service so apps pick it up. use std::ffi::c_void; +use std::process::Command; -use windows::core::{Interface, IUnknown, IUnknown_Vtbl, GUID, HRESULT, PWSTR}; +use windows::core::PCWSTR; use windows::Win32::Media::Audio::{ eCapture, IMMDeviceEnumerator, MMDeviceEnumerator, DEVICE_STATE_ACTIVE, }; use windows::Win32::System::Com::{ CoCreateInstance, CoInitializeEx, CoTaskMemFree, CLSCTX_ALL, COINIT_MULTITHREADED, STGM_READ, }; +use windows::Win32::System::Registry::{ + RegCloseKey, RegCreateKeyExW, RegSetValueExW, HKEY, HKEY_LOCAL_MACHINE, KEY_SET_VALUE, + REG_BINARY, REG_OPTION_NON_VOLATILE, +}; use windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY; +use windows::core::GUID; -const CLSID_POLICY_CONFIG_CLIENT: GUID = GUID::from_u128(0x870af99c_171d_4f9e_af0d_e63df40c2bc9); - -// PKEY_Device_FriendlyName = {a45c254e-df1c-4efd-8020-67d146a850e0}, 14 const PKEY_DEVICE_FRIENDLYNAME: PROPERTYKEY = PROPERTYKEY { fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), pid: 14, }; - const VT_LPWSTR: u16 = 31; -// A PROPVARIANT holding a VT_LPWSTR — laid out to match the real 24-byte x64 -// PROPVARIANT (vt + 3 reserved u16, then the pointer union). We only ever set -// the string case, so the rest is padding. #[repr(C)] struct PropVariantStr { vt: u16, @@ -44,45 +43,21 @@ struct PropVariantStr { _pad: u64, } -// IPolicyConfig (CPolicyConfigClient), IID f8679f50-850a-41cf-9c72-430f290290c8. -// We only need SetPropertyValue (the 10th method); everything before it is an -// opaque slot so the vtable offset is right. -#[repr(transparent)] -#[derive(Clone)] -struct IPolicyConfig(IUnknown); - -#[repr(C)] -#[allow(non_snake_case)] -struct IPolicyConfig_Vtbl { - base__: IUnknown_Vtbl, - GetMixFormat: usize, - GetDeviceFormat: usize, - ResetDeviceFormat: usize, - SetDeviceFormat: usize, - GetProcessingPeriod: usize, - SetProcessingPeriod: usize, - GetShareMode: usize, - SetShareMode: usize, - GetPropertyValue: usize, - // SetPropertyValue(PCWSTR name, BOOL bFxStore, const PROPERTYKEY& key, PROPVARIANT* pv) - SetPropertyValue: unsafe extern "system" fn( - *mut c_void, - *const u16, - i32, - *const c_void, - *const c_void, - ) -> HRESULT, -} - -unsafe impl Interface for IPolicyConfig { - type Vtable = IPolicyConfig_Vtbl; - const IID: GUID = GUID::from_u128(0xf8679f50_850a_41cf_9c72_430f290290c8); -} - fn wide(s: &str) -> Vec { s.encode_utf16().chain(std::iter::once(0)).collect() } +unsafe fn wide_ptr_to_string(p: *const u16) -> String { + if p.is_null() { + return String::new(); + } + let mut len = 0isize; + while *p.offset(len) != 0 { + len += 1; + } + String::from_utf16_lossy(std::slice::from_raw_parts(p, len as usize)) +} + fn log(s: &str) { use std::io::Write; if let Ok(la) = std::env::var("LOCALAPPDATA") { @@ -96,19 +71,6 @@ fn log(s: &str) { } } -/// Read a null-terminated wide (UTF-16) string from a raw pointer. -unsafe fn wide_ptr_to_string(p: *const u16) -> String { - if p.is_null() { - return String::new(); - } - let mut len = 0isize; - while *p.offset(len) != 0 { - len += 1; - } - let slice = std::slice::from_raw_parts(p, len as usize); - String::from_utf16_lossy(slice) -} - fn main() { let name = std::env::args().nth(1).unwrap_or_else(|| { eprintln!("usage: lp-mic-rename \"\""); @@ -117,7 +79,6 @@ fn main() { unsafe { let _ = CoInitializeEx(None, COINIT_MULTITHREADED); - let enumerator: IMMDeviceEnumerator = CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL).expect("MMDeviceEnumerator"); let collection = enumerator @@ -125,7 +86,8 @@ fn main() { .expect("EnumAudioEndpoints"); let count = collection.GetCount().unwrap_or(0); - let mut target: Option = None; + // Find our virtual mic and grab its endpoint id. + let mut endpoint_id = String::new(); for i in 0..count { let device = match collection.Item(i) { Ok(d) => d, @@ -138,11 +100,8 @@ fn main() { let friendly = device .OpenPropertyStore(STGM_READ) .ok() - .and_then(|store| store.GetValue(&PKEY_DEVICE_FRIENDLYNAME).ok()) + .and_then(|s| s.GetValue(&PKEY_DEVICE_FRIENDLYNAME).ok()) .map(|pv| { - // PROPVARIANT holding the friendly name (VT_LPWSTR). Read the - // pointer directly via the matching layout; `pv` clears itself - // on drop. let raw = &pv as *const _ as *const PropVariantStr; if (*raw).vt == VT_LPWSTR { wide_ptr_to_string((*raw).pwsz) @@ -151,71 +110,68 @@ fn main() { } }) .unwrap_or_default(); - if friendly.contains("LibrePods") || friendly.contains("AudioCodec") { - log(&format!("found: {friendly}")); + endpoint_id = wide_ptr_to_string(id.0); + CoTaskMemFree(Some(id.0 as *const c_void)); println!("Found the virtual mic: \"{friendly}\""); - target = Some(id); break; } CoTaskMemFree(Some(id.0 as *const c_void)); } - let id = match target { - Some(id) => id, - None => { - eprintln!( - "Could not find the AudioCodec capture endpoint. Is the LibrePodsMic \ - driver installed and the virtual mic present?" - ); - std::process::exit(1); - } - }; - - log("creating CPolicyConfigClient"); - let policy: IPolicyConfig = - match CoCreateInstance(&CLSID_POLICY_CONFIG_CLIENT, None, CLSCTX_ALL) { - Ok(p) => p, - Err(e) => { - log(&format!("CoCreateInstance failed: {e:?}")); - eprintln!("CPolicyConfigClient not available: {e:?}"); - std::process::exit(2); - } - }; - log("policy created; reading vtable"); - - let wname = wide(&name); - let pv = PropVariantStr { - vt: VT_LPWSTR, - r1: 0, - r2: 0, - r3: 0, - pwsz: wname.as_ptr() as *mut u16, - _pad: 0, - }; - - // Read the vtable pointer manually and call SetPropertyValue at the known - // slot (index 12 = 3 IUnknown + 9 IPolicyConfig methods). - let raw = policy.as_raw(); - let vtbl = *(raw as *const *const IPolicyConfig_Vtbl); - log("calling SetPropertyValue"); - let set = (*vtbl).SetPropertyValue; - let hr = set( - raw, - id.0, - 0, // bFxStore = FALSE - &PKEY_DEVICE_FRIENDLYNAME as *const _ as *const c_void, - &pv as *const _ as *const c_void, + if endpoint_id.is_empty() { + eprintln!("Could not find the LibrePods capture endpoint. Is the driver installed?"); + std::process::exit(1); + } + // Endpoint id looks like "{0.0.1.00000000}.{}"; the registry + // subkey is that trailing "{}". + let guid = endpoint_id.rsplit('.').next().unwrap_or(""); + log(&format!("id={endpoint_id} guid={guid}")); + + // Write PKEY_Device_FriendlyName as a VT_LPWSTR REG_BINARY blob: + // 4-byte type (0x1F) + UTF-16LE string + NUL. + let subkey = wide(&format!( + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture\\{guid}\\Properties" + )); + let mut hkey = HKEY::default(); + let rc = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + PCWSTR(subkey.as_ptr()), + 0, + PCWSTR::null(), + REG_OPTION_NON_VOLATILE, + KEY_SET_VALUE, + None, + &mut hkey, + None, ); - log(&format!("SetPropertyValue returned hr={:#x}", hr.0)); + if rc.is_err() { + log(&format!("RegCreateKeyEx failed: {rc:?}")); + eprintln!("RegCreateKeyEx failed ({rc:?}) — run elevated (admin)."); + std::process::exit(3); + } + let mut blob: Vec = vec![VT_LPWSTR as u8, 0, 0, 0]; + for w in wide(&name) { + blob.extend_from_slice(&w.to_le_bytes()); + } + let valname = wide("{a45c254e-df1c-4efd-8020-67d146a850e0},14"); + let rc = RegSetValueExW(hkey, PCWSTR(valname.as_ptr()), 0, REG_BINARY, Some(&blob)); + let _ = RegCloseKey(hkey); + log(&format!("RegSetValueEx rc={rc:?}")); + if rc.is_err() { + eprintln!("RegSetValueEx failed ({rc:?}) — run elevated (admin)."); + std::process::exit(4); + } - CoTaskMemFree(Some(id.0 as *const c_void)); + // Refresh the audio endpoint service so the new name shows immediately. + let _ = Command::new("powershell") + .args([ + "-NoProfile", + "-Command", + "Restart-Service AudioEndpointBuilder -Force", + ]) + .status(); - if hr.is_ok() { - println!("Renamed the virtual microphone to \"{name}\"."); - } else { - eprintln!("SetPropertyValue failed: {hr:?}"); - std::process::exit(1); - } + println!("Renamed the virtual microphone to \"{name}\"."); } } From 61a05853b0909fe23fa79d156593f81d36b55f18 Mon Sep 17 00:00:00 2001 From: arctumn Date: Thu, 6 Aug 2026 23:22:14 +0100 Subject: [PATCH 45/48] hires-mic: lp-mic-rename renames ALL LibrePods endpoints (stale dupes) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registry FriendlyName write was correct (verified: reads back 'AirPods Pro de Pedro'), but reinstalls leave several stale LibrePods capture endpoints and the tool renamed only the first match — a stale one, not the active endpoint Windows shows. Now it matches on the constant DeviceDesc and renames every LibrePods endpoint, so the active one is always covered. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-rename/src/main.rs | 154 ++++++++++-------- 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs index 8ad1f7388..32754c027 100644 --- a/crossplatform/windows-driver/lp-mic-rename/src/main.rs +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -1,19 +1,20 @@ -//! Rename the LibrePods virtual microphone endpoint to a given name (e.g. the +//! Rename the LibrePods virtual microphone endpoint(s) to a given name (e.g. the //! connected device's name — "AirPods Pro de Pedro", "Beats Studio Buds", …), so -//! it shows that in Discord/Teams/Zoom instead of the driver's generic -//! "LibrePods". MUST run elevated (writes HKLM\...\MMDevices). +//! it shows that in Discord/Teams/Zoom instead of the driver's generic name. +//! MUST run elevated (writes HKLM\...\MMDevices). //! //! lp-mic-rename "AirPods Pro de Pedro" //! -//! IPolicyConfig::SetPropertyValue returns E_ACCESSDENIED even elevated (the -//! FriendlyName property is protected against it), so we write the endpoint's -//! PKEY_Device_FriendlyName registry blob directly (as SoundVolumeView does) and -//! restart the audio endpoint service so apps pick it up. +//! IPolicyConfig::SetPropertyValue returns E_ACCESSDENIED even elevated, so we +//! write the endpoint's PKEY_Device_FriendlyName registry blob directly (as +//! SoundVolumeView does) and restart the audio endpoint service. Reinstalls leave +//! several stale "LibrePods" capture endpoints, so we rename ALL of them (the +//! active one is the one that shows up). use std::ffi::c_void; use std::process::Command; -use windows::core::PCWSTR; +use windows::core::{GUID, PCWSTR}; use windows::Win32::Media::Audio::{ eCapture, IMMDeviceEnumerator, MMDeviceEnumerator, DEVICE_STATE_ACTIVE, }; @@ -25,12 +26,15 @@ use windows::Win32::System::Registry::{ REG_BINARY, REG_OPTION_NON_VOLATILE, }; use windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY; -use windows::core::GUID; const PKEY_DEVICE_FRIENDLYNAME: PROPERTYKEY = PROPERTYKEY { fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), pid: 14, }; +const PKEY_DEVICE_DEVICEDESC: PROPERTYKEY = PROPERTYKEY { + fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), + pid: 2, +}; const VT_LPWSTR: u16 = 31; #[repr(C)] @@ -71,6 +75,39 @@ fn log(s: &str) { } } +/// Write PKEY_Device_FriendlyName (VT_LPWSTR REG_BINARY: 0x1F + UTF-16LE + NUL) +/// under the endpoint's registry Properties. Returns true on success. +unsafe fn write_friendly(guid: &str, name: &str) -> bool { + let subkey = wide(&format!( + "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture\\{guid}\\Properties" + )); + let mut hkey = HKEY::default(); + let rc = RegCreateKeyExW( + HKEY_LOCAL_MACHINE, + PCWSTR(subkey.as_ptr()), + 0, + PCWSTR::null(), + REG_OPTION_NON_VOLATILE, + KEY_SET_VALUE, + None, + &mut hkey, + None, + ); + if rc.is_err() { + log(&format!("RegCreateKeyEx {guid} failed: {rc:?}")); + return false; + } + let mut blob: Vec = vec![VT_LPWSTR as u8, 0, 0, 0]; + for w in wide(name) { + blob.extend_from_slice(&w.to_le_bytes()); + } + let valname = wide("{a45c254e-df1c-4efd-8020-67d146a850e0},14"); + let rc = RegSetValueExW(hkey, PCWSTR(valname.as_ptr()), 0, REG_BINARY, Some(&blob)); + let _ = RegCloseKey(hkey); + log(&format!("wrote {guid}: {rc:?}")); + rc.is_ok() +} + fn main() { let name = std::env::args().nth(1).unwrap_or_else(|| { eprintln!("usage: lp-mic-rename \"\""); @@ -86,21 +123,10 @@ fn main() { .expect("EnumAudioEndpoints"); let count = collection.GetCount().unwrap_or(0); - // Find our virtual mic and grab its endpoint id. - let mut endpoint_id = String::new(); - for i in 0..count { - let device = match collection.Item(i) { - Ok(d) => d, - Err(_) => continue, - }; - let id = match device.GetId() { - Ok(id) => id, - Err(_) => continue, - }; - let friendly = device - .OpenPropertyStore(STGM_READ) + let read = |dev: &windows::Win32::Media::Audio::IMMDevice, key: &PROPERTYKEY| -> String { + dev.OpenPropertyStore(STGM_READ) .ok() - .and_then(|s| s.GetValue(&PKEY_DEVICE_FRIENDLYNAME).ok()) + .and_then(|s| s.GetValue(key).ok()) .map(|pv| { let raw = &pv as *const _ as *const PropVariantStr; if (*raw).vt == VT_LPWSTR { @@ -109,61 +135,45 @@ fn main() { String::new() } }) - .unwrap_or_default(); - if friendly.contains("LibrePods") || friendly.contains("AudioCodec") { - endpoint_id = wide_ptr_to_string(id.0); - CoTaskMemFree(Some(id.0 as *const c_void)); - println!("Found the virtual mic: \"{friendly}\""); - break; + .unwrap_or_default() + }; + + // Rename EVERY LibrePods capture endpoint (match on the constant + // DeviceDesc so it works even after a previous rename), so the active one + // is covered regardless of stale duplicates. + let mut renamed = 0; + for i in 0..count { + let dev = match collection.Item(i) { + Ok(d) => d, + Err(_) => continue, + }; + let id = match dev.GetId() { + Ok(id) => id, + Err(_) => continue, + }; + let desc = read(&dev, &PKEY_DEVICE_DEVICEDESC); + let friendly = read(&dev, &PKEY_DEVICE_FRIENDLYNAME); + let is_ours = desc.contains("LibrePods") + || desc.contains("AudioCodec") + || friendly.contains("LibrePods") + || friendly.contains("AudioCodec"); + if is_ours { + let id_str = wide_ptr_to_string(id.0); + if let Some(guid) = id_str.rsplit('.').next() { + log(&format!("match {guid} desc='{desc}' friendly='{friendly}'")); + if write_friendly(guid, &name) { + renamed += 1; + } + } } CoTaskMemFree(Some(id.0 as *const c_void)); } - if endpoint_id.is_empty() { - eprintln!("Could not find the LibrePods capture endpoint. Is the driver installed?"); + if renamed == 0 { + eprintln!("No LibrePods capture endpoint found (or write denied — run elevated)."); std::process::exit(1); } - // Endpoint id looks like "{0.0.1.00000000}.{}"; the registry - // subkey is that trailing "{}". - let guid = endpoint_id.rsplit('.').next().unwrap_or(""); - log(&format!("id={endpoint_id} guid={guid}")); - - // Write PKEY_Device_FriendlyName as a VT_LPWSTR REG_BINARY blob: - // 4-byte type (0x1F) + UTF-16LE string + NUL. - let subkey = wide(&format!( - "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture\\{guid}\\Properties" - )); - let mut hkey = HKEY::default(); - let rc = RegCreateKeyExW( - HKEY_LOCAL_MACHINE, - PCWSTR(subkey.as_ptr()), - 0, - PCWSTR::null(), - REG_OPTION_NON_VOLATILE, - KEY_SET_VALUE, - None, - &mut hkey, - None, - ); - if rc.is_err() { - log(&format!("RegCreateKeyEx failed: {rc:?}")); - eprintln!("RegCreateKeyEx failed ({rc:?}) — run elevated (admin)."); - std::process::exit(3); - } - let mut blob: Vec = vec![VT_LPWSTR as u8, 0, 0, 0]; - for w in wide(&name) { - blob.extend_from_slice(&w.to_le_bytes()); - } - let valname = wide("{a45c254e-df1c-4efd-8020-67d146a850e0},14"); - let rc = RegSetValueExW(hkey, PCWSTR(valname.as_ptr()), 0, REG_BINARY, Some(&blob)); - let _ = RegCloseKey(hkey); - log(&format!("RegSetValueEx rc={rc:?}")); - if rc.is_err() { - eprintln!("RegSetValueEx failed ({rc:?}) — run elevated (admin)."); - std::process::exit(4); - } - // Refresh the audio endpoint service so the new name shows immediately. let _ = Command::new("powershell") .args([ "-NoProfile", @@ -172,6 +182,6 @@ fn main() { ]) .status(); - println!("Renamed the virtual microphone to \"{name}\"."); + println!("Renamed {renamed} LibrePods mic endpoint(s) to \"{name}\"."); } } From cfda622700ad6926c89724329fb7b41719c99f54 Mon Sep 17 00:00:00 2001 From: arctumn Date: Fri, 7 Aug 2026 08:52:45 +0100 Subject: [PATCH 46/48] hires-mic: dynamic mic rename WORKS (REG_SZ + stable anchor) Two fixes made the rename finally show in Sound/Discord: 1. Format: the Sound UI's Rename writes PKEY_Device_DeviceDesc ({a45c254e},2) as a plain REG_SZ string, NOT a REG_BINARY PROPVARIANT blob (which Windows ignores -> display falls back to the INF name). We now write REG_SZ. 2. Matching: identify our endpoint by STABLE, name-independent properties (device name {b3f8fa53},6 == 'LibrePods' from the INF, or hardware id {a8b865dd},8 contains 'AudioCodec') instead of the display name, so re-runs still find it after a rename. Also: skip endpoints already named correctly and only restart AudioEndpointBuilder when something changed (no needless audio blip). Dropped the COM/IMMDevice dependency -> pure registry, smaller binary. Confirmed on hardware: the mic now shows 'AirPods Pro de Pedro' in Sound > Input. Co-Authored-By: Claude Opus 4.8 --- .../windows-driver/lp-mic-rename/Cargo.toml | 4 - .../windows-driver/lp-mic-rename/src/main.rs | 236 +++++++++--------- 2 files changed, 117 insertions(+), 123 deletions(-) diff --git a/crossplatform/windows-driver/lp-mic-rename/Cargo.toml b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml index b32304526..d461b5bf2 100644 --- a/crossplatform/windows-driver/lp-mic-rename/Cargo.toml +++ b/crossplatform/windows-driver/lp-mic-rename/Cargo.toml @@ -7,10 +7,6 @@ description = "Rename the LibrePodsMic virtual microphone endpoint (e.g. to the [dependencies] windows = { version = "0.58", features = [ "Win32_Foundation", - "Win32_System_Com", - "Win32_System_Com_StructuredStorage", - "Win32_Media_Audio", - "Win32_UI_Shell_PropertiesSystem", "Win32_System_Registry", "Win32_Security", ] } diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs index 32754c027..92390215d 100644 --- a/crossplatform/windows-driver/lp-mic-rename/src/main.rs +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -1,67 +1,44 @@ //! Rename the LibrePods virtual microphone endpoint(s) to a given name (e.g. the //! connected device's name — "AirPods Pro de Pedro", "Beats Studio Buds", …), so -//! it shows that in Discord/Teams/Zoom instead of the driver's generic name. +//! any app (Discord/Teams/Zoom) shows that instead of the driver's generic name. //! MUST run elevated (writes HKLM\...\MMDevices). //! //! lp-mic-rename "AirPods Pro de Pedro" //! -//! IPolicyConfig::SetPropertyValue returns E_ACCESSDENIED even elevated, so we -//! write the endpoint's PKEY_Device_FriendlyName registry blob directly (as -//! SoundVolumeView does) and restart the audio endpoint service. Reinstalls leave -//! several stale "LibrePods" capture endpoints, so we rename ALL of them (the -//! active one is the one that shows up). +//! HOW (learned the hard way): the Windows Sound "Rename" UI persists the name in +//! PKEY_Device_DeviceDesc ({a45c254e...},2) as a **plain REG_SZ string** — NOT in +//! PKEY_Device_FriendlyName (,14), and NOT as a REG_BINARY PROPVARIANT blob (a +//! blob there is ignored → the display falls back to the driver's INF name). So we +//! write ,2 as REG_SZ, exactly like the UI. +//! +//! We identify our endpoint(s) by STABLE, name-independent properties (so re-runs +//! still match after a rename): the device/bus name ({b3f8fa53...},6 == "LibrePods", +//! from our INF) or the hardware id ({a8b865dd...},8 contains "AudioCodec"). All +//! matching endpoints are renamed (reinstalls leave stale duplicates; the active +//! one is whichever shows up). We skip endpoints already named correctly, and only +//! restart the audio service if something actually changed (no needless blip). use std::ffi::c_void; use std::process::Command; -use windows::core::{GUID, PCWSTR}; -use windows::Win32::Media::Audio::{ - eCapture, IMMDeviceEnumerator, MMDeviceEnumerator, DEVICE_STATE_ACTIVE, -}; -use windows::Win32::System::Com::{ - CoCreateInstance, CoInitializeEx, CoTaskMemFree, CLSCTX_ALL, COINIT_MULTITHREADED, STGM_READ, -}; +use windows::core::{PCWSTR, PWSTR}; use windows::Win32::System::Registry::{ - RegCloseKey, RegCreateKeyExW, RegSetValueExW, HKEY, HKEY_LOCAL_MACHINE, KEY_SET_VALUE, - REG_BINARY, REG_OPTION_NON_VOLATILE, + RegCloseKey, RegCreateKeyExW, RegEnumKeyExW, RegGetValueW, RegOpenKeyExW, RegSetValueExW, HKEY, + HKEY_LOCAL_MACHINE, KEY_READ, KEY_SET_VALUE, REG_OPTION_NON_VOLATILE, REG_SZ, RRF_RT_REG_SZ, }; -use windows::Win32::UI::Shell::PropertiesSystem::PROPERTYKEY; -const PKEY_DEVICE_FRIENDLYNAME: PROPERTYKEY = PROPERTYKEY { - fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), - pid: 14, -}; -const PKEY_DEVICE_DEVICEDESC: PROPERTYKEY = PROPERTYKEY { - fmtid: GUID::from_u128(0xa45c254e_df1c_4efd_8020_67d146a850e0), - pid: 2, -}; -const VT_LPWSTR: u16 = 31; - -#[repr(C)] -struct PropVariantStr { - vt: u16, - r1: u16, - r2: u16, - r3: u16, - pwsz: *mut u16, - _pad: u64, -} +const BASE: &str = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture"; +/// Device/bus friendly name — stays "LibrePods" (our INF DeviceDesc) after renames. +const PROP_DEVICE_NAME: &str = "{b3f8fa53-0004-438e-9003-51a46e139bfc},6"; +/// Hardware id — "ROOT\\AudioCodec" for our driver. +const PROP_HARDWARE_ID: &str = "{a8b865dd-2e3d-4094-ad97-e593a70c75d6},8"; +/// PKEY_Device_DeviceDesc — the endpoint's display name (what "Rename" sets). +const PROP_DEVICE_DESC: &str = "{a45c254e-df1c-4efd-8020-67d146a850e0},2"; fn wide(s: &str) -> Vec { s.encode_utf16().chain(std::iter::once(0)).collect() } -unsafe fn wide_ptr_to_string(p: *const u16) -> String { - if p.is_null() { - return String::new(); - } - let mut len = 0isize; - while *p.offset(len) != 0 { - len += 1; - } - String::from_utf16_lossy(std::slice::from_raw_parts(p, len as usize)) -} - fn log(s: &str) { use std::io::Write; if let Ok(la) = std::env::var("LOCALAPPDATA") { @@ -75,12 +52,32 @@ fn log(s: &str) { } } -/// Write PKEY_Device_FriendlyName (VT_LPWSTR REG_BINARY: 0x1F + UTF-16LE + NUL) -/// under the endpoint's registry Properties. Returns true on success. -unsafe fn write_friendly(guid: &str, name: &str) -> bool { - let subkey = wide(&format!( - "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\MMDevices\\Audio\\Capture\\{guid}\\Properties" - )); +/// Read a REG_SZ value under HKLM\. Returns None if missing / wrong type. +unsafe fn read_reg_sz(subpath: &str, value: &str) -> Option { + let wpath = wide(subpath); + let wval = wide(value); + let mut buf = [0u16; 512]; + let mut cb: u32 = (buf.len() * 2) as u32; + let rc = RegGetValueW( + HKEY_LOCAL_MACHINE, + PCWSTR(wpath.as_ptr()), + PCWSTR(wval.as_ptr()), + RRF_RT_REG_SZ, + None, + Some(buf.as_mut_ptr() as *mut c_void), + Some(&mut cb), + ); + if rc.is_ok() { + let n = (cb as usize / 2).saturating_sub(1); // drop the NUL terminator + Some(String::from_utf16_lossy(&buf[..n])) + } else { + None + } +} + +/// Write PKEY_Device_DeviceDesc as a plain REG_SZ string (what the Sound UI does). +unsafe fn write_desc(guid: &str, name: &str) -> bool { + let subkey = wide(&format!("{BASE}\\{guid}\\Properties")); let mut hkey = HKEY::default(); let rc = RegCreateKeyExW( HKEY_LOCAL_MACHINE, @@ -97,14 +94,11 @@ unsafe fn write_friendly(guid: &str, name: &str) -> bool { log(&format!("RegCreateKeyEx {guid} failed: {rc:?}")); return false; } - let mut blob: Vec = vec![VT_LPWSTR as u8, 0, 0, 0]; - for w in wide(name) { - blob.extend_from_slice(&w.to_le_bytes()); - } - let valname = wide("{a45c254e-df1c-4efd-8020-67d146a850e0},14"); - let rc = RegSetValueExW(hkey, PCWSTR(valname.as_ptr()), 0, REG_BINARY, Some(&blob)); + let wname = wide(name); + let bytes = std::slice::from_raw_parts(wname.as_ptr() as *const u8, wname.len() * 2); + let valname = wide(PROP_DEVICE_DESC); + let rc = RegSetValueExW(hkey, PCWSTR(valname.as_ptr()), 0, REG_SZ, Some(bytes)); let _ = RegCloseKey(hkey); - log(&format!("wrote {guid}: {rc:?}")); rc.is_ok() } @@ -115,73 +109,77 @@ fn main() { }); unsafe { - let _ = CoInitializeEx(None, COINIT_MULTITHREADED); - let enumerator: IMMDeviceEnumerator = - CoCreateInstance(&MMDeviceEnumerator, None, CLSCTX_ALL).expect("MMDeviceEnumerator"); - let collection = enumerator - .EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE) - .expect("EnumAudioEndpoints"); - let count = collection.GetCount().unwrap_or(0); + let mut hbase = HKEY::default(); + let rc = RegOpenKeyExW( + HKEY_LOCAL_MACHINE, + PCWSTR(wide(BASE).as_ptr()), + 0, + KEY_READ, + &mut hbase, + ); + if rc.is_err() { + eprintln!("cannot open MMDevices Capture key: {rc:?}"); + std::process::exit(1); + } + + let mut changed = 0; + let mut already = 0; + let mut i = 0u32; + loop { + let mut namebuf = [0u16; 128]; + let mut namelen = namebuf.len() as u32; + let rc = RegEnumKeyExW( + hbase, + i, + PWSTR(namebuf.as_mut_ptr()), + &mut namelen, + None, + PWSTR::null(), + None, + None, + ); + if rc.is_err() { + break; // ERROR_NO_MORE_ITEMS + } + i += 1; - let read = |dev: &windows::Win32::Media::Audio::IMMDevice, key: &PROPERTYKEY| -> String { - dev.OpenPropertyStore(STGM_READ) - .ok() - .and_then(|s| s.GetValue(key).ok()) - .map(|pv| { - let raw = &pv as *const _ as *const PropVariantStr; - if (*raw).vt == VT_LPWSTR { - wide_ptr_to_string((*raw).pwsz) - } else { - String::new() - } - }) - .unwrap_or_default() - }; + let guid = String::from_utf16_lossy(&namebuf[..namelen as usize]); + let props = format!("{BASE}\\{guid}\\Properties"); + let dev = read_reg_sz(&props, PROP_DEVICE_NAME).unwrap_or_default(); + let hw = read_reg_sz(&props, PROP_HARDWARE_ID).unwrap_or_default(); + let is_ours = + dev.contains("LibrePods") || hw.to_ascii_lowercase().contains("audiocodec"); + if !is_ours { + continue; + } - // Rename EVERY LibrePods capture endpoint (match on the constant - // DeviceDesc so it works even after a previous rename), so the active one - // is covered regardless of stale duplicates. - let mut renamed = 0; - for i in 0..count { - let dev = match collection.Item(i) { - Ok(d) => d, - Err(_) => continue, - }; - let id = match dev.GetId() { - Ok(id) => id, - Err(_) => continue, - }; - let desc = read(&dev, &PKEY_DEVICE_DEVICEDESC); - let friendly = read(&dev, &PKEY_DEVICE_FRIENDLYNAME); - let is_ours = desc.contains("LibrePods") - || desc.contains("AudioCodec") - || friendly.contains("LibrePods") - || friendly.contains("AudioCodec"); - if is_ours { - let id_str = wide_ptr_to_string(id.0); - if let Some(guid) = id_str.rsplit('.').next() { - log(&format!("match {guid} desc='{desc}' friendly='{friendly}'")); - if write_friendly(guid, &name) { - renamed += 1; - } - } + let cur = read_reg_sz(&props, PROP_DEVICE_DESC).unwrap_or_default(); + if cur == name { + already += 1; + log(&format!("ok {guid} already '{name}'")); + } else if write_desc(&guid, &name) { + changed += 1; + log(&format!("wrote {guid} dev='{dev}' hw='{hw}' (was '{cur}')")); } - CoTaskMemFree(Some(id.0 as *const c_void)); } + let _ = RegCloseKey(hbase); - if renamed == 0 { - eprintln!("No LibrePods capture endpoint found (or write denied — run elevated)."); + if changed == 0 && already == 0 { + eprintln!("No LibrePods capture endpoint found (run elevated)."); std::process::exit(1); } - let _ = Command::new("powershell") - .args([ - "-NoProfile", - "-Command", - "Restart-Service AudioEndpointBuilder -Force", - ]) - .status(); - - println!("Renamed {renamed} LibrePods mic endpoint(s) to \"{name}\"."); + if changed > 0 { + let _ = Command::new("powershell") + .args([ + "-NoProfile", + "-Command", + "Restart-Service AudioEndpointBuilder -Force", + ]) + .status(); + println!("Renamed {changed} LibrePods mic endpoint(s) to \"{name}\"."); + } else { + println!("Already named \"{name}\" ({already} endpoint(s)) — nothing to do."); + } } } From 46333e8c05c0ed6e29cc6f660d257dc95f94186b Mon Sep 17 00:00:00 2001 From: arctumn Date: Fri, 7 Aug 2026 09:00:52 +0100 Subject: [PATCH 47/48] hires-mic: auto-rename the virtual mic to the connected device name The tray now renames the virtual mic to whatever it's connected to, with no UAC prompt: - bt::find_airpods matches Beats too (Powerbeats/Fit Pro/Studio Buds/...), not just AirPods, since they share the AAP chip/endpoint -> dynamic name. - New rename module: on launch it writes the device name to %LOCALAPPDATA%\LibrePods\micname.txt and fires an elevated on-demand scheduled task (schtasks /run) that runs lp-mic-rename with highest privileges. - lp-mic-rename reads the name from that file when no CLI arg is given, and is idempotent (skips + no service restart when already named), so firing it every launch is cheap. - install.ps1 copies lp-mic-rename.exe and registers the 'LibrePods Rename Mic' task (RunLevel Highest, interactive user, on-demand). Co-Authored-By: Claude Opus 4.8 --- crossplatform/dist/windows/install.ps1 | 19 ++++++++ .../windows-app/librepods-tray/src/bt.rs | 14 ++++-- .../windows-app/librepods-tray/src/main.rs | 7 +++ .../windows-app/librepods-tray/src/rename.rs | 43 +++++++++++++++++++ .../windows-driver/lp-mic-rename/src/main.rs | 27 +++++++++++- 5 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 crossplatform/windows-app/librepods-tray/src/rename.rs diff --git a/crossplatform/dist/windows/install.ps1 b/crossplatform/dist/windows/install.ps1 index 6db4f1ced..6f42614ca 100644 --- a/crossplatform/dist/windows/install.ps1 +++ b/crossplatform/dist/windows/install.ps1 @@ -55,6 +55,25 @@ New-Item -ItemType Directory -Force -Path $dest | Out-Null Copy-Item (Join-Path $here 'librepods-tray.exe') $dest -Force Copy-Item (Join-Path $here 'librepods.exe') $dest -Force +# lp-mic-rename + its elevated on-demand task: lets the (unelevated) tray rename +# the virtual mic to the connected device's name without a UAC prompt. +$renameExe = Join-Path $here 'lp-mic-rename.exe' +if (Test-Path $renameExe) { + Copy-Item $renameExe $dest -Force + $renameDest = Join-Path $dest 'lp-mic-rename.exe' + Write-Host '==> Registering the elevated mic-rename task...' + $taskName = 'LibrePods Rename Mic' + $action = New-ScheduledTaskAction -Execute $renameDest + $principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" ` + -LogonType Interactive -RunLevel Highest + $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries ` + -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Minutes 2) ` + -StartWhenAvailable + Register-ScheduledTask -TaskName $taskName -Action $action -Principal $principal ` + -Settings $settings -Description 'Rename the LibrePods virtual mic to the connected device name.' ` + -Force | Out-Null +} + Write-Host '==> Adding the tray app to startup...' $startup = [Environment]::GetFolderPath('Startup') $ws = New-Object -ComObject WScript.Shell diff --git a/crossplatform/windows-app/librepods-tray/src/bt.rs b/crossplatform/windows-app/librepods-tray/src/bt.rs index 743d1dec5..bbd632775 100644 --- a/crossplatform/windows-app/librepods-tray/src/bt.rs +++ b/crossplatform/windows-app/librepods-tray/src/bt.rs @@ -12,8 +12,15 @@ fn utf16_name(buf: &[u16]) -> String { String::from_utf16_lossy(&buf[..end]) } -/// (address, display name) of the first paired device whose name contains -/// "airpod". The Windows " - Find My" suffix is stripped for display. +/// Name patterns of Apple-chip audio devices that speak the AAP protocol — not +/// just AirPods but Beats too (Powerbeats, Beats Fit Pro, Studio Buds, Solo, +/// Studio3, Flex…), which share the same H1/W1 chip and endpoint. Matched +/// case-insensitively against the paired device's name. +const AAP_NAME_HINTS: &[&str] = &["airpod", "beats"]; + +/// (address, display name) of the first paired device whose name matches a known +/// AAP device (AirPods / Beats). The Windows " - Find My" suffix is stripped for +/// display. pub fn find_airpods() -> Option<(u64, String)> { unsafe { let mut params: BLUETOOTH_DEVICE_SEARCH_PARAMS = zeroed(); @@ -34,7 +41,8 @@ pub fn find_airpods() -> Option<(u64, String)> { let mut found = None; loop { let name = utf16_name(&info.szName); - if name.to_lowercase().contains("airpod") { + let lname = name.to_lowercase(); + if AAP_NAME_HINTS.iter().any(|h| lname.contains(h)) { let clean = name .trim_end_matches("- Find My") .trim_end_matches(" -") diff --git a/crossplatform/windows-app/librepods-tray/src/main.rs b/crossplatform/windows-app/librepods-tray/src/main.rs index c9682d4a1..6d941bf16 100644 --- a/crossplatform/windows-app/librepods-tray/src/main.rs +++ b/crossplatform/windows-app/librepods-tray/src/main.rs @@ -17,6 +17,7 @@ mod eld; mod media; mod micpipe; mod overlay; +mod rename; mod theme; mod volume; @@ -331,6 +332,12 @@ fn main() { Some((m, n)) => (Some(m), n), None => (None, "AirPods".to_string()), }; + + // Auto-rename the virtual mic to the connected device's name (via the elevated + // scheduled task; idempotent, so this is a cheap no-op when already correct). + if mac.is_some() { + rename::apply(&dev_name); + } // The current driver handle, shared with the tray menu. run_receiver // re-opens it every session (the device object is recreated on reconnect, // so a stale handle fails) and publishes the live one here. diff --git a/crossplatform/windows-app/librepods-tray/src/rename.rs b/crossplatform/windows-app/librepods-tray/src/rename.rs new file mode 100644 index 000000000..55a6a6777 --- /dev/null +++ b/crossplatform/windows-app/librepods-tray/src/rename.rs @@ -0,0 +1,43 @@ +//! Auto-rename the virtual microphone to the connected device's name (e.g. +//! "AirPods Pro de Pedro", "Beats Fit Pro"), so calls/recordings show that. +//! +//! Renaming an audio endpoint writes to HKLM and needs admin, but the tray runs +//! unelevated. So `install.ps1` registers an elevated, on-demand scheduled task +//! ("LibrePods Rename Mic") that runs `lp-mic-rename` with highest privileges. We +//! drop the desired name in a file and trigger the task via `schtasks /run`, +//! which runs it elevated WITHOUT a UAC prompt. `lp-mic-rename` is idempotent — +//! it does nothing (no audio-service restart) when the mic is already named +//! correctly, so firing this on every launch is cheap. + +use std::os::windows::process::CommandExt; +use std::process::Command; + +const TASK_NAME: &str = "LibrePods Rename Mic"; +const CREATE_NO_WINDOW: u32 = 0x0800_0000; + +/// Best-effort, non-blocking: publish `dev_name` and kick the elevated rename +/// task. Never blocks the tray or surfaces errors — if the task isn't installed, +/// the manual `lp-mic-rename ""` still works. +pub fn apply(dev_name: &str) { + let name = dev_name.trim().to_string(); + if name.is_empty() { + return; + } + std::thread::spawn(move || { + let la = match std::env::var("LOCALAPPDATA") { + Ok(la) => la, + Err(_) => return, + }; + let dir = format!("{la}\\LibrePods"); + let _ = std::fs::create_dir_all(&dir); + // Publish the name for the elevated task to read. + if std::fs::write(format!("{dir}\\micname.txt"), &name).is_err() { + return; + } + // Fire the on-demand elevated task (registered by install.ps1; no UAC). + let _ = Command::new("schtasks") + .args(["/run", "/tn", TASK_NAME]) + .creation_flags(CREATE_NO_WINDOW) + .status(); + }); +} diff --git a/crossplatform/windows-driver/lp-mic-rename/src/main.rs b/crossplatform/windows-driver/lp-mic-rename/src/main.rs index 92390215d..8ef34f47e 100644 --- a/crossplatform/windows-driver/lp-mic-rename/src/main.rs +++ b/crossplatform/windows-driver/lp-mic-rename/src/main.rs @@ -102,9 +102,32 @@ unsafe fn write_desc(guid: &str, name: &str) -> bool { rc.is_ok() } +/// The name to apply: the CLI arg if given, else the contents of +/// %LOCALAPPDATA%\LibrePods\micname.txt (so an elevated scheduled task launched +/// by the non-elevated tray can pick up the connected device's name). +fn resolve_name() -> Option { + if let Some(a) = std::env::args().nth(1) { + let a = a.trim().to_string(); + if !a.is_empty() { + return Some(a); + } + } + let la = std::env::var("LOCALAPPDATA").ok()?; + let s = std::fs::read_to_string(format!("{la}\\LibrePods\\micname.txt")).ok()?; + let s = s.trim().to_string(); + if s.is_empty() { + None + } else { + Some(s) + } +} + fn main() { - let name = std::env::args().nth(1).unwrap_or_else(|| { - eprintln!("usage: lp-mic-rename \"\""); + let name = resolve_name().unwrap_or_else(|| { + eprintln!( + "usage: lp-mic-rename \"\"\n \ + (or write the name to %LOCALAPPDATA%\\LibrePods\\micname.txt)" + ); std::process::exit(2); }); From 7fa5f8705d2ef77f006c08b2c4193a5d40f7f630 Mon Sep 17 00:00:00 2001 From: arctumn Date: Fri, 7 Aug 2026 09:17:54 +0100 Subject: [PATCH 48/48] docs: group Windows features + document the hi-res microphone Reorganize crossplatform/README.md by category (Control & status / Audio / App & UX), add a dedicated hi-res microphone section (LibrePodsMic virtual audio driver, AAC-ELD decode, auto-activate, A2DP reset, gain, dynamic name, minimal FFmpeg), add the microphone row to the platform table, mention the second driver + lp-mic-rename in the layout, and add a driver-signing note. Co-Authored-By: Claude Opus 4.8 --- crossplatform/README.md | 72 +++++++++++++++++++++++++++++++++++------ 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/crossplatform/README.md b/crossplatform/README.md index 729ce3281..20f7b47d0 100644 --- a/crossplatform/README.md +++ b/crossplatform/README.md @@ -3,8 +3,9 @@ This directory brings the full **LibrePods** app to **Windows**, natively and 100% open-source, while **keeping Linux working from the same code**. It builds on the Linux Rust app ([PR #241](https://github.com/librepods-org/librepods/pull/241)) -and extends it into a single **cross-platform** crate plus an open-source -**Windows kernel driver** for the Apple Accessory Protocol (AAP). +and extends it into a single **cross-platform** crate plus two open-source +**Windows kernel drivers** — one for the Apple Accessory Protocol (AAP), one that +exposes the AirPods as a native **microphone**. > Apple's AAP runs over a classic-Bluetooth L2CAP channel (PSM `0x1001`) that > Windows won't let user-mode apps open. So we wrote a signed **KMDF profile @@ -13,15 +14,28 @@ and extends it into a single **cross-platform** crate plus an open-source ## ✅ What works (validated on real AirPods Pro on Windows) +**Control & status** + | Feature | Status | | --- | --- | | **Battery** (L / R / Case, charging state) | ✅ matches iPhone | | **Noise control** (Off / ANC / Transparency / Adaptive) | ✅ read + control | | **Ear detection** | ✅ | -| **Auto-pause / resume** when you remove/insert a bud | ✅ via SMTC | -| **Conversational Awareness** (volume ducking when you speak) | ✅ via WASAPI | | **Device info** (model, serials, firmware) | ✅ | | **LE battery** via BLE advertisement (IRK/enc keys) | ✅ | + +**Audio** + +| Feature | Status | +| --- | --- | +| **Auto-pause / resume** when you remove/insert a bud | ✅ via SMTC | +| **Conversational Awareness** (volume ducking when you speak) | ✅ via WASAPI | +| **Hi-res microphone** — the AirPods AAC-ELD mic as a native Windows input | ✅ see below | + +**App & UX** + +| Feature | Status | +| --- | --- | | **Full iced GUI** running natively | ✅ | | **System tray** | ✅ (`tray-icon`) | | **MagicPods-style centered popup** (connect / ANC / case) | ✅ (v1) | @@ -31,6 +45,35 @@ The whole app also **compiles and links as a Windows `.exe`** (`cargo build --target x86_64-pc-windows-gnu`), and **Linux stays green** at every step. +## 🎙️ The hi-res microphone + +Windows has no API to "create a virtual microphone", so we ship a **second** +kernel driver — `LibrePodsMic`, a virtual audio device (ACX) that appears as a +real capture endpoint. The tray reads the AirPods' uplink audio over AAP, decodes +it, and streams PCM into that device, so **any app (Teams, Zoom, Discord, OBS…) +can use the AirPods mic** — the Windows counterpart to Linux +[PR #655](https://github.com/librepods-org/librepods/pull/655). + +``` +AirPods ──AAP/L2CAP──▶ LibrePodsAAP ──IOCTL──▶ tray: decode AAC-ELD → resample → PCM + │ + ▼ + LibrePodsMic virtual mic ──▶ any app +``` + +| Capability | Status | +| --- | --- | +| AAC-ELD decode (FFmpeg/libavcodec, LGPL) + resample to 48 kHz | ✅ clean & in-tune | +| **Auto-activate** — hi-res stream turns on when an app records, off when it stops | ✅ (+ manual mode) | +| **A2DP auto-reset** — restores stereo playback after the mic degrades it to mono | ✅ | +| **Make-up gain** — the mic isn't quiet | ✅ (×3, soft-limited) | +| **Dynamic name** — the mic shows the connected device ("AirPods Pro de …", Beats…) | ✅ auto, no UAC | +| Minimal FFmpeg build (aac-only) — avcodec **69 MB → 0.7 MB** | ✅ | + +The dynamic name is set by `lp-mic-rename` (writes the endpoint's `DeviceDesc` the +same way the Sound "Rename" UI does), launched by the tray through an elevated +on-demand scheduled task — so it happens automatically with no UAC prompt. + ## How it's built — one crate, two operating systems All OS-specific integration lives behind a `platform/` abstraction selected at @@ -44,6 +87,7 @@ compile time (`#[cfg(target_os)]`). The protocol/UI code (`aacp`, `att`, `le`, | LE advertisements | `bluer::monitor` | WinRT `BluetoothLEAdvertisementWatcher` | | Audio routing / volume | PulseAudio | WASAPI (Core Audio) | | Media control | MPRIS | SMTC | +| Microphone | PipeWire virtual input | **LibrePodsMic** virtual audio driver | | System tray | `ksni` | `tray-icon` | | Paths | XDG | `%APPDATA%` | @@ -53,23 +97,31 @@ compile time (`#[cfg(target_os)]`). The protocol/UI code (`aacp`, `att`, `le`, the `platform/` abstraction layer. - **`windows-driver/LibrePodsAAP/`** — the open-source KMDF AAP kernel driver (`+ prebuilt/` so it installs without the WDK; Test Mode). +- **`windows-driver/LibrePodsMic/`** — the virtual-microphone audio driver (ACX), + plus **`lp-mic-rename/`** (names the mic after the connected device). - **`windows-app/`** — a lightweight native **tray app** (battery + ANC + volume - + ear-detection auto-pause + the popup overlay) and an egui window, plus the - `lp-driver-test` CLI. + + ear-detection auto-pause + the hi-res mic + the popup overlay) and an egui + window, plus the `lp-driver-test` CLI. ## Install (Windows, Test Mode) -**Ready-to-install builds are in [`dist/windows/`](dist/windows/)** — both apps, -the driver, and a one-shot `install.ps1`. The driver is test-signed, so it needs -Secure Boot **off** + `bcdedit /set testsigning on` + reboot; then run the +**Ready-to-install builds are in [`dist/windows/`](dist/windows/)** — the apps, +the driver, and a one-shot `install.ps1`. The drivers are test-signed, so they +need Secure Boot **off** + `bcdedit /set testsigning on` + reboot; then run the installer (elevated). Full steps are in [`dist/windows/README.md`](dist/windows/README.md); build instructions + the technical log are in `HANDOFF.md`. +> **Signing note.** Kernel drivers must be signed to load. For personal use we +> test-sign (above). Distributing to others without Test Mode needs an **EV +> certificate + Microsoft Partner Center** attestation (Azure Trusted Signing +> covers the user-mode app for SmartScreen, but **not** kernel drivers). + ## Not done yet / in progress -- One-click redistributable installer (bundle driver + app). +- One-click redistributable installer (bundle both drivers + app). - Unify the interim tray app and the iced window into one app. +- Fold the `LibrePodsMic` driver install into the one-shot `install.ps1`. - Release build packaging; precise BLE lid-open detection; heart-rate RE (AirPods Pro 3).

`Lomq+-V4wRbk=`j?PLG!rpR*}UCN&Y^5vJcYre&2^vAXP^ zh|J!#+kFx${G1r;7Lf;Hm7Ru-~DO!2^8b&K~VMl*6DJSUk`Ne-~Am>eGBEb)yh4{b{lDSU$D>Vt>rI+RTTzIg7$$AFE7;<`y5JjuQPvS6M1v*&+9H5$DZlXo_XEU$(~_MUpvd5Sqp^H zX4a5u_RP0fMoRX~Dfc9M=KC>}YS%cVV$W#IFx$M1qag}BO5MLqdxp8<;oCEAW;>`s z)4rN*%b)n48IaiC&2b`xaqj*n7_{@}m)qc9W1h~F*0H{vcSK=R_zrkT%Vj)V)wC{s zx~5o|#f`oprCb;5ROI2vf|SDX);u^L)$GyvUK;qwa#ui0TphcB_qG8pUBkfSa}Sb$ zsdV)j)x{6-h@rE0P4%SSfx0y-eiE}-0teV93khG6lxqD~UCz{FrRzaprGb{E-XZ?Y zyO2qXU%dApOLA9h^}~kB)O;Q0ihI~)81Xr86Vr1IgXP^Ge#2=-vQX$oDGngPE+NfI4il4 zg;C~U_;pkr%~4K&w^}!B5<_NK$%C~#q!0_0RtklHR#)u|?ZNM{DoQ(}QnwBBQMWgT z(2LB7$!WSNd*fK>h>`*NsNVppFZ5}PFv?Nagq1QL8C4ReB)=ZXLnh;#w8W&O@q#fE z;o2?(W$%b=TTae;WH**$`1KwrJOk+_9U{M(3>SCiG!|#Pewo~*x+&nyx>6_Z z(4h{e(GXgib%l=k;tCx{ceh^F0P^Z7uhy2_o4Oc_D|3paAuJrAt>c$%z)*tx%v_Qa z`xD~a!PjMHcn-qXin&=_r$ZGwHY*WF>RftH03ju!mBNToCSyV9x?$N6%c{nWg;N+M z=n^&jdjG$U&ncYsb}Pht9BW?SR+bxX0@L z8abUaB2qnZ6_}(vP9cmkpkW}Erw=lZb%b#B7blSFEM|~5OUR7-zpdp_#lXvM_#B%k z@UYjw6h+7RuJ8RKc~~n?c90$|mzTwa}q9*{YcnL<0vj5y?3B$6w2nK;ZO59zi8r$km?I7LBvqnHzlX{ap? z9jjR@YrJABW{Wpf$1ENLp-b0^Ivah>ez?DLBg0x`qOx> z9MBzVqd)3AjsCc|yV9rH=#PHwNh!6_A2>sD_^Y>QT+DID;D4C6Uvr8q8V-Wj{z%ZV zKQ@pM_D6!QqdTQs6VUl|ZPV72a$Q7-g#9s^Qi|BTf!5_U8>B>o4q%P2JsTrr;L8nh zxW?l9+Nvkr?s;THK=mPI+h0C{k^Wkq+S#dJUGy#O6+1y`fRn-sBfu4oEAYx(-k==4 z(suEl_j{S{Fxj*dwwfKgMgi6UaYrX+#5z#ZaM?z(riCu^7O>LPu=*a-HA8Cl1?x0o zbXK+gF+}WZuG#ay=3n{9VSNw6t z&POc^a$VI_iiggKr)5xK*_7|o)Gonxeao!q>No;#9*6s@sz9`4z5(<>}8@BU}E4-b#YOdVP6<0y!uml zG7$xHFsD`maN)Q9i!|W)kgJu5{T`!|2sdz>D>g|vg0kcd z4G@N%r|h^)vt4pna>0)S6+8d4R8+zkog`sXVTX671zk$#oe|Ljf-Sc_&dl%ngwJVH1 zs&K)>ZjoSc=hRfZgPbBYyM8T2K?D+!&n%fHJ*gVxMp4kNanY1yal8;e>#(b?ZR$bB z8?X3Ju|u>Nl+bvNKH5)?JeV_DSB9>KbybW(tov$M9dK^NBgKl;BVM-N-6&BTw+PL`l!JcxgcbMqn zKf+eCX3&v6DWzu3&|`;EO3j*K02xjx-;eMdiWk<*S8vf+nqyCu*tN+zPY*4y`vZ7) z4z#cSzl?w9uriJ=B?g|D_DaU#M;!xR*L+oqGvS=gWNl&FECcb@{`<6)TJhuKcE!AE zubwiXDW&nVoD7;&-!;^|ddk^Er>w1>@|PW~TrEc$7q(se$XVJ}j&;VWxHPu1^yybT z?oi{Z#dKzi09BNyvvr~tg=m?J!(M>(avQP{kOKQU=gw?4Z0({KdwzSh{7qt?^7&2?=|l$3;-HObV51F zg^BArjq3-onVUhn3;ytRQy68A7&mi{>?x#tqZWyO^7vK;qNMrbif-u2mfUY5>fR!b z8sr}Yl=H+X(1wdi=$#z zq`fHA{26I_W1eA^trxeYJFT>TFxXc4DPV+ggoP3m^+_yWu+^(T^M3uA2}kL*l0ejh$6r~mS9=W(MX3_AjYqCLxduqV=1t!*)*=o+8qnoTHeM=9K{crA+kvovX8Vwo+J|(*6`VzD zEHN34c><^v`)#pq%t_@^A^k4l5!sp~H7}e&6exC=TASHuCJHq((gC)J+ZSWK82|*n zUWYp4|^88s{klf&US4k|blscg9!FxGHF;F_8V*Jp{bKnS&G zo-|7Wg~E(a*70ZnX-GgKV!IPhU7n5zpbX|Y`XIgoE-u#0i|~Bj)2^47D3C0BO<{xY zVghrgl0O!}!hVMy-pX1{P-h*JkYthP%;|)zxRXrGT~tnRV)l_taaL_J}s72(BVGV>4MksonLG56{KW90)Zk7$Be$i;|X&e9)m5mg@=i$3K3 zS`B;mb7Ieo77gpn5O0_`&_WQUx6niJ+4)?PDHa$hQ$*_%H|n8lY4IU(VFS6n0MJ^T z&XP4v>&th>sDL`$YITW^Di_doB7~ff+xdetDa~@S4h46ZKSj?ryk3COD_uOGRBVP0 zPkbz3s349flV|TBT?V4E2bZ7XE;G9_qI3sIm2@lt6{5q7bNK$wgeS#LX z_uZ1ZR~m?8({;2$+?yAn8HFCKfse*ysxRiZ3+4#X5}@ZH;1~x#CO-sIQz9xeiOPy@ zTxharo{+K-@DW&#Lx5~aI*QFe&OW%en!XqPV~E^Z;s&k?1s|n5zE<1tl-##aP{$TTECqr*E zUtS&+eLrSThcRD{VE*Y9h`-&BNAh=0Ly8-y|KHYjYXPHMB4iHL!Hp*T z{0d6?9~J-4Fu_#UdMamRyz#(lzi&%u87ui<_t2vK@G2hI z+rx<0Sozd)e*UPL&l5cSod0P1h~~zaV2_{^9`7WMqWU7k*Y;B|O|^~i1xocLk^(lv z4LpGj-KyRDgFeCp5G2b+e_MKOtZ)WdkroZqI;VkJQv>zBO8e{pG#m8W>+ZB^9z8Ox$3SSb%lVVhEa2JJ zvJ{9}M~jVgDUHF)myRrfO0*OIX_iXs%7Vc(OQoImiMIKqZS#@0-ZoG`eSn^6oJgA6 zI;GV&H(qfTt<#QJw-2;7v)e!QfVo%Ka0Acatp3tm>m{6EKd^#$5<5!upC5_mCprpe zUPniv@1#CLcpzI`OWiwc37iXSyInXZ8e|eO9m8QjeiW3_nfxD&KOJ^ex)r7A?s0nJ ze(hNEwcQV}SE;rCqy|3<0q8PL z8zA+tc!3wlT-m$7?$Y0>{^2jqthW8e6i474Sz0jysvRph8M-)+oXSs|qHNn81OV+} z{29G$pDVRZKSTbTYu>#X`Jc01+PkkjqqDGem~W*vi7PEQjJ*1%Ep7cz(Jr(>YLnLL zM+v%0?eYric8?K*i|38ADW09xNWWg{zO~d(&p9c2PP9^T?z?CfFa6~L zP^kYLKXY2{Vq0wme;4?LhfH%t@51RT`8fw}X59$2D+IPj*wU4gT$G?=Ru=i7XTy2S z-QMD&nYFh2p^kp``+Ri2H(#hkxVzy*JM*g_uAcBvG<;ng(6F6G|3G{Hy?ftT)I*I) zAz42iuN1A%#})0paon56sBIu8tKuWBryo-cSyfS<_j~ zibTf;xrMf-9Wl^oZDeHb4MlIzKidZ0t3P&4|KqLIFEt&B&(G0}P8z4uha}wldTM*e zr1DW*mXkW@{^*%=+LiuOu}2=z8RM#*TWErgZniM}l=a>dhdH_)eXu`u#8YUarqo8X z-0V)-W5Ypzr~NN$pR!NdH)XryVrQL|8f#6rbmvfbW6oMhYRAzwMq4zAXAH*>WqZ^H zqD4p5dgQt(yX5AgD?WbYTA~S8ObjNz!`-&~raR!?xm|B&v(S8hI`UpjGKX2`S%Ik@^r3hxv>v>Pi?|F&)9sQ5Q&{eH}*G!*^TNgql{wWNp(0lS#rD~g< zFuNE=WS_S~8648-!|9F`FiZDkMH}B;kd;%OGg(m(v9zw1JAWdcspS z2OTWh&wjL~`f+xV*xMdGl0Jnl-MehI{yH7TgGJH5z=Zy_juA%fI?Ug0(BdvNlkHk) z%g(p)hvlHhpyFaAS`?3)*wtF|TsvGG9{`@QMm7e~Tna(Ys?d}-Uv@?Gr1lkiI#!I$ zG!a$NkLII~u6N(6XxEPJx5Yhj{daP~vSQqN@2e_Lu5)0d zJhOVj+dBrnx)GrV7LP6 zm2oHEw3rHoaR)*dbFfWVQE!*v8w&|z$Ho5pfb=oUjw3Gpn0NhD&zp6>4>OtUgxk{L zr~D zN5=;f;omBUrkg)Cm~g5gwD+Fb_CZHCn&%4{e0p4&YU_V=P4$u{w|Qr6%~SWj+Fq?^ z4TftCxy$DfY8<8l;$Jj+|231J*522SZv5td=81u^qq=qyWY$e}R6mimR@<6h>3!t2 zv#N_Y!{KFa<7v#^M&JxP)pjrE1fu11lRGA2^c;w|W>HcX^%N%u!J#x-Hgd-Rl~pwejWbDd5+m5cent2$|xC zO|t-m-BSuz!rb9Y&b?8ENNvuu%oX9t*5E4J{ZSIo)R)<3cP2p5fJdKdC? zu04!{nATJ;WL*s_;|Fn-CHEr`iN)1gm;XU)^)yDwWp^txB`z(&@ZfUu;RbFVgny0M z5sWL$eM&2~2afjjR+yf*gj)Dnd-p9RHyrf8!XC&Gx_;Jn_kz~Hb#_s3Zs3f z-BMY&ith|nTqY>_y32r1uG(~_yv=P z^)nf>QMqXlK80Lf_unu$t(oG#^sgt#mR9 z=P|e7d={L?G28>nyhalgE@ob9oX4NHl?=o@+JH4HJ`FW9z2SiSDth;=pWoQgcr0RG zdv0pGuiAD4j23W-CcA>29|3URO_$sUt9Ik z_tUFbAE9lUTB~Qg-d??Q7==)~AF2PTwQkXW`o+|4*3U(fYR2PlZLQNOy<_6P{B`iU z@*y-zd9s5GCC6-$$yoYrt9yYv#t{GCE7k2--PzQ1+4tu25jC-XE>ouO3!WqYz56!K z=Ld}yTMV8a9yoEJm1>S>lh3ADL4f#83lSw$#Hn9C$0hZT#}%lanRgqc({H)k^oJ$J zpk~gxSj)|w7{rVY#!m*t%BQg>qvSqOul?~aASz*<)b0xne)LbNmwI<(RDW~t&9p}4 zwu$>>iUP8nUpj=s_|Iaz_{0199@WYpx@%bz{Y*#jmI!v*pgi&G;Uad!^1H4XlI^hDb#uE$6YG=V#gFxu$N266GU1{guNB61f}4MsR|PF=S!Jia5Jt0_ z(#Y;hJpLnmD5oP1%*)V5k7oxB z>(@n1Ey6&|ag$TfT?X0uGMP?W$2N@1)k;}Q$={6|z?xx*jOywJsxUw?Ti<1FiclC? zDsS|6{dy8lXre^K4_tyL3lc&Vbv7+k<~${^?7>_deZ^Dl$lbI*05@9xnHEaNj#dv~ z#?J=%Pl0REGA;@5mKu!g7p_-}J`R3NDDy8iQ&?hxGZC5>t08e56it?P0bbZeu1DQ& zqPL@1U4mcmJ-@KTxABm4dO>Gfljau7O2!}X0Q)&aDw^N(t2%Y`yiV>Dns~XSDb`n? zG~*um8;jv_w1gW@9y3~>P`E@V*Qmw%!rUP(F;e0+>p+UPmfdM{vH8YJJC{P>K@ zI>{~Ap0<%JF6noAc6#|HzPY|bz6&#+lc4*0{wiLJgRLidOe@&uZvg92NYbwR93uj= zaGuT%L0DR7`E+k3{i^{Tq}u9I4(vypntD>NNn097NxLq1NQ;p?q~#+X(*7hKz8~Sh zJQQn89HYGBTXZ!#_C5XwyJP;2hlv&JDut?Sv$gop;~3$?kb@As$~F%bDSdrB$Z`zg z)R(rzVkUeZhDEn1da=?RYkMw>$FcbuqHaA2CX7M)w*_bqaDg}*+${LU{I7fBKT{gY zxloi1ZZRMAd9Xn8A0y4^JZI?WKH4$unK6%g0yRhjTQ>D*1tR~OwBVY5P3)=X&x0Cmln)R? z$Igj(2BzKH#a$q88S`t>+^9_Zlq6(5BL%=IKB_n3hMjE7M3MZEWV@b9p_TkY;F_g6 zmQv$*(9Wh7i#dukb{Ypufhjh!GuFK5acIhJQqaNYd@56u+yM;pKet1WA%aeZ1rY0rq{rTg1!NqELv{Y= zMJJU67_m;2M@j!$^v$HZE1m*QQ@R!OSis}NO+Jt9sB;yD#;ArG^ zSQDR#fuT!c|9Wd`VrY#p^3ya9=FmGC8FJCfzqXAR2R8-_LbQ5#L_1g;ozqZ=r zzlkj`;Nqwb_C!*z|Hw1(ZBk+GaeEkZ_rUw6Bm9o-ihA8 zuPZZ0YP^EZ$^@WQg?^>S+J7+4sS`zBnY61#a3-vafwwbQ<^nHl%Qn!l8L+iM`K}R2 zFQIch>eH)oKq`TrZV!pi!QPxIpnWLOLAFGz-Be{1IzmmtI1iA-k!*8|)Iz|}a3Z^J zC>4usG(DwAEMuXfgE6B+VQwBF3vb(o{ZH9a3lPOSFPN7dv*yqGVw21>eAjKqD8vJU zTBUD9^x;9=L=p$S#8?{JZpNYgnLrrXp++Lh7*;fu(U3~SM5+=6K~m^T-MK``p=s~- z$;he*ksK6D*#s0#@KkSzeVjWpMpZFTh<&zoBJm;L8VpHVq)(mzLeh`xy+R34yJXwO zO$QyvC3{HTCo9P55*E5kV=Ei%5@ch(UMoh0)|a@M^{tN&dK_JIbAZ+(94a=3d98ot z#|+3%wxNrMn77fBsNK4#-A)$KXF3wq#9iyb$Af&r;M3|!Dz)fea3@Ul%>`nD%?Bks z)s=6SyF6RJB7>kzk9Au&i!`+++taofBsV!65rZp(K~^ly+1rn;Y>GZJD7SbY%;JCE zC;q(mEluw|i5=O(mwS~b=`#)pE5*)eyK2Jy%l_p1O^#xd9{Tt=^DTeb$IxSNkt zg5Ar8%`$FQ&t!W0A0>Sj0oWZMXa4a!)NCuM!>nf%@23tmKeoQt)OVX9{&9<64L;2O4VAx|m zBuNy2-`UW*sJQaHbp*c5LlQ2*cCu_Pr!2d`-^IA_3NZ?JCPO)nhQfM|iL<+^gm>81{ZbN87$rUYW#KU(uhf$M2Kp-Bplz4@3_K*q zMBztB8jIBAtVv#u6jFeg=7R;B`lN^Vo`Q#68{JY*+Rd{TSboX&-Upt3BYSV#-Z!%M zzC)^_@XFqzxJm}z&{v(hi?FuzZiYyunoYeFZ_c6h;ll#0r>RB0}a4CNn<$v z2Ltf`9|quS|AOZJU)BKB467M^Jioc2hf*%)ptZT@o7iv@cRn7*)B?7iYZLKL=h=TE zbujG1Fb7*X{ba5g%I=ar21 z20RpDF?+#-5>ewWkB)2mIbpe-9LyuL>m`8ahlQ(m<%S*-VirR&C+U>s)4)*V(`d}D zY)H?sLhTIAFzfFPi4PreI89}E8c7ZqN?*Cf5+b=gisrpyAGqKzm;eOsn|weDNM!Ei zWEfXgW1jFsrClw5hf1R<>$=BU-L!P63R$qO5ba z_q0rHPV_ssjSzDWetwRRuGlk+#-R|ak~%sgq}xgLEs0x@`0g5&9U1*3uj>Z_l6UxI_j=0+VK~*V~ZJW+){ebBLI4&Ts@Ky&U%M^ zaLX@nO7Was-;zF7Y@kG1W990Rs5KvGwlYA(ZNQH!Yp?qnq{XGWh#oE`R_$~ONEzNj z9^woir@-03gz({nZWtvF^~S@CvdQ4Fw7(VSV4g5RIIP^NT)5*12Y~1kzf!^_w9Ef6 z?1rE?AXtcM;GVN*SW`BN%Qa8rmh!#hL2N!C15!&k-S0GJ7Lmw<89d_~$P@oSe0|gx zHi*7UAnQo5Tz2)iC`O<^1SWjsDggp`toUO}mR;Qym0BqK?s_W*lLsXXZwcFRA?_96 z75kzP99I$GBo&nl7fJF0dnQ-(4A*^DCtpY{CyJ zYHo~n5fA^K9kZZ5588srZGk2Q0YE_;T#ZT3$*x{0Ffg9eeK|ISq=Bue!r&I=lu!I# z`oHok6Y1HKo&P*onznUg_vQsndBMGGU{yjFtwUU5@?k~ITg3{mopcz@L&w({N|reI z-CoEsA$DErl*Y6U6H5@it3-{$FG;&z)XrC=;zy}_(ruscLonn9NhEJxW8in?2bH?b z_~n!>DTD0lu|)BAwBMK$hbZkbz(uFs?60 zV&Yev%;378iu3AqegWc>Vj!>6J&iw=Wh#)!0IEhU?UGRX0IVf*?_?^Pf3L;^1UhNrVO!Laf1DxgnvQI2Xs*3`_-@`M_w(K5Mp>UoBSwp?@3{bfD)2S+3UP z1)H*gje<=I&LtljE4z9!m3>BbPWc@MAE4kiMCFyR7&eLkG`_KdQ*o-`j5e90;5_+) zfldWCL!B=LUDgf$g+j}(lwRI7gC>DF%JZ#)FoRl-R>}toT&<=(|s75Y!R+m zz?baNo_%8rcy#9*S-|K2=#4DkHdAXBFxw?2?ms61h7WU0Yu+dRWdRt@&oY4P3cx9~ zhku&Idmoqw_=^CZHh16u&!lJP#6OMNu3W%0B-JKdUM9Y=JFs04cT%&-aWFoe8+xMDA>#us=tCUiwhD*)B0c~W5pf~0 zP7wA{@0I|Ey_~R%K_MY_Kv;k{WY=#YV|18AuqrbAcsC6B0cjUO=)?w@b_);42nrYG zWPU-Pj4*Rw!L=>v|M_SJmtGk~$PqR(ygQIZF4xYEp7{I_wJ~f}o>X=`*Udqj33Av+)yH9jQ* z4&)O!WY76LpgHF!6N^hM# zuyvmFjK4X1T*?hw%}JG!ptFJlrdOl$u+u^K^ETV{n-l3-@8*JO@}kDH#K`$fn_a7ZQiEu-#NKhNVUyDyZ+BD!4Eu7h0rZGMJiOKa~(E1}htGDjKdBwH(un z!F?~xJ7DCRB=O0B7o`q8u!F&2u&2O^k;~8{EZ5ZZG=~1M2=n{AZm2wL?b+;^OgZNW zNuo8sfV%TwMQQa&;}y@pn6~t!Gf$xW4eeMCJ?Tl?duA{8$NsU}`88kN*N2DlaE#RV zFa3l@9mjKUQNgWi`|p}~cerW)%>sO!Yx{SV`d{v-Uf~NH6(_#;u$J4OEm&Op7B1W? ze4l8%$8UeRV2O6-75<~_#J{>TQhQRW|4i*Qb;f|*Gx3i01o&O^0P{ZapMQ`5zdHfu zpCDQaz$vw-NIgCQ?&#l>+`|)pTe9$y-~X7F=hs%TXR1^^b5(I(FjBIVzYDQDhiB~0 z5F6}H{_bmC@nZg{8O79@sihddAkSIiG1WooldQPvA9=J&ASLodtVl?9PHco6~>2BiV%;-a2~*4`9#W zo3m&0p`}N=a~A!HC-dpA*`0}V*quSh3|F=mTnTjMaV2pKyR+cRjNMsqWn00OF}c$9 z*158E4p-hp)oi1J8@Af$cA0I_`iIlG#tJ#vHj7WG^nrW=8SKs)pAyY8d>SqIBogyg zbK)U(XThf#yR+caSiz?W`Lyn>^J#PrpX9};XdGNM(;$apk9OxQt|U$!$d$tG3<7H0 z!0vnlE+h_NcNScju{#ScXt#koJLup-i&RVoQ?WY}BD3wzXt=j*cSfm05A0xY80;yq znz1_*(KN;ZcIQ0yOuhko60J46lLFIrr>5J|WMT0S3k&0KVlVdIoXCR~%t{)3+AhUu zh;{YDj=7Nscu}=KYkSalpY#V_KhUzEh%Y!i+Z4BHoWc>Y1Mdr?^vVUxXS*DEnfP?L zRIgmHQk-ipM_wk@#fOEv&Pp!FDGk5A1^mO0ORK+uzwtdG7`=V`pY}KYb`tPp_xUo% z?rXHfTekb6)S<8+KomnQiwK?3pOoGbwvYZ+&Qjt@G_Z z(KtAJ4%hBW2p4vrRLHc=z=qTTc~N6pV&r_L&2+9o3&Wmq%Fbucczna|E7&t*_Z95f zT(E~m{bl(ZMdRS?*?ef}(e4B98vThU^XaeIeG=$oAyGKPm90T}-a9Bd)14{_P2w1K zU%{0byRYENwt_2|8UHiRe-yGauOY+cSJhr4QuORy)@i8G}!W<{3VX z`T^PbEZV+kI3pJ+L3XzcET3 zdSC~G!(dN=)r{Q-bl62>9ANj&W6xyDImd4^`P(5tg};#k({|sX*Ue{Hb8{VzZ`Gcg zwGw{zUhT0ru;>02A((zRz@F=g4@>gXbXSg*s(-!;Tdt$}wPez5!rYA3{8d_1f8HMa zc@sUn^!22M?@4yu_7>8%Y0fCX+I3s|eEEOadl&F1uj}4hg27P|x${mU658NcX~roy zIEB`3p$8`#BRMm86e~6{Gxj*a8IDV0notK)J9TY2f`sWXw$6#0(8f*qTAx$W_%yV2 zTiS3EiTlOa0^j7jz&IW(F!Bv#jM4Y|ul>H7(FI8)e0jb;4?GW}_ubdE*Is+=|6Y6T z{g&an=9Mt8zxzkoM_xi5X_=eX3pQz_*oLW%4!UZXbLJ~Y?|vw2UTej1yxdVIT-WLd z8!}8pgST!i38g$%y9Nith4bZ#;Ha1g9Hcx}iVbvQZ*J*jVq2*L%FiXxZzsXzmL4qal>2L<{GxX z%{UNgHnRGsAaC7v3oqfi=Izi8XGCBmU`z9MpFLe-Pl|S)-ZuM^wju0kqnZ)evwd{- zNP3En*p+HUz$e#$p?rb{j+m3s_~rOglAbO_&|;&jpFcK5uXMcgR(2T|B3$s{OOMZ% z=AzG@9U-&?oZHQj4oP1!VcrFaoA%`tK?(@N}V zRc6>@bPZyUW1Y9M)n`wD>jJhk`?yYylfQ^PZ%OMA_O#N35!kbObm^h}Vo1<_$CJVB zkEm*I-Fh`%D#x|3#1)50BF#q5Ag(x$c`MiXTnTVpz>Q`f*V$Fuzkoe&$+`ht8G#$? zX~X(;aEvx^(p?Xu&df^b&`M;bnji4Vi1F5S27GdDF7c^D5lD}SprrCCd!^%{ zx3a_MQ-JFN{xtizE?t!LG@bt7>KMQ$@uEXyoLV(^j?NyWM~w}*;y5*wD~9VOq*ZhcPrK@ootxO#7nWx zA|~wleGa4-)(SlO_CWTEgZoYqp|f_u?>E~}3*_#sUC^e5vv$GnoB}_7t&L%G)-HI~ zE-1f!J215RxBC&mcUIfvIRpXteuyO0RCm@c_?`8q;L|z{E&7ca%hBmEY+_mvhQ_z;a9Xw=0Tk6i8kSoh7u#OYygS(_(XFnFW!T z;;#*{k#YgiP}utEAB_xKe~XI!^Cz)uN?*tu+nMr95+Bn3cWEa*S@^pOnw2d4sG@mX zMe#TvD%ZJdz8jf)Rfb>Uil1Za9EOz6YAdC~r{AeqGp_6qH!sBxw)fwpv~C=ASus2n zPqwL;gAT+ebFUSzpGW`|x0M&c3w0I$*x>JXD!R(!cqy)@6j6eCx~IQ*o{E1%M1R@T zQ#@ItfC|@Vk(a+sx%-L-2~^&S@gmJXV$Msk)g3Ya;~#$8j+i$q*~$w3oYLR3uaeCG zPVexy-`}%uoNa(Oe^0%X`2~=&Z2Mpozkssy<(6yI?SnC&FSp|G_jJ^02mCvZu%T+J zS;m94Bs65%Yz;26>neg}b2BB<&hpKte6z*j?`e6;{XKoIt#yCTq`#-gIOXP(+$l%j zUCFDlfihofoEpj%A7?vmlyJ7+;x^Z?pS1bhSu=n;_= zG%l3;d;07t`s`tk?M(T5j?A91`2~F6C)mf?uIc!D`b-lq0;V}e4rW@3J*_@_x`tto zV;%mUK6?Vc0D8x%q}4uq$h=WHj9)f6p?mI8F`aijT9c0RcC#>kh*O$07VZeJ%uk0WE&(TY7yi^ok30>d_u! zD*m31kdj{jY0D<|QTzfp`*WU_V`qlaJFl7N10zhaK3yHdwPapk85ji z&W8-ALOGt}Wgwo@fI02+JC6OM`FV~V&xr`(Iit?U za|#=P1kn8 z#50BGMr6;J@tl($wIYBf4toyeQ=6oxsOCC6XZ$Li-|_h)oLAycfae@9yNnA1@SKyL zqR$?5;~B$qBeG}Acuw>M_XWA83(q;Gi5CIW9P}E@w9?>e_1PnYIG8hSp_oHtl{91n%( z9G}YYoa0lc&!;nq=SGwsI%G8V7@jL}#c^sVR{}hzh6LOYo*T*q$06Z4$AvOH=eW@8 za{)BfkLOG)f#-~n0eDVbJT^biay(~(G3vw)1!G{3PgNP7vqle#=LWJzkan<;^f&?X z_vvB9>EOB2Y3y<^2aY;TJXf+h7B92Ca?Egp@!YLl{pLLf>C6ZTo?Ac!);!NFurEyf z7I5#$;)g1IYhG13EUc<1?hjyLbvZ1ot|;zsuyC#l;3i4#kd&E^KRREIXbj`O+4n9* zfD7MMh6~?YjthAihzr#rr;iJ*8%GtNm7|M~l#c^s!i7eij|)}B&|%h0`@n_o4RE0v z91J(%LLv+ojvpdd%@!wIs5}F3q2tw)d<3b}AJ70-U4#N)RQ=6ox zsOCCcX#6U}g^oYM(Ix%_xKMGj^C`~&Tw+Xqw5~C^Of4~crv*C z{kYH<8rQ-SSJwGlX&r_uj$^`wjw@xj&~atG&lO1M<&%#KeLlH1m-y7-^GSGd@ZfSh6fSgpD#L}2Pn|xW&Ll1zQF`c*(b!|Sup~X5 zr{GF}3)PT-8^VP{x!^b?T5i$T5s^d-{7n)#keH< zoV5d%i&+AltxIE&++_znJUPt!2;Zw zj{ULU`*E!2!;^)J)>g`NSZ0d+eN2(&1?dGg#N2)}I(ikw?;D83Oj#4e$t4olxfl0D z-wV-@r}LErcK!zu_!&A&r5qV=Idsw$KdHQkNjM|!FU}5%pIjaXZ@)$<=B4=I@(6f) zEfM`?%b)SrDIS;9Yb%!1D!bOG;)Gpm#Gh6s>S69P>I*Yrd(A8P8*gc^<9U5^-v|5c znd?^SrOcj5N-ZSDX3t#GOiFj3k>wiIy&*L=duFpUByyjTqfW+^R!7*7MYCw&J|hy! zBDK2N8XPPWxz9)uTzAk6frHjVE5!&huUun!%I`Dsxwh8*J(KqtiHuVsl(F7tRK^v@ zsi9mkd**7_vi^N;TIyQd<{E~3t>ca?x+U&#pOJ-^?3vBmt$&02jC}TN_u1106VK3n zMkBLlZ1&9Nq9b;tT0yH!dRzmB@~KVIQ&e*$J&rFW>FM(MBl~ZOKmL727RP-?#)b0x zjC}SKef9|7o}v4UMrP00@a<}!;3ev|b*o*|xzEUFns^Z~%`tK?(@N}V_1Pnn?qK#f z)^VSa&z``ZN$)t7wAyEn?3us7{p7k-sLVr;Le{sA%%0U_F}bW1LxT1@o(yh(aG#Om z9QPSnLrPp(=X1r#8R#kvH{1YR=W`{nXTpBRmGwSXFrWP*_miLQeMahZ)KT+#>;2Iz zQcBrrDY?(6j8882P(H1bgmngda&0d0sl(^fI(6G1J~vI8X zVsM|4F_rs_93drpW^=D~+}P}yW%n6buF)rUC>R5Ke5wL_W~*qT>pNI71n1F%`;4q* zCHC|T!=4@|K>mG3WEgOt5!ZhQCq8O{ORpCHo1N7G-%ZzR5I4P|_?tt{>Tr-7Nf>mW z(c4G=WJJjNr~3y$)?a+Tyx;$^t{f27RTOjVX9qxZff`}ZbwNdO2@xPgP9y;jfA{Dg z68B`Wd!NuE?QJeErn#c{&z$?Qh_-S@v{e-U(jq4O)teNc{qio7v0u)Faq9i@I|QNF zFTbN~zx-$Y`0`&?_VH4NFG=|+a*PdMey!QZmp^H?T%(HN*!?I)g!apgIw1tk#VBmZ za1{;OFaMb#1pFxPAXOlj+Ak-<_RBvtSc!2iMseCNSDpd;mz;|+f&=^M&kSL(U;ZgIBQIVc3O3{%BL_3B#GY24Jzc}F z$FWZPNssa(vl;E=DaYv8QJk_VhRb3iiuEIKR|>`RSkEK6q#a z2(4tkG|Oe3o!_o#swlqf;9%MLZ7|~JFf$G~zpa#Q9Md+$H?JHD&Z{UM`?nIJyrv&f zUQ5_~B_~9>|HJ{+9tTueC!H^W9?q{* zVkVsWsWP1Ug>szA%Rro}qD~*DD%a@ZymEALmNH!1r{aWDjXEEvDs1SmZ>D|V)Gs(? z=mX|{&%8B?Fr0e+5H-+jal)yeQkt^wgIj>eP=t3zaVli|@;J4`700QeTv=mNgKJqi zP8B!g*J%v{r|MlewVXS`sR|!}Q_okz;JlCJ_QC6!#i=8*XUsU&hy|yX__W<5YAB!D zBt1nn*WpyPEYObH=O+UGv<=`-fKwHxeSYN`fKwG9oN9m1C{7)bJ!8hHMsR>rzo4cI zHlD9$fKy9MD-O%F5_?*G_H+%y9>+T2RI9BVrz$`d+TSyZQ%7Xa>d|!%?O$Eie#euc zLenatS+B-RXj}_RTv_LHrF9stIF1RYI?!5^zH}mFkD!R9I&?)p4N=r#db;?CD(#O6#HY#PC?_&iinE59sgeeV+y@K3V+uZXf+sRLbb-TRST%OZLm=$}&T4b7f$^ z{Ld~5ko~gF!9sTRPHn&JlVpJl`^s?P9hJf+{=GiD48(zgiVb)Chz=d~Inv!m&p(S~e{gMd7g?9`YcFh(iT&O$)aG?T(3+?Y2#f6aZ z%j3clS7~XkIDTND5eByZ+If>|!A=xi|KDjoR_|)O^34RUX6Ja*EI($B@ z*BnK)*mwJ=O1RMeo>BYdh|)ucj6r(T*Z?i_JS7t$_2+E*)Nqga$OlN zwAN#jw7&yzp)n3zXoL*Fg?CWM>ElA>8hv6PD=rM!lR=k9uwPoEhsA|zS&2P8!?1@i z4YU9kf^bd)7Y;q|Q)a(Bv?Lr^8l4`F+!n24UZ{^Y@tce;xG{XB4e7gd(dr2m_4$wR z_)o1B92MGg;>PfAZ;j`6@y(vEM@ZGjb;TE+paGX&O49g>qv7S%d_-tYp*s4X7#u6& z*&W61zdXTBoO8THZcBVcTX^|-B)Bm=?~;#_BawaPweV+;Hmo=hzUzL{-`Eg7vLoL9 zLa1TJ(Rg8TbP6~BUie_LvO8Y5En16G^Cmp=y$Kby>y2~Ce9Ioi;wPWieTTRJOyM_45#jV!{yzji=g^mtD|#Acy>Z9C%-9RFr!QJni?Cb0P`}J(!_jUhmtNRyk zIW#jIxj3p$@~o3;p~b7K((e*azxLQv9rlWPyQN0IsnF};%+}Y#saK$?J?!o0@g;(u zi03+9XL8uWPh=c%oAkC>ZBLPZeHUp`+E~GgZH1uD>o)9 zxAXK0|0nzlu@w3Y|96MIm&4u*RCAEGF8=T2dDH9R$c6m>BAFvq{I3gzJsJbkXbeoN zge!T%+ zd5*A7MbFev(`2KOr#fgkNSY1>FA2dNHNItEFT~T#Oc5%(6P4|XuA3BZe|fy5qkaE) zv8|1tjODDWF=+{Vo#fl7;HSdg6O>CCsYl41>Y(w^@i=kb1@oT}-%@*^F8v^}X*g&p zn$!mq>xhoSWs+VpTS-}-rDF3RZ1cXRA+h@R9h99?O|`T zlKoscx9Djzv4{2WO4!>&t9B{RGx|BC(1-X*bwl}63VKvO&naj>*&cx*&r*8oG01&h z4^I#ui4e7ykVgs0Jj#O_$q!MV4N=l#3g1H^ncalZYKq(8a&vhT4-t=4k0_Oxnc1XN zdNKx6P&l=cI*?OGwnprSHa8 z0YJ4q68Ip6KVy~EijPa9H3Xa>LOt#+m@F9yM`lO$c1x7H-yu%g zVjBT(@qCi79-a}j)NxWF;^7pDA~VBYuNp)A1z&vBB-K0b20esRZ;=pT45z3ma*G7} z(koq(bRSWfZDcx5JsTMI z^8$VGoJ+jN5|jBswSHk#Q$+eWj}qiG^=DqzSZ)#x;f%yQ{S=ihj(P-N6jLxk=;h3V zRQDpKX^f^Gp$3hywEaNT31WXv?28IK%1)$uJuAuBhv~Y z=2?~d46$7*;^)L^d@DUeo2Ww;C2bs1m`a0wD{ZpkU*NG*F{%r}r540BJuM0qTf!bQ zLFRQHyG4aWGcpyDkMNL@o=Is|ihL+sMz*k0h<8awIjikSD+T)IJhUQE#KZ`7c>zPD*Kb88N68mE;si zodmNUdcu)fg^)(7G{OYRV>`hW2)G|(uh6TPhhkF9;b8n!1?lbK} z)cw&mm*#pPqTBq=)dbqGKDkZ%s?7b>Y zMCgJ^Vw3nz_=1aJbdLh&MW?~*?SyqZ{j@MTMU2`{$fL?vSFMg^24N_;Y8CI@!myBL z@~2Rnf=Rc9ay4ugBJ-+rnyX``Q7u)~M}Wzhx5R)?(`?dZG-Xqv$gtjA7`@mOBxw!n zERNQa_bA$gKLewQUYiIJ6EPDdV!TmXjRXosB@yf?c4@Sp-)CJR z$XXq&VZ3CXC&_Km*(!NnG_I8MqP0|zkuKm@EtUF7J?6%$8-NU6Dan+oR@qW1^P+^( zq$Hd^q=FVkXYy-;en2I(^Akbjm@jywY9niA5$)KU#&YDWZsqAWn6=%TlGTQ(pfZxi0q8!Ct>CgMrTd4%E~q8O@5 zZ|8rnXxc^M^ExbR>L3XohUsrB0nezewBRlUh|ij2G78^FX_NO^c5z>egb(;l?O<+I#0h0v$XG#mkz@W)mfk2!?MNk~ldUw;w$TbLlTeB1im1fsnDU_# zGf9)-t)zHUxeoCl9g8@s6^1r_0esp>A&t#QJxVPQnR%5bDxFSkZ}aq&BIroeX<#D9KS30)+}=-A9TCc|wn*V6|m_$THh2wK8@lk?1znNwigO zGXdy^^0W#d*ipjz&vd`$6ch=unh`VvI%q|tRzE4oldh)R1+*;C(lk+%K%lF=Kvy#@ z2q_X3=xU|~r>mJ3q^p@0Gy`n9(eCR2pH5)~9jti5kqv?NUmj@xRe|=uC(!=)2HO8V zD-kO1kM>xtAXePXsh)B?9%%l#`*v#Nd6({Se=pgszer2mqs3mz0BMsc+XdAG8*H^G z>&w(85(#N#p0rH#fZ@!{{>I!+6s`iBrX_%@Zkd&Sj)0!e6ed3gK{m$QVTRC-baMJ7 zJ#_IPEzJZ`r9VPjzwC=3*F4BdO%QjW9quqD-#?6rmtqrwZRO@`Q~HrZDW)1eQd$ zT0-+(tejn@U<65^NhD|}OTjaf@XEv$h6Xjst3xhnq|LqygelrY$vg&0KLrGmHNyPk zxb1jMkfTEKC>@p7BJ?Q|3zcftg^!|zkev!)Y*4*VXcEmPO6D1JGo;Z{%!{XtnkL09 zNRlhlrZ%{Gy_E78hBO5CD7g@x7f34v3xOGH*F5E}Yf?~sG)aEV1i-TN6J+o?OWe|E zN=y{xTUBls8H}4Rl3lh84PsE0N^4rG(iTP+i^wHQEP{!I@)r^fqphw*Rz6LYc47Ia z&}4KeS+p8OIaqZTc#8^(FLe2C(@Wg~>S?p5#bggjLRgx@f_gWHXc6POZ&Bk-8`tw@ zqOZko>J=LCIQe@iXfuD`RAv+rA_bXgX;Yg+7oWx@r* zUmzFna5%F|?-CnzCre1mt)ehkD2a)@$3jeVUy$D_ZGoC(`Z+|iZAPce$Xw~tbC(i* zMWN;@kd)G=--;JPk!0l#7_g7j8FfEPEOnNar0IiN)=<;|o}YvoD|a)o-UTyM6BUR> zte3otrdZY33%~^=eOl#fmPu=|LqQLz7c|z=Zx8@ZN^7Jlsa7Yf1t{zp5h3W{NvSZ6 zP_VR&x(~kds;~_1UYN~ z?ovFEhj)4V=*!#m{0NU?Z;C;|1Q$-dK~}dwrhzY#1jPo|=y28o z5+#OR-o)S)ggJK_@&V)$Q5NWFoe4`BQVCS>BlSwAV_wYr3Qoq2(e>i(29i2 zqX08CGRH$Q<|Yb)u#`k0vy)gMHnnc1>RQa)%%Afx3~RXvg`l=G+oO%{mn3 zO{`QR`buJ+mbuD|ry0~9Nu3cC1u1S~`0-=CiBGq?TyI-NTl7XnW()xjXQaqqRfyE% zJIY2oG?bASD+AU)35n9AEvciQL{f z1@4KO)aS)qoDP1t&BDY75)!UUpX?Zt8NLiHZ33$d0qLidLf z?Oo@@D|aR;*%8{4nEIslap;|Q^ZyUxEp2s)mW{P=$;+Az;o7c5OE>!t?TE4$+e|O& z(-8@KPcyrDH_JpWEkG>7kbYR(0}>~j+q7(CZ3hxmXWP2XTha#qU*<(pEQ_LdYa3-e z$A2J~vwfqe(X+rlm5I8v*);PQ)nMSDPqiAhS=8`FBu$YKl^dB0iIS?wXE#$827T!Q z9t9mWJT);z=C&zCtWA(jvyYj*BGAu*MDrD{h5F5c4!i^fcrkK&-_X;|n&WrbgxO(@ zCPsXq!D>7Y3K*`{;>t@Z_Ew%!Qlc`ah&SRvW`}FOYqcTs(OXSHktO<>`)JT=YCmPG zJE$iTW2HQx)#Ql49kp6x#>-AqtGm?d18TLNZay%m)x?ag)#UbD&C@8YJ}|bvrl80Y z{meZOv>I|w*=lKnNR0KwfL4lxH)azs+nk>0h|_N->M#CEk>WBD6;x>=iK z<*k-njPaM0>8wwHXgceIuY#(1}OnzGOudJL_m;K&mF%zY+kHH4nB)t%Pr z&OxmvMS(*4O0r`S5)L_oTP@Tma5-1XDiUKGae#!A zBa%9ioYfXyF$4dfQFnOpBUo_VrW;$up(_1gr{Y&`5f~F#&}!L(%Yy>7UW&}Ea@cGm zFwnR4c zP0SI7fIQhCtR26hR)whcnS3LrhEQj`WsBNJepV_gb}YN!k#ig`b2;V=q=)v>#ccKC zl@ftP@$9cBb6e&9vf}CRUECa35zpW1eWnoF%_Ce0NS2pB-r!oHzYmLH( zletat+&xjfC9;3MhClS>Z9>^4tryqC;SYs`LEa! zzU!}5QntNe1`b_|qjmAzWAVbpTL`RZEG%46QJ?E2Wip;)(c6$amdGAW=Jv#LTg`6W zu%hqwDT(aXWFfhtVn!Rr?B&WR`MEQmuX&^-KU2m9Y)W z)!!fh&*KXsF<0a|$wcKl z@j^{U-_=v%v))|xOfpM3>cH7^3m2Q2en#Jn!~T9meh&PdGpS`uCB5{?fV;i@+&$KJ z_4L@RBg-C#yEEbLY;hN!A|&GO6mi#DUI_g=+&w1lGLC${qFNp=u@zsx&G7+jZ5_nV znZ~QM$Dplh$i0nB#9CfD8Qb%Ato`ITcr-4Ndl2u%hRWxYx!nyK;#$ZivWyMf4I2tq za@OREP-9_QGfU6E#t{!DcEZN!F{z}Be)?AvD!Ol#KB})gjzeR1?=h|1z3SF@_HZI= zOTW-sLNW~%;rYAuP~A$#&obb>kIXI9Jl@haF5a>Ymz^zDv6h28x1%M}`?Q+W=7k*E_ncoZP&%)oeKhu7fmWR&aXWlt# z(LVlzLu9~>ME`+=>5L^zSO0FJWh=apDJi0*dvZMKy~*Rru$})}(<-X^hrEQwC-KP( zr{|4F&lZ)-n3SBlG2YVK8(#4hTC3S@fULOt?&sMI)N%;7S42?CJ(1g)f45`kk@UmwhS2OJOvCO7{ z`lWPdZJoeE6KJ>IJaUq3?&fDC^S4T%s^a;ySD)*N?K#;9REp=nG^xFJ9IAU-f|)k= zxDz!Tn$bmtn!5VJy!Z9Rv&S2=drhN5{2m*M8=1qC=y;|ghHJ7g&8FHJ3}fUknVm&b zvM7>Gp_Xk767RkIzgit$jYssP`rL5}dJ91AU2$TdSgucIZ>2Mf^jkYEmRwAhXdWWZ zv8R-a{Z6S6c1KK><;H+KS1aQQa+nOIfw%~dcO5J6l$lvVtrUP5VVF(7pkj{U1Y2|k zZSo6xSp`jAZ-togmGOY|Lqavm>S_c{j$K|>iyFF+NmYxN%_2pE3DJ}tZ5Qb~Notz_ z9R#3N0L-?jn0id>A?>xYFg5Se_Yh!<^M|xNaobXF{RlVbN^S6Z6JF(+3MTB+Uuv*w z#2s3wT4-Q~Ehq@7nGZah!K1PlTtD zCv64EMG0;E?Rep`-b8LkW7g)H#ZrvzNXJ3xf{Vvr$#gC*(|Ue?BWbB*!lp&(7lT;v zG_kazTpged5HHgP$q%Ts%=`5legE+Kp!x%354~T?hg?$219U>h*9mo6kT8H)%q-xS z0fg;%C5;@QvTqzb{yIq^#XZdUlOtR+(e&}XfltJJ(KRmQ{=g^V0rQE-S0-%@lJ;`j z_VhO9Z>&NG2~OouKD!yCjMj@|`EzWj<`Y$gn&xD-qrQ+~qyn-)OFQHF&rNE~KCRa& z2>X*O`dBW|!SUSvQK2>)v~vry4KFp!IGh9)gHD!4FHRONz2=ACW(A@Cjc2FA%=ac* zHiu#@TPE;)bx2bAwJ80^3T@MrT#>OO?+5RS-eaBd)x6n&39XH1zr?De3w|?>Wis(5 zH}kSTS3K6KJPgqIY67Gm86Do$O8TnORV(isWYQi6f=*9a{!nv}*U7z?J)n&h6>`WG z!iI{CM=x9S>#U(pjd|}TnO>Nt{qd|SdLdiR?P(3l_M8UQgQ5&HMZ^{r?A`Q+E1AuZ zfHIVfS(hjp`$DJV040bE>BBtiH#l~6Pkc35_WP8{p&>072iuUZS?kj`t(goP6WRLc z2};AQ0KKq>-GAWxMruT%@T0oZuV63QPBfdUpeH#G>X?K%`UtO>bwtZ}^QL1(Ez1Sg zZGL3f-Xb=LMr}Himu9nvEc*!c%i1hehjMfK$t3t~-sKs^{7dE9TbB-5q``I3rGKv@ z0AinaNsMP6tZ6T*K>6ZRqa2&kIQ5ynqV}|WB&^);z(;``H9^Kr;7g_j|RjVA#g0VY0*5YI+iHv^DM_P?+rS zwGo1Hmg*g#oE@Gnw?Eu@s0z&|{k%Zy!#wU$l_>9TDuNsw09u70{cNcw;|d@ zn-GC%$-*VK|6QQBlcu+s=45N~t_#((a5lx}D`?^WwaM(4LQX;Bf?@M-wG{LVBtF)u zHE*HPpLqvdb<#P#MC|RxQ3RtB1q^#LBB1k*3?04-a>n2Cf zWBv5J;Fm=aC~5DeDF!juQb-5QB%@TKn;BW;MCQpu%9}HdzL^A_@{9BSlpv{B?HKo^|#5@5zvZa6L@7_F&q2j=6JS2UL&td$sP-)lWvN-Zn}b=r`nUEUhV?;J)qN` zCb=D_(n+nHI@;*jc-h>~m(d3Y_#vo#;9u8yP zuDMn(uk!L0vPYIk+AsMwX*IjTE1TioB$=H(GtYOunS+fsEkM%@etf2b;xrAUi+*|K z*-2|V6`HP?)ijT0RZN*WJHZPW&RvM;pQi){-Rf3n&4?-f3 zS_;dRN+?IiOuTbHuQFh}97*KgmsWpu@!uTzer};;wDBct!0Uu?kWP4*PO;NaDY*>V zaFyUY2YwMQC;QfSj<$@>5hVk1TrpqMlVzc7TI; z#u)AnVf_4g!lQ@!M24JvW<3fT79Td^#LV^h$6w&2E+=LFC5KRRLnSCqNAM2A=Kr1)lBqn`;tc@qjJNc-Rn~t~otG6PY-gVWe1A`Y;n!n0tSYUJp zg~@0GO~e@?HhHHvx{3DfV4_72((C)&nyrS?e9+=u=kc=NhZKWmZ)(lFq;sCkujKA^ zW%?5aum@WXRLpT|yR+c3boo?XaR_q~mzKjqI9gRJGUun2BZ^vx80 zZbF0kTmnIeO^Rk|T7rNqLV+0sr`jm_Wh&KiP8Qw<216p+^3f`D2S3cZmT6B;SC5c^ zl2qi=J~~8cfl$hupw*HsO*g6uR@-C+>42xO)?UYzez1hOavCK@aPuS<X0Ox2-@A}CY<4Mr^Bk9YNKS3-to09ho1motsR^Z>*5`xU|jkTJUX-Aue}8?G%p*vhT2&DRY}BAbnF!Oqf`b}WJ!b52m;P5eN_ zbP+pwEdl2DsYSQk5je@=Y;|(WHJ3RY%k~il@WiHN&0;=+BQq(Gvv2(Bu$2r`^e<2RMjcZX8#^qKVx(9vKh(2uTRJ5(qyy8#SFq$ZSB7VhVE_0h*{8V6#aq zFoR1pKbwgLV}dV`p;r1Uok#V-ul z;p12>73d}iq9bOiVK0$Hr(`VS5<>hWbv%MdkL{|sTufEMF718ab_ly&Y8 z{=(t4y_BQvDZr|_|B`Pg+=b9;a*O?(z}6ays*XY9Tm1J=N~_CKdr5`Ib6WQ*JVaa% zb-)a7;wN2MW}%W2o;bq-s7jqnrQW&kSBOS4`Am^OoG+CZynYXHRIcM0^5CL7wmO7sZv z&+=a4d1@!&T51?hV-Rq>p00+Wgrgg=!xL$6kLEEXSaz6P@FM{an_oL; z6vXHzs>f)69PqBVlC+aMlE2>>Oiw#$VCfD%;e`??2!5>zWoKe-&B z1l0((3ejCE}l>a)mGiKZXE0yu=QD*N~Wie}fFJb_;oj$Ij;>tqwD$b~wy)~Zq9a&gW z)h2G*xjsozVsfJWKuBPCCK+&A(T+&rUgLTati7HT?2CM|_1i=qmz@@CT zlL0bWsB7V-Q0@o>96a`XJln^E%pvS$*mRg?t#C~5q4lUbHUK;L!^CFC#kB6!rb(nm z;2=`J$!)c_^oE!HfP(LfK1ls?jbN*K(=F^>X)3=rs!ca`Wx~8{h(5{-5BJ!L!`Tg1 z8T~>!$N(#Gon*shq`Wu!j2_Uya%W)cg7h*!=nSN6Y^K;Qr`jwM}GrdLZb&=p+k*o|Lty#*ers zs$0`YLQE40x62X&k#r`V#3V*(S}uzoGuV`6-Jm#Aw$+_l9OwvfVrhp@@AtNe^> z0b_t!pBllpBx1N=IfThZ2-T>Kq+ZM)LZ`XP?cgc2OxLTX{3TZQ6nnMFi-WaROs#_8 z5|wA}4bs;~Zy|Dd^kPe&b{0hobSu>n z;+_#_fI<;BJ<%u2qfylYM9@i0S|SJhm5WJ{f^o7G?xD(uDf1oWS{1#Abdby7z#v8~I-ah>Vd|}v&b#}k zu}SO^1U#vQRPVPG-9ZL`D^F@DfQERMtzAlY-pBGN2^gZoEos~86NeFMGqnm40*Q#y zI`**E9XxMV&I{i7b8=cHmGg?;5OJMAl({gY^U12hE@(&};LRlK+%0~>2^;+Uswky9 znWSkh_}>a;)u&=aF37x=KdFsokJUO>mQ4^BOB6VWkF=V{%^|SVo@@v*&S@ugKB9KI zCUCV032g`pb;2S+M+(ug>WD{Tc#bugf;2LN19Uto3?n6Z?la)RlNNi_pqomxdkE$C z8O-5r3MIYl*lYUc5MfpPuM<7SItFyIvWK_56uE`JZ>a2hoM=$?Jtj4TYZyADDQ5{F z@Dc?`%R-PTe69y1D5b;kXh_|fM5;x!NqPmXYWW#Kj2R6?lF8zWbP=&oVA&n;)46C# z`xNraj*94f&^4M;bm~Lv9GT+j7Ci8H;rOuqO~p$=wRe@)E0N;1l&9&*ZQmn)Q4k;drJZb({J zmZ+=K{>kNOlxt@rZH)HN09C177mzn?)Jn{5uhFvDHjp=x#yZ|EkF)J$4FopJNML)> zMzlJbLbOEDPJ%lwEvx;#(PqZ1ao+Th)ua_BwH+ok`bp*q8`JceO*R_h>QHi zIjfrtfo2ucDrm9O)y^RCbLvOr{j;_*^=JeN9oc5OP6L=;vN6_2v}(rmru*D9wW7O)yaWBDg+-7``otv&1h=o(4P z-M{lDi?iGl$-KkCa!?Rx)_P4?IGK0o7q9xCh9wWVE2JW?P6HfKlZEN-D`&SQiV7SwF7dx~53qb3I6KH?nF~)mxqSWn3E@PHR znaZ5TgwZFId6HgZUSs~UiFvvS?TFY0%O)Vo5*HFIn;6ioE+kksF@o2*kYL$FIUR(s zYSXH0z^bjZKQn0kCXR+9y5A=Ta)%obAEJCcQJ zb8djYmt3%z%W0=>){3l$qU#Gc_h~sZQ~smzSj(ZxgARF;m%{V6#-`$!+tHZq z!)ThRSs%;w#il;tUTyu9Y2QNvc2#lT#3Oz-8=u}6)RE!*t^Bcd)xP?|>_6bSTlug+ z$@fe4;`I%==PBPp%{JYs;Oh0Wj)(9507QraZ=)!fztyK8G?0QCR&bd;qM(;fW<45^ zpoQ31LwMLypO!G`Ej|rf91Z4nJ*|uYW&m?^X?@VoRgKa|LR;{=)`ZAfb`k)||-SA}u3a7*dtNiEHESpW+* zp(Eb-uhn8o7cz7xP;+VIgJjg?=CI#6%yX^lpg ze8A*o`>d~Dar81jTP?oh*`CTad6P{yrJ3E%@rPvoUK_LwI`a*(qYw{s&eQajkulTlHU@~btZC;+=x@N_9wiLV^hEzw_81$^%dKuszhO0k$?uYpZ7T= z?8_(okVb`EuaU;e7@+T;m-r7}uA{j06}^a#EV*_SkKI}}iD00Ge@=p!>i^`eqLH%) z;k3-661zxca_WxwtjEJE7W#g;O~Mch5IeU$$wT=?W#~p}yn(v0q#WtDLHbeaOzFo3 z(vN4%|10i0>n3s!<$q1;GetFx(xgkHbqVxmZf7Bs!+3=WYwFHe?y*?@1MTeOvS>(f z#t<*u|EaTviTu~?&{UI|v}DCP!XAG-`znsT&CJoaMN^HrM->@oB)>_+G1XlB&keaF z3Y$_`(ibZSp`u|b%3~jHW=MP{ z+S8d8;wIgL8!HORrKt=}>)sZpe%P^n3c{%L_G9ca~3HCK`UN zFYw7l-q0w8q6%o<3{H~zbEX6(dF?I%VKYFvQHY?MCk^X28?h0$7SpO`+HJxm`B;><_-iSZ!j0RL?f^pcSSAND$W_Luk5^R5Oo z{bsEKr21cQbcv+9erS{8Yd#sD4tuj(KV7H^I|lIrnU@Pz!BFiel?m#ds8>AX!@M&K_HJA~kllesP$|V}Tk%p9Pr5)+hgkTn)DN8-j(m>! zB659*1G3@e7or>M^Y4*B`XW>}n9Zi4Wf(G;h|~ zj)P64zp>TVZxbINiX!2V4lcd^=^=w>wzSdP2d}j0x(>`$R#Qp9CDNwRsO<(<+am}6 z9B1x8pAN`ZqENRM2KlB2`L>+8Mdj(=T41eu)K1eA zAGtk*AVfYYj^mia?}hp~ML!6ffJ-pz%{cti2|^TdE7tMb{`DO55=VVLQyUNb(BqZw zu%3(cU1JNnF7U`~tpHw9Zs8G?+0>Z7d{W%UBM;at$T;`$2>T%qbLj2gg-3W69sz;G zD^D__?gEm03rHe7@~0!=k=XzXu&tnN9B7*;SU{Kn!T&Ne!g;yq*x|^W5#h*d;T8Yg zha>;ryP0u-U8maP2j>Gkhnz23WcbDTyvv;20sHCw<^E8w$O##uOWZ{S^a zU*KKl4CF+)^(qf;!5W~L`uvBJoH*i??e|$2GESeR64w3L0VuMeaB)k%vSI2|S}}6T zm7vFh#_TSR5ORgJywfs?>_&WH?o=}t#W|N?=a^fNGmwIo^_t#5!C)YQ18*3v*2j}`?h1uumMVll9RIiWe6g2xaxb1TwOgm)&=R!z(Hy;1B z#jaH*qJ_Q6?gJ%CPU^l_6KCs?$jD`HBxXIb^lH5Oseu!@R$cY_+_C<;Swha*7{2?D zkfZwC5!OLdablVOtV^1iygs+Be(Dqb8AZ~;MWjVZv5UKsmUFp8l+PC4`!)9Gm{!Qk0i2CXX%Wd~X z2b^*N1uB;8{xywDNbFAfl)mg>-*O;{)~U3sPM>m+zq{Ou(tUi&!OmX2S}Kg0S64Nv zBD-u)Ryp_O27hl^#DeX_xJPILp=J224}ZVS`{yE*_YFDXp!yM#Ll)g{_c;}dQc6t%1n&C6!ak6LhTn7EY^GvcTf|iRokzD zpp-Ja38&O^=YGzmGed>>YVTvS$f4I~$fHvM!B-n*>siK*HkF{nwn=~!KQNmp`Fso8 zq|N-@|7N8sLHZ%`J_0e%kqFZ;TuPh6+a~kVCYvn8bt+EYLvYsiaSlN0eNHl{#K2QV zdy{7Rlkq28FncT|_gQam|8VL2goa@@9TPse4N$ z;^E~AR80$YUw40D{{8d{!mKCBG^;KvV*9>OI}|X6_+jJ))oAChpIUcHOghG_!t^i14HGBk|9^~ekPfFSyTTJN{DBBHTB~um&`X# zN@m;46!Cz~6rU;7xceDa<3p+&8Gb5+!PL*OySH(Mi02-&~&=6Yb+tuI`>gKLar>`m!}8yo5g&Kei0@76(Mq$`er zSYH`K8dmHL-}Qki$;k2gn_j*sUbx5RiX@Ic&5$n?ut+EXY1C{U$LB{Aou+y@atIi7 zK!#>})z>8HX_Z8$t|){K#0%5Dsh36F%QXKtk~;dMX*`*I2zWmV32CKxn1S_J4@TG~`%qJ{g{W-fvQUe~QdxGPE~L z-P4~RQnw$xfeg+MPI~ele}b=vpM{Cvyh%zQp^`5W5AIqT)WC86qn(gMiKH?H(|ksL zkm&l<3v;ufHN@}@6x-kXvXbFzLoPyuzsQcl$!K-1 znM`gNlw~uzTUpvxphFjmb7wDjN^LN2C4y{ux!gRO&|}!Gq#|`3%(-+?gBxQ!-0!<3 zF?HzxnSqXbtQ;aWVP@pv+NFw|^BBRPAr+`I(0FLbZ%VJ4w`{)Dj6tJ>Pi~WckzHnu z6x2qgb`DY}n~h3ayWVdHgatO52>1@pJJ4o`9T@O4pcyY`z^2pviJa=Ft0umbp$iQtS( zMCM*xUbpa?3NQjJo$qQauxUQUEVZ;qz&}FK6fsFZO@?ur!Yf{VOJ2qPWWolsCJ$j9 zO&Vs6h+|a(>Bz&lQMYEan}y?CcdteNIs5(o22453(K-92jk$v*3x^MLZYke!*)9i4VP2k8(BE= zq#lTG!rE}z6QA`&ctzHSH(hW`+TI}x#)=PS0%U;>s)fM_Sb!{mH+3!~Ko+QShb$<^ zkOfz#kYWJ50TtM+e(W610&(a3@kt&cf`ggmI+a8w<0)i_nGYZ`yxFlFgV}E+lkr$N-w@@tcmX z7uq>MO4Td3SY5+n+kg$)BBz+uiUhPz5kArcuR9-V1&*3TX6_w{`gA!&uOTv4SO)Ij zVA>IX<-4+&+jH*RqiV{~Y=&S%-#copUzL_hM-ki$)Y&y-&X{A_!eS5tH z29vemsC2R%M{zOvFJm+LLM&eyD@?;?VpUeJEvrAY)=<=!kj(nriw;FSbH#*;fWXY; zwYe?zQy=Tk3z^#w%2Zd9Cx+8~<{%u;MzE4-J@J4!<(fA&OLx0MgV1}OU$gn|>83H{ zTtk3|<$(wCChk8Ia9CyVn}Ti}AaZ&zv|9K;>4_J?IP!Koc6K z{Q>QwaOO^%G;9W`waO#nA=*5PVepGI!`!KfQrAJ6FHtFGqFWqYO0;I1<<5zQ=i z-UG^MnTVSBk9vcBcHsnWyqV2%x}~QK&&t2oL}|jelrEgU^madYx0>EV2>?3pf<-RY zyr;E`?3qGJVX&0G0qethaZx|;H1a;{E3@lri80T#8mGOio45m+YH{hs=xR>jc31(; zMP?gp!mCygKiw*g4xUahJN8Oq|Bf;aga$;U>y;{y0t30#@dm2!C)@B&=``UCI%y{ z;q)l(6k?oo12mceP#>9ikThDt2pW@c302-}162OgN`4y&?7KKR1o|p@GcwC-Y+p#c z&cq@-A5@u7>&L#tLzbdMMJt4~T)$<~MB7HbEVf*9?{%_yn}t{lEAyJxK@h~42;MVIl^`IK`_3EzL+GUtTi-(`Q6&c0J9p1(m3}GxZaIFn0QV~}QTc@4ObjT9b^00lERh+yU!p0$X?6jFJCZr4f8Yn5LeCyBO)#?4 z^ly?5JYtG);Ae^You&gF@jI0JWnW*6GW2k z)c^nY_2>fTeT|(Z{6(mPl^-ao)rABrKcM6~7ZR-eKu;YmBv|=TP7fiN+pAbS4Oox* z`wy|t_1^#-4@Z{r+3X0*D`z6$+fVs-bNO#Pzr>5>9>o5g%pSz#UCV92eNA9>Z#@66 z4$Uouy4hFxKlBz`-T+QCg?Uw>1tN1$&yn|{W`E89d$|G>>Ph)tUd0;^Y(49(nm5i~ zw7gRpzUx0Ij%}G;^|^z|Lg?e~_mn ziq}Fz?oh1oN8_=S==$p%7vHnNn5b=kXPlG%&q#DCt)j#^2RK?xh(Q@>4p}8 zk#lGvLqva#({tc-I!msS#Lsc;)@`+0V0L4c9m?wG>I+v^8pkD5#$K|89+9ZpXF2D<{B->ag3?!W_)p+O z07*1I#eZhp$mDMsGvRARf{%E7ucfbY=_d+To}62#|JVsW$38ATb$c@RBxW?TD^lxa zC&*U+=O+*dW{i$yhje*&^aqZ|y0trYy@Y$Y+A+{Sx#du*q;miutYusuaCtZ0IbO1G zdo2c<2CgK3$MwM@vBEXugMK)U6@|et`+M=+Q?5sF;0t>nif7q<^)H$%Ok1I9UDvR0 z_kJ$1em~t{%QD*U{jqpT+JvB0aMSQ1dEvL7i?C)INn53Mk2-48v&188}Vbzd(GuD2Bq4kdL_#ZH|64^t8N0%n;lsu|d&$Hh^jvPdY@c-eVNW8W~Bp^!HxMdT$lI_wf_ltD)XY zPVEZD@zDMw_v{~)#s=Lv@GB~Vzt7ZiXr}4OWcJ*vWZHe|5#w9A>lK+6F?2tzBRi?LH)3oBU z^>s)x&AL{05A}mwxgs@u*MhkoV*)emvY!SRk&l(^rJU<4TDr$Ay*|#TTMF~5`t?0A ztR=i@%qqHo-jizd7Jf^`WWI%d=+K^TIE@0co1p-3?91AYux6!54f%=`km_8~cE`Vv z6$PDs7ZIkH&oLgtKKrl;-}I@ga8v~(b?+{p-;>#oh<)(se@TGrb1yU$7DrEt74=h2 z?0Fj$#jeBS_U()P)Y(QoxMK*5{x#q;)^g%q;k*8gCy-CF(AWz(O(&9tFI2?}_0i)k z`%hd^sIG#)Q<-kPcjLz)MeXrL2r2S(wd(l@UjSg@mD~xPc~>)e$j>d^MF{qu$Y*N^ zP8+bplbpvnq>$o3X-M=UF%<@6BlC6I(DZJAt+qM6j}%C7#A-@g5_d33jEq&qW^Hl1 zUR;Mabu$Cz?*lnVHp?=SNj5_-okW?TW-6JiuCkAk2po4%y1eis^P1_rw9PPcVS$-_ zBB5sWQ%i5<9slS)lp>_-e<&r+t^9?WPt0h;rJ9e%jtj=cRVOGvbdF#{zxbu=wb!Cg zJ;M}(Er?&FhD1*C;q@OKnXy~ z_s<|ER=61-phuEi0>pRT5*qB>dAUs#RJ5F|yuI#NnoCd;CsjKz0qb8@!+m|;K7}|=E0q~=2LBLx?y1AIw;n|U$!bk{v!>! z7h^34PU38H;pW#kO}UbIrlv;w{@XZGe!inYU}`)=@Up_iw%*jxW8YARG;hD)t7N#m zF#8iYVoxdD&XL!{ICXz2=)0D!l|)Q)_?b<`X^6Em{NGmmsJ$H7%gc89 z`PvUADxW9mYy96yp{b+#Iatqk&hA&quT$InLoG+f>7|>WYmdq#x2!^shhM*(otFQD z{@oIqg~LyH#ihuxl;3nMXXppO75(5@KVTSW7DL0Bt4{>k?{H>*1b zSOo@t-=pQwqQRYQoyXqY8^7)P?oO4RuY65hqRSp5xG}d`;`&!xWUrJ<2s)apt6%i7e;9+&2#61>5gNq@}No6G-Wf8BdD^ zZz7{KG<_^sUm1ULT+074U9yRot;HR12d;Qg9Ub#B&%s>89`fKrQWCU>OSb62YwP6# zlxA6nn%(%WaZna^Bd>`KA&Yk1pBZAxaXi-WS$AxjbVLaV1M(?pXLVdoWPKXlM_jmM?feRM{#zi&O|J+TP z4TeR#py;x(E@;#BB1UC-l}B|0P38Y{;g9q8f-lu)ZK7K%eDcuSAJX2zJJws}XIJ#I z%h%PcTdXkzQRPqNHgP=zHcJ;cbHRx9KHRuk-L{292-o~!Zr)Npc#vDGoTGd?fL=>| zi8(4X@kdlfe}j(8*=<~2V|8E9Y2N`9t;MrAKt9E>#}`Z^&Fs!^w0v931o5s8{eRI+ z3vDEskYp5RzNoa*m6i--MV-2B^<}{f9!~43121u&&c{G%nc-j0ivm~ ztv>8f5wuX^PpEj}dert6b}h(*;n#1#2&5C&Q)e0kg@YH(Pj`rR&3jo3@%(~!_a19# z9riOHcMS^$@o61g-`Js*N!5SeE-tj7Z#(~oslPc%)(HWvli13Ix#$UjP$&b75Vj&? zn=!4Q@I8f#vdK)fwgvQWcJjdKCbgVBOM4!WQKuz$>nt2CpMcc$Oli^=Zx$%HV?N%zwdj+r#A%}_$T3l1x7EII;2{;#R*79k5ZcZ?CQQD(Qto7RX z+-u3pUqTyn>tTcn+B_T6MXT*0MYon1)w?lbG?+5E&Zq`Xd~-fU&Q9~cIoz%3iu`DWQZY|VqUOkAJi3yK1@60g^RsPVaqCQuY|f>2Ah1gjIG z$h_c2Qp%pvp*md6;$1gT0v#DYHo06!R@lM|6orG%(suHLQpn(&9m~`Trg&`b{NET+^k*tWWbnY2`O>klnyEASX?yRJIbD_-2Q}Ms+m#$DAqfg!k=a zx{h&){!9^c>clsDTnvr{&+uMfv3Qwlr0lXT`lEBU*G4C~nIh;fM9Ek)dtlMpf>MVl zojK8bokz8mf4ti5PT}Aqb`Bg?r+YTWjz9x2(@Lc?qk5K@eY3O{MPwq~eVt;C-MTD; zV)q<{zLJZYSz2E6=iggZ%4UkQPCrL#uXy1E)rQ#N4@}Ha-=3!cjq9$}w_C~fO>7kw zU>5&(A-Qq7Gg)WLXi&q%Y-}RdW-SBq2L53tEo@3*2P1Cv^!jFrslZ(jw4=j6KwL1= z9A2B0yAM#7Z6Vi+aD2`z{x1iMHHE+=4vShNqMh<)>+`n%8M}^kkw+gOEH1}}r5oi? zv`$2OsQx#iGu&%nOI#oD32Cvao0zjeBCtJ-`YTpJi$e)j7-?tfRSs)N4fKV1>#TjW z2qQ7=4^A*(S$qvjqXleof%UvY7HJT_ek#{mwvi@(vyJbvU}Lc==DGmr_@D3*q85-B zPle552?M6_wCL|5GIpt!w^~4V;u@ME`s?U!5JsTux@BmwIf-w!Q5aHLaPe%+Lak79 z7D+N{l$bqVgM-@NQJ=`riUaX5GPkhv*%$Du;kvhyP!!N96>mo57(4mR7i2SDJcCrrOcOl^;7PD zhriZZS~6gd`t(DZ@*nXOEI&18mYM$ZKIwk@dwI|E-o@^B!Nk>Mc{3J2iZb!aa z*6i1i8r6o?Vb{jwoom5sU2|!depe@|k(f(;qJ~x@(rtBeSbW81i2{JjdUa80?fA-J zyH9j=xxtJz6I12>0ec=_BA6+l-^J7DymkC zkRa8(GUZ~aP* zsjCJC>3AaOv6UmLV~ixeWQCQHSkR#=1A{{=-v5w2m!nNWIo>lvFleMD4a?Y(#q*s5By5mc<}0KU6H6qjeI?P& z;HQsj0HN`tfo8=<)syc*!}vce&mAgi!Vj4Yw!)t9 zJY%BQ2_8Rv^RHV+;XO5{Yq-_pN%f8rO8BZTIQZF zarh+`QpfnYn}1Ds9HMj&Rs5Wv@Cazon|V6*MZJabRJx+jr}z&?tQ_3HDBr6J9%4Wp zC80KSS(j3P>3-_CU!BF~RAmWdQ&mn$X(1*|(WBNu0L4zx6j+HBu8Q%Mdt6nQOB8ks zYw~IdHJc>eTtO3`d!t&BAyAV#G+{pBcNS7@b0pcXM@i7#O>Lxun(QhRF0ot!xE=b- ze`p_?CzFz}`o(+8?%M{gK)&B4d5QXJy~vyv7-jemwV`atr6zfT$;J~gZ#%u%_GOF8 z+s11x)?3ILK`m59b3d^Z!9nkfuQ;U7Afz2NW44sniMbFO8*#9riRFStF=)~YS93zH zNd!%jPDnS{sGS$JIUhx4?Bq$O(Vm~F?X}X z!4O}v(%pA2AfKYYv0B(cNwa}+7cJtmicFT77;iz0Bu=y- zuEwgi{?bTdnJPklBO(x-xk#`?pkYXOY@CES3!OgE4au5lR1ynkk}l#aP@yH3nZ;wU zQe!^JYe!zhsxVZMiAgN+pahF3z1PFlGb@@0pIpB5w|kGom%3j+5?`9lQ?>FZKD$Bu ziOcie_>6jQyuTOe_%$v7(Q3dcm@oC|ho`3qR6T(jzT`**>c8+51x7ioM-N#a;O75_ z1nO_5|L;zqUcXq4d5S=-95T}oS-1FkBcB#9lO#|}N$g1FDFTHhJ$LCv6A08I9$_R- z5hxpL{x>I3t1hH5|35>ZYDm+uh*HFej?aP0hhH;d((Cwze&op6$s`)M1oe~WS(s8{A&&Xsfn)8dgX5s&;SRMS<@QCFYL2|Wx78O zrFe8=G{OzJ@bU7mn5U|*ftBQJxHAaf42YO0{h98|r|aFo@}_SPLQJWpr43UonM&rW{KKDF8NFPqWcRXsjW5|f9q>ryvIky6zCC>FuRIB*x+(*rxdviR&}{z9<%(`eV_WCTen`Iny@&?G=Rh(JXEkX}c*AkGot?)KN3a zd1EBExs>42r05OOtZG%!%o>^PxjllK5xb>T=9EmNZS_fRI19Kf3ZrqG3ld9BCglH- zNx+5SCx-&?KBE6op+wQ3M`2d}OW>d`KN_{7}8@TFeyQQ3i4Gjd7o>ONq<`r9kV~L zZGJ}WmmtIyh;)32=7;g(%_;-{rV3GI3I!YQ|kPm#62b~f&g-2serV2Y zrh$rCpr^?*jZ51gKzUrHBUGcGvn#pV}B}rx$$gZ+?~PA&mLEZ8?6eGX9{= z5+{~QSm(~8PKtNbS`hv%bvrL}!X#3zzHL62Kp5}XyJs1XNHVT(vVg&(Vz2)URM z{5Awu%|Z#tESzDK zR60~yoowD}K*I;fpT+_-bN$P+7Vn$ta~_b)hN#Yc)S<@oJ^G~W12h~~Ni^~#BG7&y z7+7l15ej6My|#Ui_uQz2q?>Q=)l{;6R?#2o6^YGkX)!-uEb9>-Ix}Lzh?=Tf%Ff%_ zLO+mn^11PCt1r12vl0dd(iiVn3CO4cjhEy6Qg8Nu0Q+Y>!@b zT}vKFFN_?035O9vKWqh<#nP4#8Yh0wnB_E!bx5y)a)QO0>GIhiKZ|Q*JCemho8>Ac zSb4m~+9)}k#i~jL5U$unQQxhYsKnA+?N)SUF9i;3v6%d_U@}`YN}}j0ZTo$Bp6Gkn zDwtTR%IW z_14|uibrOsJ=+|Q9M4eC+GTdbW=t3?g!U$ zZGCPnQyIUm>|EW)TT#Ag06U;1fK>zLWj*$)@>dx?C#))C2P|H|eBVZE`ZilxiK6Od zls2(cHA9JqYza+-*H)GF`S^pIUG)?9I5}nh%;U9cSTE3U)ouLBa#7-w*K@zbSJ&F) zz!7Vn_ic8NU03GDoIZrNh}MFatpSV!MqGc;Dr(E@H(@ulEIIEr%qqq?zRGVOj@AO) zayyA+M7|0IJ02+XN(t$)aPUmPLMvg3dxovzlHcfl(P0oTjyi!>je1N}r3xnT2Y2W( z^7ZX-Kojx8WGSJ_B_c5T9A}MRhiQrTOhdpE0cErvlu^FK7mo}I{Ns3_sJ8p9wuz#u z@6quB)N2Z#k3YEINtw9Ep;6V8y&e_Sse+2dAQT;7aU*&{WQW%j4@Td9uPG3$cu&U( zf+8b5PE)k4{HUO4$V6N32cvJJ2Zd&g_sl#&P()|PfiiR~P&9Db-;U56z(=ao z*%Z2uVDM5qAnK$}+{9Po4{md4B|MX^Vlm>eP*v)%a4^M-BOVJT!Rk5@2A=cAuY>Kx zd#0Zt7UDw{ERL!eOtj;xM%2LS6x(!hTu_v9kEKi$CALS$WuAZz^@u;XCql=GT1BVq z(NPuZ&~d>tmvJ& zMDNgj`Hf9__x)b3$)O+emjCJrdph8r>PJue^t4Jica>Lv$ra2Wns*=d1#@5izAu<- z6>NWt{@rqyFW5aD@J}yr1#_snbGMd%*9t!O*FGwyIQ!n9G-qmczYQAJ#=q;~i33%h zXbJ;QyriQ5GTCPnU*9u}6e|Q8sv>OGiSIU7%DF?`khA3X$|YyqwqurnKq)tub-hF z`A_1BQ~Tu={)gRpiGu0T5aKpRdl=nN9Ku6N_e6}sWPM3>rok{ygE&BfWZ?jOASx- zpg6J>XZrx4{L^{ju|SzDPjof)JTYq6jUKA~Rj3rZIH6NjyU&mZMZt)5pg6qXi5`>+ zPxPQTE*6)&F@F8b6YM?=MdL?*t%e=7`%IE2R;6}8Oc?$7Dm>Al1y3|Vs#uJ8EL4>` zEF4VmM2|&Vrj0l}Q5jsxP zDmrD4&d5Y`9B}YNk4}XrdUPBYi?h@LI-Mt|DOl(6no_0$N7a-`^290@4xR~Ec%Eni zL>RymC(7<%fhT&|D?HK5?$}@4q8qPo2Y^*$_HoA(xkMDt6Rn|6lqXuI;|$4@-hqiwT0X9W72e3kWey*s{xl7(|SRlwHH|Hw$>(gqfut1dlm${#Y9 z<W)%i{D(&MJQ*SYk5e7bY#9TFexZ{WwBw{ir39)Ca`E$CazZ^fVYF|P*VXyIis!vPtyzWG!ttL)sxpB$9AGP zV6Wh5mZgTLd8jtK-;?FfqXI`YACu&1RV+3i84J(T90paM<^>&f0<9YLm<-oq0#DOp zs@S)~6+WJ)c~EwEP{h+tfsmjwlDxR~ zf~Q%Q8lL7s+3!ISPdf?zykmhfS)S%<>Uo+IIo`L?L$#j=zEkbDM|GX5+I@yRD0?S@ zve$z$Z%F`^<$>C`cD4wU8tViN$b)bw*1Z9k(syvPK6`od&g+%TO z597MBh+MXtj-SMP9S<99=h;dT5o>1lH$^4&VmZ)YEruGSap6$A7S&ZkhIv%#t^RV8DJgndI zuzt_O6htDIw?Raiy`G27V@7tu{<4KA=(uUzN|7D}JEFf#3&h6*g$-d6(hZ+Wj?BaO zsxWW@Rn}Ge9R~4!&%;)F9@aaahpmWsSnqfqW~i{5i1EO(@tz|yKuA~6mg!T zf-*TC*6Wx=qQA<+mK>Rf>GSO4jWnf>hplwHBGEgMhxI$a;{Be7b?@++;=$Cqu2AWdE#Lw>MvV}=W0ACB0on3Wl}t>UoiOYb7UT-uf|u1kXSdW<6$d359^)C z!}>iB>-RjY+w-spgI>?W6j*%1{<4MepDGqd#b6snuM`Oq59^&Y59@VABhg>wVM~t8 z!&Hy>iailJbv$gP=V84Qd04;aVf~(mb$cEbq0;Ml*t}oFU$(H`U$#F6mNWW3D1o`>nr1jWr?wo)X;7A)Cx%q5~2 z59>XowvC45W3Q_PHXy6Q@iAgRx>maycjo5bj&$`~ld!iB(}xp=K#o5YZ|kZGFl#q&l!C~(QheHDFU!rev|)O!H;S9`f91uvZ7dD=-T-F?VRBq=RGseaG$)9$@>$Bq)W`FJ%X1k&_QZ3AKqlMYiOpxz4%&mRL zP5G~$m4x4K=vF%U2$hMOa<9EO{jz=QSyla^$e#DNv344r_eVRQ^1GqJ_?=Gq-Q-~O ze6Q&F-YLJE?9wT}8!RcY^w@lFmFIhX6Zu}z^Sz?yd(}8P?@{o4@48cdH{4*}yCS}K z%I|i{@0RHEe6R16-%SWq{B8oGPY#={l#M@(tNHY$9-VPP#(;->ruE}*PoQSA$E z%D>GEND+)LwX(N?2j^Z`PY&Jca}7DvD(gRPJSsWVpRL*X#07N(@t?>KpD>@_e-I_C z2JUeqsbBUqZ~{O4*5gOvhduV<^z+K6_#q4sH(J8)vtY7fqkf$~@YK5ODSjvqv}ua` zfe%Lhz*GG26hEwAxR*ch!N?zYYF&1`yXPkP10Rh1f%nw;16O%}VBbW4VA1;nPp!+= z?z8Z-s8jrKQv7hGr-2jr;niyo9~Q5|nFcF_O^R2FAO0FI#__|q+u>B$Gk9pVKfEDUJblj9bU`2Mk53;e|2PvBQ>;LiCH1l`(aP;?f ze!Jp<>{~mjJ;$HB^f|2uS67yEr5`ll3(b{&)X)`cD9^zssUW`aWdxREm3QR~6$g-N z;Ga@DKDo4EZmcFEkel*>)s>TQx?_CHis7pKA}?~`PDi?P;lA>}Kc5GDxTm%VZunL? zW^{FF!@}Bk+?1D9i(gbJo~!b0yr`7Tcgnv>@s&1<4Z?egs7&%u9^zih>*E!;z0y|2W|B3_Ytxh0FGs@cSKa?guh^@&$JY;~wap$+SW;uXnU7u`BwuZUN)EH&|p zcF(>N_j|J96{!ID9&w#~vipy#SZt=WBVgg<6|Lfxb@HOafc?i#pjD$DlVJ*}U_!j2 z9!mvwxWdQBE4sXWJKXQd+JDTKjta`;*2(+!TWyI~tfJ!usHZ)n#*3Yl_)SfcXgw#s zYOhCSl=3R5_;^KoMZBVAsfky#d$vHk-|JYOIvMebRN$zfOm3b09$!-*ujoW3UXhaJ zNZ-!`->DpWb@5nLP=-7xd&yY`io=V2B_@2${$so6WA684`Aw<7Q9*&>AAg~*xUnj= z1ENmqC|=Q_MZBU3P{m@zV=+Wk>acJy5wB=j5?`&vE80DNQ}_GNzyFx3Sr^`>i{pZ# z&c4S|60cZA$7P;?j^o7-J_73x44qbTf< z-+xT{ir;h+@rsrG$Ep7#^|jiNMSmXSWaAZU_KRHa_lv-otF)1u@=l{!OB))dh#GqS z#Z7tG@vj$t+wren$G`Y#vA-jKgmvq~5?TBUDi@vqa`-gYyy9P6JN^Y6zbOB5$e$ek zWo5y?s8__l?9qg-Fd$9c?5Z#RB{`$kXWd#a#J^0e@%u&WmH3y_hP5t)#2^w>n;m2) zi+@ppqnd?D#VHmgq{qT>!wFbK{L3(??icZbjyi!>je1OmYcYX;=`mIG97})kNFg=; z{1=y(ccw=ti+>#pl*#fh$`Gkg^*uU{Bu+qQRGPBiNh$s{UQ_mZRK&~b?1ckN{L5*| z4zDR54EUD==plu7chs?-jMI;kW6<-JF^Q=>dF^a0;UoesrIRB-( zTep^c!Fx`Se^tGD<(K__kqP|kck$(kk>LV!6wI7_@UOYNz*`nK59dvfuY;a#EgwAF zdCNGxuZG4oHk7{;m48MpjXR^E{JZwz^mjH=0B*DfN8|WWyd=HhNIY(eUO-ZygcTll zdJT``ue_^Yi|GBrJkHemB=I=YdwAUGR0l(ySgM*G!FM!(SnxQjzIdGEjI>BRju*z` zBvu`d(<|{fWvTU}IjA<<^Y}^QaW*IVC;8E;SU8S3!MsE~&M>IqaZb=tClEZ&VIl%s z!9+Zc$5H`DPwIJ`17(K?MH?AT!oFW>a8#Q+X&&b^Mb)qHxFc%Hs5E82lTtj+P^x%b z_j**s?<%NxKbpM~k5iUfKbiw&zX#=H@wj7vGHD)XHH~^$$>MRx0A;c~t|GMqqE6}xk2AEy<0MEGixH27_+1?q z4kqz9heeggIV`q$EdKd<9Ez_l?1Tt-UiNR)V71s#`p0y>_@d32npRdmW89r3$5 zbR2NvaSoj-k8|kk@#vf^9(N2)nJka1VBz4IfJMaPBtV3Lc-#cp9W3H;PWCE~bFv@u zve)uBecbanKR~OY9OFA-9w$q9l6ag4CE{_C^@u!fJSbwYbqX=&bS3hm!AO2V9%ttk zS5{{ydw$=z{UIOt{UIFIS6yM|rgncw!&$ZO&T1%!J}|K1Y|=&hL%1m~bo)d8^l}&f zSM{&4+IsB$A)v(Ybjr_Gb1sXq{ZoE6`Y&hIobt1|$zR_oKU-zQiLW~4XNyK(4l(u$ za>~!9?Nz7zZ2WZ&8&o3=Ipt?#YLK|cc@(RloRFVQ`$IT6&&S(wRkuH+;ls5|>B9}> zulvBjhL+kFEe+)_*6a_FKdk)r*avlidtK&`t=k{+!B1ApWpJd;!?r)KpFrGQ&G|Go_c`|DWYXu;xcODT>gBvZOH{Lo{z88~jjKNA)0mu5Z-}oP)(dvQ z%a1sI*3vKWfuVocvLveK(|D*hyWf*_J`EKB-y`}9wO!(Pb9~+pM z&ZnuO;{~XTyYuJMI4Kj$92!+k+3Qh}AF+ap`3w6UV4P25!Y8Wd(>O4wf&)eV!V^8u z`3UFJ91E1m`3sl%n)>r;qK0)YyhQ*0DpU@=Iz_62GUP##r?d_fhgZCR$b(WjpT>i- z(Sss?;Ym23=2)Oi%3s*Ou`0C#qE70BKcB{-m00Ekt70+Yv5+6J4hsiUynn=F;r)fZ z9)sR(9t-&kPxL(J6FQ%Us#zCy4$9-%6m@pztmAx|DmpIn1a#ytT(KuY$B9}+r|i*@ zAF&P{2VA_r?9r*5PvcOb3aXk zUO7bTWOuN{`^UWO-d`BW+Ja7e?pP)PW*TX&opMkwMv?Peb}~=hMI*p+82(;v!k)3t#r@scpKA z-nBK9Kf;Ugdqdbt0$?>1Q|HtC+XwzpPmfA5ul)HqiusGLA6Me{+G`11dqX)1+l+|g z^a^pD-cXM70@m2T(s$|H2mkiJ^KNT-)$3w+@XxN=V!HTy%Tat_Pc0BV#0TydLZ|&IVr>V|V_?cuMxm4~&5&!_oLfDhK}!yxN%oz-iP zPkm@Rg78$9;sC$yv{38EdQ{&v{XPs=eXSpVL3OCC3J&XqtshIQy7gndl7CWJYS)i- zuPWH@Nn1ZYUtk}R4^DO;MimPO&jc)@^%OpnVu75bMWZm%x3)*3=#o`6qcS z>~}bz>*4?{FYoO4q{RUq1C+_}L4xqkmo&ryRy4&6P{#*v8l_cPKQ<|~ek@6pRKmb7wLA3c z6sZczkOyV&L{J=FT0gc=RnM<+U=RoBKoK823Fk&13zSLm!Q#fM)DDO`sVnQpUspHK z`mqG4Vlm>e7@CNMgGuYh4vXsgv0=b+uKoV=@54|7s|#<_#c}7DO1Z~UYW=vP6E5=v zbo~19*Bv@e)G9h5|vVA1-qlfAlrY%;Sd>}0Q9KUPDC4?cK^dLT*^2Y5aoJK^-JNn+VF7)0Jrb7)J6>T0cJV{k=c=PvhN# z<{50a{k;vH4dp*~^sQ!pFP!c#apU2RtMSy4a`_rhRWGQeZWlC^|J6^b4DiAV1H7=I z{9#_${$4pvwZHctUXd&BM-2_rYKxd=`+HMS@t>}J_vwc6(8_A@7gvhExS{+2FCw?( zKJD-Q8pZPfUo4FC_WM@b{@yGPjd2<|jTkokbm6EG%lCiqkB(T5Ibu0>jQu52F!9Rs zYk1|wPHl}>UhFK=+QTiV&o9U;TaK^9ljfBwOT6;pXb4ozj?OEs`r?(=k!pA)FN{}8 ztU6w)SK^h*Qp+nHRF1oyytu@cqno=)`5DON#VZY^il*%K zsEpR467fm_CSIv5wY<`S;>cP2r18pQfHG-bX*G@F5`DvNw1!n&Vg;)GuC2#I6%7hn z_m<>|K4z@--N)f2Ug#W@b`t)n(D&aba7m^pp<(orFdlp9hZ3mI-Xa0beyPF zbjlu`k%{Oy;KVB(I@P#DhmPZJCy!SiLsKTpD=SzycqU*G@k$90VIW>Pp_e#V#4DZb zRbJ_27d^wY)b8)KhVZ=dVmCmmp$=I?oiML7JvjDOfywep4@wl5C|QrlE60NZC#g3b zV@_8hUI`;P0bY5s_V?B-I#>LI^^Uz{&HfVe?V0xz$6nm+FJVIpZ0)B1=Rcc&@Sd%n zt@YNjz}_1F;6SZ^aG>HJeCMwyK>oo|N8=cRj=sO-Ht7pI?zS2p_fw}P#^Zh(@whJl z`!C4jz96+ew$e9XRQygI8amrH5<8&|op#7dS9(N2-Ce7olrV)?(scTs0vJ;Q1K;>MUb&6C4Wypgf ze`6ge4lnUI`&5m8(7?byXul_o#~lNd$?~|0)DDO`sVn|LLreZa2~fpi#A6}9VI39@ zCh<6BsXeE~Fo0Is@Bae-;1?nu$HgRhoKlL%RnT$X%n9gt9`{pyLGg>XjYFsG(UIS< z4jl)ac$~7-`UiC{Drvtb>zo!UfE7FPLd;}&Tm=i~yPSYU#N%o)5RaQ6yMskM&dFZo zaZdI_UiMo5pg!(-+)rzH+!sLWgn67Y9cM_MERXY`L_AKi9+AgMvZ&i6`s5j{Q;0FA zD-n-_k(>aJtKBE;_LtQ72lp&&N!;8qy(MvLM;BU}?wHH}a~(b3XnA8`UrYS5;Xi3? zNEiPFmw&gUp`jtQ>CiV?E?ysmkFn?Ej}xRiyf4*q!J&OE-Ix6*k_LCY)3UgkKaz5J zsk!5SG?61HJW_uC>VuqwczHY2%+bZbZZKD6}oE6C%|F;pG1;aCvv+ShWy8mh2? zy38Bke_tCc|N39X8mM);qm%#V$lNk-J^!BA*K*y!TPY-cv60J1blLo3(6=U*x^&xZ zKfYuD32y%6Hw>p@>vz+!mxIDn+2XZZV4Bxbr@jFauDxx?B?CGkXL?KAaN{%J#%Fqh zzO@UZKcLL1I95)!u+g9>KYdj#4mW>X7~J-)#)eCP+ClKW_dhs%c=vx?$#VAL-T!`x z`%mlfsp7(TrZ~4LQ|xX`6&JOpirvkbVneFb_?c94U%v2Esrff%m!>r&4+hJ^3%L4t zP$){#U4$*t-ta-ICg$6`AjM~kS#4fOE1HVgWK2Z zA|1Y)xaQCT+p5=_Owa9R53u#1s%xSm?}-Z z;EScH|00##l}^5t51+_|1G7uBemRe1;oTj}_*40V;`U6lYsMVK;}5xr-H(HALoT`+w>gJsK~V)?Lqinw&j7tLGi|pb}oi_u_l*% zAqa2nm`-VXmXPW8bwWnTJB!pM7<~VHk{!r~hjPXF9n;gvUAe+VkCKw7FQIe!DUG`Qf_N(Uu;9{t#tC`SXt@kl%~E-K@I8TP&W2lD*SvZyr$8vPD_Pz8tGp_ zwST3)P7iCS)29WdJH@W)wEHyriFB$pQ|zSc#M7l&=*W{&lOaBWjx^I(E(r$Tm;%nt zYOyZ5*NiaTF+El6YD<-7T$<)hKw0gnT5ep98^&#Jjd z(xF`4sn~i-nR-PjeOW^)Hk>xiDLj>l?F~_t(zNOM!aJF;u_F@>r==Ciy}_~!>9}s^ zH&-~f_pbHiEC+?xGkml$U*PYmqm8-3Wq-^Y68sK7=-3VVq0mmcd5=B%T$Z1FxH(rq zU6rX#SM9oL*9U@ha+7}1&_~kAr*%1#&XjSN-E^{CD8)oO=khSe`?!A?N?!#3)aVE4r#!+3Z8CtrFl6n*ShXvR=#8#9?gaWO3)cl*S4(k zNHT7ws~+4u&cEIMLozk`kSpeysuV%&QSD-AdEhZpU|w$M=nj&Ps+jg5_P(sZ^hlJJ z2ObeFSPWpm9O_&HI)mifMbtT$v_wHcUtdA$9AW}kE=D($u+UJQsF#Cg;%oSyJ(+AnepjLQ%_3{$KJZUG~=_GEsCO2szvU{><+RO}HhX7Ds#n)d5_dTKg6fEvyyP5m%0Iw>5> zwXh=XqRCpj)yx*!A&gw`dpNu_`4mYLweq*LM^NXd{Po`pT zW@7tNu{W?e42~bu=o zqg_^m95wAqGcq3cK?9a~`*H0&zM5esd zl%O%KiegFM>9_Hi&pnnaoU?wt%fuH|ye)uqK}xFXlf9%$rl zO4A{L`5j2ukI9}dtj~r&7f+y+pHbz#WZs((hjPi6gXG@gj1J#3uP#0GIhEylbykGx zz4Ozh8$Q=yrUuhMA;7(Z{JT{F%6g99P5j$>W$7VfYbHjfH0@)?#A4-K_&7X=l;xmw z?}b);;i6Aat-zV;SM^GnI`hd_vdLY1Vp`g)k0%}^^DUA}mU%nFOm|@*mE4Iu8$^Jb zP!g`64Bv?D@;oCQJDf^BD|3d*p+}b#r$Ir?Mo8~crCHO}keO1)$J5~r(*BNEI<{90 zsrz^)+?E^^kh3z$wLx*QvnIT0&4imX$&Kmci?Lln-{@E{WwB{C1|^l;D@}-}l3N2z zP8+#f!#Gc9+xd*p$$bHjg5-Ol`s~Q%rE5P$+rAnMjy6W6gz=!%`T{65sD!SxQpSce zjPdD^I_*m(>0$Qlic)J!Cix_fQ{kiO*dR*c--PH=xHTQlOuk9puqjn){uMn_)p(#< z0Y*CPMEK97!ybJhjlpiRnkHY3JsWn0i)59$$62MC4PoC{GLHY;zGqA|E?oBK-$h%C zJushctW?mPDqxRYY+7~z+f#Vti=`PKMTcd#0;XlMTfyM#7^-cuT^zs;$v9^= zWii$Gs2E0^esKZ!X$F4u4O4YSu#65z4>0337bVhA^=z(mZYy&Lp?P z5HuualTRntGky4o((&nb&v5mQ-ZKkB)~S5SHR|O-CbeR-bfXIirzQ8L zOH-#N?BKT;9%w&jiV5 zWPy8_lcfFZ#=SgH9dA{)?&O*|UXC;~1=W9k#|_M0lIi5m=z2l7*|`Lxwsq`f&EKHM?Nv&&0Ue>IbQ zB~x5v)RB1;)k(fd(uJ|rs_r9_zmq=y0y@-7j@hNw-(aYb2>esEpUg&+O7W!dp^ko% z1>uW9@(B-WE;&MF7et_v3UQROY$+Fa$omkK7Jr-{pzFSoYW65irr34E?9z-2gK)9U z2-C^kmzNrU74zRr9b$vjkea2!Cy^n|c-5wA%`P>c5ft8$6>oXqO{%^36ZjbuD9!pvD*03{yw}++ zY{>#TT$(vUFZr>y({tfdLVJMQbkQ-X%S+RKmC47MM!!pqpJp2MAqM1B@{x3GBpdD_ zSue>EB3HcE_1thusS(@{BR1AE6<*E=c6!fuG)uVX5AEl&>-5v|01S74I&&rJ43)mm z`a-VosT2voYfTOzhbcc_7-VZKAZYJZ_XyS1)$i=E%ZM~J{FX6 zzuyowX}B?nhCeLU;11j&2kB|A<)++cz^7wxq{O94v(5mJbn?ku?A=ssFy+R!TR+#3 ziM^Toy;oNzpN;JcFJ=6jl8)_S3Yd-^NF_&5hh}u3C;V1pF7{Ho_>d`0m|#RY51?=C zXiHPIFEhGEsa6%}U4COSx$1xn9GP zPlYi?h0kVUtLaJU*r>*l!aK??#TT0{oWA`wO-$cK#ThqV=0+W1fY+$mP_FQ~4fdYq z4nmC@k7a>7l-*b()$it!d@x%w$#Mq8Z+YMyW|EMYNVm}KzoZ0Se1K+*fJ3v?4=&~O z>X1_s%|SuzUNbx-eo>w3wPK6)E3G$m6j1PL6kG+!IEv;+gd2CH8ys43*G#`=%w;R(; z(`7ISGVeLGb%@{O&UE-}nv@!n=mCq;;d;82l>F8!(Kn-lv7PA{kM1<1Zv&1Qz9b5~ zPbp_+!-LEe!+5Fn5-DZuQE|1xxmW+G4C3eJ>Icdkgj;By-O?YmBrfWwr5-Yi{Js+; z-}e&-y~TsF)qhbl2ogM<7BfvVvWJf_(?S~$-zt4aIxHhX-kJ+#AerUmaQyj+aPlQg z?TaLYE9RL-m=WB_H>LL*bBt15>O{gMlY|fA8Nz!+tgU13^1H0nH{{G*K_Z||g-?;} zhE(h+`5?O7tYjC8Wu93*YiBMzOR5t%?i;VnG#1-r!CU~z7sYkqTnxU>mn$8VMFi5e zTukQIbatkO z@kIY%TM!Njy#<$-S{dMmB-#Q9Y_4?eU+jRp+(Bs#slIY7HCR54=P7*tL8%%1AH_{^ zdUkO1j9~EPM*LWFN;4YF*}_CG8*a)cx3-+0rr%*SDe%%<0jEXbSF(jani{^H4H>rI zKJWsqyn%t7AsoGXANb@udp@5W%@wZ4`Fa2O!Ye3zJ{vyo2O!eyu?Ep>njsV&*_JLc zRX}G`#XoG!tB-X?zG23uO!!7nde{m|6+eDOX~q;;vP|+oCiZqZ#Gl#uMM!%(_F_7@ zK8>2N{(s4})zWNh^^&SpAS5po{6Q>{pebYF`jB|P$5?MT^iBq=90Vn>Zw z?bTMSZ9!{MCvAt9vcpLkO@JcFD$O{ry}lj4)sB?yN0qXpA|+-5eN2b5VF*^2 z+0%iPZAgixerq~X&X}B(Gis!qUX`+5S0$a3YFMxW z)77#_IsK?o&ZtN^0|BSk3OHSs46#$Z>6w9qZ9(CylClX^EzD~+RYh2|)oJb#I%IQ= zl=Sf9^vGu4md#G$rW%RIb;)^66WS6>wxCH;(ihb+>4m;?(kYv*chV=DttFEO5w)pS zRC1?qCHA1HUz4_~J=HI#POdGd)=1fQTq&n|DW^Iq+m0$_+XN}wkh1NlZ8^2lmbf%$ zw@E-Ig|Th;e%qq9+cn%8-q6Qt}! z%A;9WwQKmzX=Y)kAtj!E`etogk~_tlo@ultl70puXVR3jj?|QqiN&Teddy;Rx{GSR zpY7Y#&Jj0V9E&Yq{vL0BgT8dfg7z#gWQ%Ih7!w-K9384NzK5LnV-t-p3&Z1$Z|rUQ zFr9V`@yCwZ$cHM8dqIE0IW)!mQHR@hq%?kN8o_5 z?dg~jhl{3$K@<66gRy}JieGQKak$UTn*vX-&D(LfoCKC2yhJpl~o-Y8*=!lx1Psw_*km=wL^D2f6IeGG1KV|XR2*4RcyR} zvTqM8I*||8Db^r!$5SnL-HY@=F%_442_rk4xn##xr5TU&wBgFqjay*TjUC3Ta>c0~ zSCwYHsyCM$zT_P~XV0_XRX7W6$M^hYs(IZZW+RY1bb1i|e-!inH2s2E-f-mD89P5F zzvG7}sY_GA*oNTJEw}vlR5(4`w>Fl-<(iM}&0UHk_Lgvh4vxdOZ%=ow_@(yLJKt$% z$`#8LKa(&17fpWyEirg_u5@H{q1Zxg| zr89r&o|{`#W7Rw;UfsU?|6QVKDioFPX2K6Lcf9lM&$BdV?RCjJG#>A-XeUcs3Mhlp zwV!K9{iKNsXJdQ$+nCF_3SuuF{>t>sr9Zo6Gjk_Gg1&vZ79MBX+(Q*$?DlaSrN+O` zm0Gt$yr)#^9~9zr0|+WnIYF4n#U9CCy84!#6P)Ccymjpb%uHvp?P{83s!d@Ey{;)& z_zTtTo!hM))5S}J;@_zqX%1_Xc6uCB2NqAW;rd)l`X=b-PJ#)T*P+JW{&K$XXtr=z zKHFJn_f@41LnIh{ZOWX|w7YhHSF~JuWSzrzZB4qm;uVi#>#A|b@=d?JA+H# zzGa)%>Sw6|XEDjxLN%oEuRD82e(=4#t#4h7R{G5d-LVR~2M&LEdg{_QZg~cDXM*l5 zp$n!ciO^-xant6Y)cE(HdqC)#JuqA`HP2LGWnrZ*;-bDk2SITjM)jFuA{#!LFaAzb zxFsC!d-;P+?+=chM#znvKTi^2aoQcPx7_t<`6UWlQv59md5zPh-#wf!%~+yE(CMiI zTXUr^H|V5XY~%gcSbmty0Ec-aO{jcCLt)zdNEu0g!8ZW4W33nZ^Vkx1?8X~N%g(X zqt#7Z%U+BGtQ%FAvBRqyvxPZhdWmb@e9*EQ;hE`6AHO-6UCNzEkWm`#Mz@ z>{dgnmn}R_C<|4)P*odD6&qExzJYdMx1GumwJV6I4@{?kS-GN6yV!`c*#>y|I8O!zfbL+WrUNfWm7)feqbb6rs3r3LhBM9y_buXvxVkfhQw#7 zzT7s9E@RcvC2V{~?|8nNMGJJ^4Krc-8AM*q2)^Z(zskze`p)ax_As7Xn(&P~o^QG9 zAFUbJs8w-3oRKdzo)+|#o5X*D!Yov}gZsgzEG>~QRVhj&Tcpw$-A3S_omI|{ZDa%~g zz*&{Vnqm>ZlRA72L}zC}vtbVBW=iP}Jbk!<333_1A(ks$bvS$AIb>y3>*dqNSS9of1xLMp{vc_m4)PHxriY~iX_T2*eyncm%x639SP0L%X*Ax3FV>E2(qG9t6i zax{*}d~!9zKwDmChvKL#HOB}%?At&z=@{`AQ$LGGbQ$aWF;otZZaVykKEqhbax|z- zo1#izRl56Q$}Nv33sbByKW}lQ=bZIBID-q99sGuV&Ku)L>Pf9E&}tz!l99#jH9_pX zIZ?DGu>$hkyLz%Xp@m+#Z3n|oF#5DvJy}1G#->FKE~Z5=0S&SNu6NU-qSqqa&&G`qwg>Y04_X|}gj;f@4pYfo z?7hfx4IlpPPAu!q2~+3dRqgrMYrD70PGvOUzi6eS|JdB1cojZm=+Z62E8TP((_h$r`hLqXiwHG#CS-APrjaL_@ewsp1zrD2H2nnAZKT6FGTQ5{1 z_;3@S+RhkfOT8*4WXP=Axs>eO?Q3Ns#+kaB;i+!^bNikqh6CA?Z(&c?$)2oF4Ze?5 zMoO_Hqe4tEhKoCTNa~Erzm-wZ`s)C1ORc@N#$~ZB%GTPK=>gVaNaYm2jEQkksxbAI zyOy5LLvL5GHnT{>n&%;<8Rjw_x>XlhnX>Zp#mKtM6?Mbf*wPY}bJm7aREwf1~Gat{$2yK^5nQP1R>oGsy&%%70Wq%gn)iFELczc$~ zMkBOa-MxqQ8lzR-%oeV0B;JNw{(|hS1luwQFb`UoFUTEVSj~&|L>@Z})|)Rh_LD>H zIjpsB3=R`v?w&jFf)!C%rwJ%(s?Z#=YMrtdf$;O^L!AG2TZf@ENoWmIP{n42l!09& zy<4%#!^>KwTf$0xC|~$WvjmvRIL&HqD6+Ff#$$RT%K;1{g>?aoT~;I}ZBAkSUy_Ff zn_LX%Wcm(3SB$>QD5UwJj^&gY&`wgiY~c^!IS<>KT3F_*uY0DlPEmfYmN)*GM!AtF zgV=~x2K6vs_My_<(%IzQHwgC<9`PAx>a%VkRMuW5o0ti}aVAgM`YE285t{a}H)!`7 za1wEWzS+$h+1VswY`ODH`_%|!1{byNG)qjYuyFdJAh}x0-8K?DUjqSwUCibgl|TsG ziKxM~KtGe+VGIg4l+x#6|Dl=B$Hpq-w@MGMz}TG`FmVsx(B>F48|Bz7w^R}W`A9Y- z#+;FcG32j%XdoJAu1mL$)%3gdh~)gkqqB?L#B|-Lb#Av_%k%A;pZ4SnPq5_q`y?lg z#XIqpC#dZcZ1RxSFW}n7hF)r2WwFGu5#{LC5?7N2o1~ZnL|vq53V}mqi96Q^6=suf z`@qj!_;Ul8=J%5Wf-KbTexX~+DRYx!L{YoDf!IQ|d;B6{o`Fvzw`GgsFNgw3zDodM zOvHVCB_K5Uge{5pt?kUYT@#(r>SU~}b;(pXQ#MGtK)0K9IuWz#e_gGy4aqkwaCMek zK16VQBp)lMStUzuCtiYVL~EQ)_(qE02}NrVK`hTuIl}@azAvuu7^T7m8e~T)z2$p* z-_s!LjVL--<|(lvnsJ*Qr30EBr8;IuQBkv_DE&&3M&oPdl6U?=8npXt&C6xP@fYL> z%Qa6*KK3*GWVi|#cW-&ghS}GYnLv!b9d$?d%{rEys%$yiiC?TnXUw z#imlLd2@)OccGG<_J&YNb)Mhb^x?i;5X7gD5YNfo9c}hjQE_;LRw_i+{{oZZyM@tkULWjK9 z*Y_d&ehzOB9Us@$!zNF@a22+OpveImbIpMfh?kAIYpyCZ{u#|O9N?ZSH2)dI9x;Zq z1*S1fsZ@iRJa{A@ZXM@8%@XBST5Qo;S$SPiaKR>vmk-}!vr=S*ZKQuXU%0&a0Jdg3 z!)dTASNMv?*fqEU{zCR=u5g?V-D|R1G~SNuo%c`6BgDwZ_XqG-`~@F^8QcuxDEymN zO&J0_DtSxFfPTLlpbLM{<_jU~P?pKrFwzojZQ{xiOj=C|!uyQ+=2?lC=#95itEno+ z25rT-xAMg+;}kQRD_q?n3h+Z(jM}VL*uIOs2nt_m*D&r_4@FEU8J%f-whqf z%*Qmjb|bqeY+0lEfO5!i10oKZ5{dx$RN{(GgTHVktLz7}g+Fb}7k&?Zcc zn0goXoVRc3@ZrKuGootBhAzNie6LsXTmOMCXjmmiB!FS?dmvkyw%hGX;?4Acsg0Yq z@Lk3ZY_QFv3D?n#E*0_#HxbDu%PNaiV*$g=$|iF}TP-$|N<@%y2dtIq`yvsHEp#u9 zxy+pisK;f{g8KvY@8>c59F=#BOJ$tPXzxaSCc(-;m19VMXGepSSOX6uDfLy17dvn~ zewDfpiUcmFuq@G9o?a|b+1kpYpsk9kY$kSJI@|4sM#_8os?uUlHC)hVj?Gatz4Xom zWym5z^|NXW)jglI8jR|a;oeUSgVOz)ly!;a3~^zU#YH8p{bK3n(;JBBP@r6r9b-W4 z;;uB>GB|EfMmboQbD`k1UVbCe5)IB;d?#C(SA>1FSkErqXXAM~d@onPbr9QUA;^Vy zSUoFE!)t)CNGC^QsFXIJ;`IzaLfSNYQTT|UB|3{eZ`O$woT&C78j=x9+x*zhw)`uQ zl+w8&KkRY4iywCX1ci@?*aRv>qo_>AbSuWWNHqbOo=(2N20e=SEix&kpvxBCwP+N) zjTdEAv=|h6)lH+hSwjw2OW{-J=^d^v3XwjkDV2}%LOJ-}wJWx@4DzCj2dsX+d%ilo zwNEH58Op{;eE>~5lrP{hTPQo{GF*u(k&{~qNIvgkjea_BD6 zccdHnaA)N^iURt83{h&Q!-~i!YW+!GuHkZR)r+0O>V)v~fjk?g#l9>2G>e^~N3i&k zqc<{Y1mxDNYBj%X7Gh>aRJ`8KC92YsZo<@T%A>)2orQ=oFACo!2VSeiO@f0h$=Ujk6@KgKNg#i9MTvZIUV#`?)wue04fPwR~^jfa9x1Jpjn42N9b+GAmsq(J-*wem(1; zW&!tv4jYe=b4bQa!xgVYcXod`TF-z2;Sj1gi}EohI^JL8dF!iW6>se%A4?^<;uqTp zLJnAvx~kOr_dzLzhv?}FZ~ZcUq8a#zR`YK+bmrE^Mg|zj$~CyWe;+>)QQNo(i+_YE zIg4G{=*-*bkOtZJgTl|puWE#?@)OyT2fX$3RK)y5AqyCk+|2)GG`pSM((5-VgRtV- zWs$J;Y)gY1o|kV^$Zu8)sr3?F?z}`IqT^VrmuuYm&!KTcbR2-b87^J_q^kodT$a@(U-HuYmAW2<=WWj1GxT!sw?PP>P{=( zZ4Lt2ss$v}5VXjC70Qgg>*Yp7Xw)9EJ;Q#PXY(rxdo#cJ@bMNG2PxZuO6v1@yfs;T zL4`B3g@4lw`-F+o-PT3^imQn(P;U*0@-8%g*V9mN)#Az{P)~LgS8asIA2W8xKcQg6 z0ea4rntn zbz#;nFF51!6>V02IH){}L;#nQ+{$y&^Qsz|hUi!N#0nKw_yZz>X5k^bM(i27;s$k| zx2wShEX{5BwcPAl?KQ+R3ki4%_m~omS|Zu@bpk;3<4YO@L_`ZIHfFN=1#<$;PKi+_ z1M*H&W)0V>&0c;}7Nx&V6rEH}G;y}DiQT-!J*WaB`i{Cx>^Y%MiH~yo6eUep2@R$a zYG*%PDtxI;<+SrW+@y?373WUeb`a0q3?5p8_;#bjVX235b?WPMce2Q=p%7C8nrtT5 zK#h&mI+pp|0{H5EHU&=|cs`E^g*7TyuvW`u)_@kwZl|(cp+P0r;+(c@W~>J_Ga z*UI#x43+FUgseF}Rcc%-&sM2M^Me8P7&LX4EreHT|8B_y9=;}^q2FIkzW zL2j9S-rcdBTT0^C3MadYQ){F_&c4F%B4ttos9{OVP6t0juGZK{t=z-|D$iFs6|PAo z**dMysw z71c@Eh&?||f{!Vwi@p~=>TG_!Yi)|n8@MW>$=`e$Ug`m|Z4?mAE0_w|vaaf(-2+{! zYWO6(5#wSeOH|;pbaI2}I!>=9m>MyNLtwg`SL`9so{dFlc`7!<+8pkMPPWI#cE;Yl zqSQQvNkuw5o4C2Np!n(VO4trQM%K4hUMaTDc8(j^fT_Jq_jUAA9?NE+{a6iCRbLwB zjWXgyv>Y>&?^_=79yxw|P!HTGNbQdn0Mad*vXAKg~%-LAu zx(;tXfbB1$KD)B4o&qEa_%Agd*Y3m{m=Pq2`yAk#U8jk8^LTt+|%7SA^U0P;Fw}-<6S$u~(M= zekwL5Vd!7l#G{Y%vMU`UrgGG9<;W!2>`t@;XHZ((STtpjjpi2Q7f_NE?Te+H_5k8( zmmL`935nSRtw&u%%Gy|_enGwre|=M%17EWOR4ABBy%oZWuUbh;&1c&VHG;IrAk{!>j5?Wl_F1+`AL(tJ|;)MI;DI}gG( zy+-+_^lD+~&KREk5Sh{_-sQvjLE(J(j0mpdjWQ`Qq$0W;8fCY~t~tpLn== z3~oo}9n(hST@jCr#Gm6c;V>hd2H3PSczd6(1kDGT8epR@& zh5zAfu@j{2VYVmkek~?ou+8RIpGMd|i zduqy@Hp;gC-#X~W4PQDsgoB7`8<$wSwNQ#mSXL^$b}fC0sPDe9mRs&tuj<0v&i~bk zW>PN=UJ5bOiiN5zCQ9G$t&vQI=vMAYxyT-SNlMKdC`A1-S2*vt(r$$jaL=;%6k4OmYon+{-<+ zU&c=~NT>(Q@0d^hWG!TJlbh2Qx}<{XPM+opL#4*gBSrE(RhtvR+E7aimE^>QTRVC< zB_g3J>+?(_7>0zrrQ(FzR+2oc~@=z{(LsIVN4F{3PmOVuI-n*(~N|PK&g(FmR zg4lmVxHj*G%B$RKHwaQ>MRNeJWq(uaTwZko}StM{T0_!#M zBR8KKASd+iLHo>jI!rpNJ8p_Z06p!Q;7Crx{99Cu^H5VlWKj=2XA~#~2~R zbW&Yea;Jzf*=P2Oedv*cG`!!d)!Ye9p2fHGTpYKh?C8CStT7{r-9IlRTURpp&*B>o0#n=Haqe_{kPx zS(XsZ#UjVgYE1%EAg%|j;W{2Mnz&OZ^lF4xiV`ne^kZ^Em5n2pv*GKEIRJ@fa-_?- z%k%}sIml;CHhn)^U}N~hh9!@6OyeN`wv+5peW9!>0?;C+i<#tD8nV{oRfK*dwb$B| z)lhrSJ%P+5-^dr<&=@eRPw4Qeq@3`WhQH=Pm)@vkt)6t!9?ZpDUt$oUu@34y3Ok`u z2_<)4p)jmG@hYEu7Pq`!SoIy}&L)}H`I9nKDcl<*7$s+9?TFcsm%QC{97W`Mk#A*= zb1;r({K^-!@fX)3F5|&J2(v=15{3WF33_P`&*emJe7LIh#uop*= z@Pg8`mUQeT4h4fbC*KwGo2z3*5v-G9kyqW8vl(@`krs7i5DAndiiPq}GpT!cmTKR` zRVI8h74Fi8BBWbR(oAxv4oo6pFL!B9i&O8?B7vJ&r8#s`y+6aoM@}-3*@&&-jF*oG zrCDd8btncJ$D+~Am!W3iq3}#ivrtJp>xY<|A;N5e0xSF5>DFk$7(O*xPD8VW*Gxx6 zyU6Rpm|%z2f3%GGoJ_4*9%gSnDWXXV7yXK*bn`{27u{RhmA=qfG?@eSEB5}R-6}>8 z1<8~1WS(=6B4triky46);LG`uB3$Uf(ov)TIBR_a=0nE=$QWpRRpqfnv=?pDOCFB5 zvEu`HZii>c80dLAEK_m8NdJtM78Mb&z!+FLpR68MR{BdapuTSMr1_nN+=#jQXdOFU zg@sP70dZ0nGrHs>+2rBNOShhmm~ZDwp-ND5NgREK0|XSXO02UfZ7+`_#f+>f?`4`b zSjDz;8bBttJFBJ2y}8(EEg@&j`zsHyoK{CE|#upWMCE* zdy1vA%2K6fM9zMaQZ6^NInq>!(7IItMxsW>@TKlvobZ(zzQxFHW^O z(&$LZ%~>twt|&Gq6y`eSOP!s?)k51=r_tzbKg9qdel7VaH%SxaX_(2M(Ur<6003Sv zmn2(B5~(wqtPViWUub>_)cOhvLY341le@Q%kE^=wy*2jO2oM=L$e;v~D2Zq^SP+RQ zshudfI@Syx;Ssp80}fE?`wXRS>?S7I#4X$)M;7?xaKOE!iTglXo+fRRKniUrb$}+4 z{3aV>WJAC}2Swp6C8?AAdg9oOAX*`>eJ0+I#=@T5In; zgTV+cG}Bs%4pWF6pzLMKELa-b4O4*#W)x^^HLs7St<083P)9Xf=AG7(u8wP-QD0gG zcBG<)fi?%Gfd|z!`ak5GXeje>DYy}Lx+rtqjRZsY`|ywTq*3OP)(#UcAs!_ z6`-3s2D8GIt|_mzVkuBqnNb%7s)~frx5rtcrPxNc1hqAaTAF^9MG?}pRGbtUU<1Vt zb}5i`rPSm)#spnz$fc$QsW#@=^AK|E<}bX#`YH4=#hpOc0@Wxwy^vp7NEey=U=~FB zV(#V0(*TuJ=rIei8te><)S09fuU`w}(SjgwBEIF<%f+J+XZ(_6O4y;+%<(}pWAqaz z0h*rGDy188p1p+f&BuM$O8mE-Uz?>YU4Db{>vd(8YTH}FPvzMAD?7o~uCLkvQrk@J zO=n&ns=d-*MVk?kR;i_PX>VC&Cwj)JMt8fMdnP=|Z`<+pts{bu%_BBU*%+pioNBa6~~K zf>LB}O9i24de=4uO&Q3frQ;^DPSb*=pa1#4qCUZ=Hd@9bhV8*84~ z@sTxb481I`o8wijaeDgejV);#tJ`)EbOCUuSyR;yc4Zi)3GQ%Z2HvKf{{#YsuNYu4 zUsg)C4j+li-VQqP7fi_w7nH+LlJsiU(lQ&hkshnDtJcoi6uY?>0(sbG9y;WB=Si~> z&H(#`_Y6SWPDq)1AGX^sACdeZ z_c2IiLv}2Y>b=@=u9QHR$&syFvFSdF+ z1v_3$Vfy{l_ena6wf;VfJ(U(HeUW=Gm@`VD0Y zKTvb{Vzt(gt=;`POjJ*H`8B^zn?3DV$4;y|i+h831!58pD|R^5vycB9Sn~HuWv3s- z{KY3z*e{*Koqj93#dXlF|3NDA4SL+GMo^QDeCe%R5RsIi!;RjjMCB#Jn`GFO3bxTz zy5q7obvEyxLuwzXuaAEHevo}vL^1GvCa182Z|rh(`YK>j7i$(~(Zj`h1AC}C;PJcb z_R;;dCN0{ZAXuTJK6YiN`>588d!JQ*-9;#@U7T~bsiFrAMCpHTk~`oxb@x9PjSpY| zFw3qoj7V)rm$`znVq4YqT6293#!w&*2V~szkH8qym#a$rYkz)}`WN)k!~y`NqS&{X z-1Qh$>FhW1faE@Yke=!LmHqbMenh|A|Ab#Zd6cVe^TYynp*q0^nLz~*9CvRRzhm9g zbN%SOLfp6W5*pgak7mW9g8uz_1!bvZsn*Kjzve2?6JF`&jtGJHkQqI0pe-_b`042= zibjs)jH;W}DiZEi+Qp7TX3Wr%R=Odf0ea}ix-uu)9$L#;*=SPRN6GR31RAj+Z#%_^ zV+Im4t1uNm?=Z1ZBk5V2mS5<2AI4-+BOVNKVdW3yV`ELkIKHseW^xW*+6&X?WukX8A^IJcGAq4ce!p*~ z#%RE18hq9~vVoU5 z^6i;SEdG#e+-qk%1{ax|2^_SO0d1=BG<(Bq%t>K`sZojH`4$N#8{~9f<3+3~#{H+7 zqhN3y2i?ia8mhIUIRqKiQ?W zE}vwoGq9d;54qbIJtL4Svmt9sgBV-8o!!h}*hw=_rNd>VNzO=yBQnJ_kf|a^Lmd40 z#&qOv*eR{y6Pm)ZXL|)NGnp#G(L6xg#9A$yQ0`rElQlx&^ z+D*2@|IZ}YvwJh*-y`I?|dD{*>-c_|~@OP_-%=Vtw7&d|)i-p&q zH-q5mnz-K27;#(*bCH6c=#b9$n>O(p{nM6CzYfg0gYo2^n28577j?O7Z%8a0r14Acs@;^wA#~HP&(@w zI?`tM8}?@ap4&b+2*Yz9V`-;fx0X$uy$cb_X1Zoog5!PcJiqO`TH>kkLTb|KeW#Y) z48q|*r>+2Q0QM{hU5R`QHoM;L>(=n2Qqb}mv848m20XRVs>-e zvk$uNF%Bd$+{2SjzpY!DO*ij9V7oEy*OQjwz6lnU-p9TFougc-m1{s*V^Xj!@k^l4 z@PRQV8i>MW6TI+%$r?|F<)VfVN>$dIxpQz8{VzqglLrBidm1v zZob%#F^lw2G}lPk8?X9)Vfd3L(1AD7VvL^)+OHwiu?DkwKG z;~pasM#ErP!8{4fa7vOmEnIG(CY+4F*OhtC9O9zMi>t7exA@OiXFT1<)rh$w5Z@eT z#n^Sw7(Er|*6IG946k=Z-s^H7=ZYhi?lD2XTENL*$D<>r?I008!R?zAMiDIU)Q1$Z zqj~R(<`WMGpHM+vajaD)KpvadZj~YBCVoB`(8%*TJ54C6eJ0oDh$RZzWJ%#l5j^jv z*;fTui8vWHCbrP*%3zw3U13@9NeyfIo(U_)tgEpShY?F_DQ1hg%7%6@YdCAylu?wD zRVVoLu@^O479dgC=CFV3)RmwF3`?Rrh`Bp;Sjn&Zc4QM}i?; zDUQ2G*0{zfTXBblC|ZBAUD%|O{JKi^j8md1%Dz9xuluCj)d3Vtu)DY#Ir#}+1vQwm zIS3(mD>6h&E_huYH`=&;J)7pb0dJ&Xkv2eG_6lzEBpz?$9k`3#i}Nr z>U`-2G)4$u?B-X25ZzR;A|6af&Iht4-MT+g!B`L6__fvm>^Ui>ah|b@-R2bcpTirk zf;Sv(6tOR|Vz-t;s{N{_26@eIJuQ`CwQm4tGn>0KT}2IE5_RnRd;d_L4v!+*?OS9yup~KEo{}00(Oj85AA>2@eH^O+6aqvYjKh+M_ zOiIm`W(??k5>+Om(OIJb`_d%*hCaWQ23RF=k!gd<@tzd5I|J6}d+Cp;NsU&~3nF{F* zjr_W|*ujEL$7gdNO+ZK=A|2u$RW|t8Wq$ELNFTv6(#JH}%mAoRiaZ3fs*di8;XKHI zjFcbk6Ns>*CNF9J%Du=YzabH&yqjAMBO+ng=Z~H5CEWeO8O9PC0F9x*C}`%g>Awkp zMqmS7XJ)aQ%wohFh@zK-Ed)Tr*h1}Ob`ZVQ;%Fwb;htmp$*kODf}<$|G}5!SEdQFr zenx(@N|V_Iy%p|$5rn0(x5AnAQ0!)52b%iK9GPH^Ay!+&pEF=%CzSHu-&7a_l?WaF zia{H+TlIvt%7r^5Q-hdL_Ds%{;0nyCk_= zk2K5FR_-qDdArSw6Wez&0l5Bq)Km!nj{9=L>?xx6K{5KS?A)SKSwb47_ zzN-xqU}#Pgq!0;WE;Y};KLBjcMKH%r+m&Ii*;DeR*M3(3f1gm@-6DuKJS2^n%%5F^owsSgy==dQq| z^CFn$Cm%C2??n7n<3UZZ!yha2V|Tq4OqRh6l)$)3gpAG8rpB@?5z&rh#Tk`Ji40j^ zN>grU<}-3_YR3!?$?8Xbl!Kuh8!SU;{K>f7f2E>$hEX{0k#wx5n8lRA?zAn86QhwUQe zZ)3}epOFTn`xj+lM|k%Q=-4kfXf4+SE8}e6!yR$Mx0w@b@XMIxi2%h#jL-{kmu9|n z74K_Bsl4AYoSFhU?o(awz(CSni;TO=8yLP3opEn3TK#y4r}IP#tW zZq~*@Jcnvdt%34t`DJW8RiVqOgf=NX@yqdtxmch^7vI8MfU~i5;00EKW+(nAyV+tp zp_SYYnF{trpLrFRDj8CyE{Ss{s)MSK5--KDkB!L$)th4&6p-vbON_BfT&WP^grEMB z7Ba<;m>^_4N=d%LVGN`ZPk1UxLZ-{in?!ybv~kC~NMrYF_$AzQ2X-)m;{~H4L9*0# z9^Ot)SF+T&toYqYVTKmBnq|g#TR&oXz@DPe~fp+*Z?8m&l*^c z^*(%1@P|$e%{F5V^=QT#gkrIe9cyxE53Hl;W8(T1eca7uid{BJ`$voLkNl&+pJ#LS z7J8&Uy`I?~;S`^%YB9iQv>MbiL74#Pj7C9u)MM}vMl^+d6{DYS%AjD`>Hq(Oe}o!T zX~WBkO)jJGP~{|8&)e&by@j2lR-3S_gm;=jN7nSRP@O+k6n9|B$XUiv&%Roi%PIjp z?WAGEDzv*S;!%i)>bVvk`aUts7+vPd=rU7Lf&vX%DY8^$V|QVWL3ewjiL#|7Hl_mO z3!ARuueF#9P0;5|)Gazk{L@$2~4$^5cdkCu$A zH#U9A10=P`{61j9V07G+LHdYgC3$1Q?NUCK87?*uK5yh+W(SeSkI2!`ud*~!stnBz z^l6zP^xa{F1IfNqV3&zrADCrwrvJo@s+<0|n`JgG=iqFa{$-b`y57xNt4!7Pj;u15 zTBy`$tTNH-L&JZ8Ri^5uyirD5T84Iis#+N3`;tZ=S@rb>93d6yMuO)?!WqFQO_O%(Wf$G`wikW1gvC>rG+gEB0;`Xo9U}fVFNEUnW7nize#Wk`5TU*Bk7d?e+I4#NefDk*L!n4QOo0sT!XPK^1|hHFF5 z1Ih8%%xt|sWJ`Cnyb4M|3=i-_l(K@6qk6(ZKz_sp&K~&d<4%m+&986*q{B~~1^vHM zP^_s55v~Hdp-Vj8qr3=xj^7kAQb08y9aIKmQ!w;HkQ3jFJYgWDQgOeP%7)}fXE_d0 z)uJ=7-$BwYC0h>*AFtw$Zx87qTvMP>_oI4xrwL$2lRl~#G}&Jbp#-Uu%E6R=O`OOL zj)=dp;rpcU+CwBz1!x&)gHSrHz3r2~$a>ix0rZdq6OYTXD*#U%h(%@dh;y)V9+W}L zqxLg*C4LhzA>t&Yy%b;2Wc8ZhzLwscQ94>45<>lS{fE{VW zaj1fLg;b~fvu-$9;Cd?=HCmJL1v0{d_T25m0LdjG6FN6>S68sOG)+S{Rbfu(!(W6i zQLq|!5Z&N%SIS|3LMQ}8l%C*8d5xKqjV z(J{UGSjq!u+2N|Qt!-JGffJCj!0M<RL8BMO+bgYR{xM8H9zKJ6U2NYa|A`;6%1CcA9codjGOOE|-s) z%7W3|BHF@MF-KhUte{@wPbs=>MCrT}9@{5(U$Ffe)s@p(AZyr==}Sj>{~&0tUvsuB zV9h927;=ri5(Mp@$v2NnFg=X)>C7beMND1E$Vi0v5hALef`*?!gUQAzRtHVM-x0ca zVbyCjPOek(*E!PafQ_4O(_yj-tj7C?6M*6EFeZ_XQzg$2~3| zff^YR%4}zj8tqyr=+(_jXn=%H^2VSioe}iTOhBcE?0AJ8QSI6E{jXEz zLmJ#gJ_>woWPfP$p#Q;=kCK|xo@G>K`e_19O@MzVJDkykjYb8&TD;3wxS^# z=Qx&+2`jOqO#36*MEvn&DHnz z>nS-AIYecD;zJzrO-wY}8EBejftN$98A5Lhdcwf|_dsAxVfeR7C-PUKwA`+xOm>0_ zG!U|-#OmWiJ!Nyvh*{7%NKPEeh20*(3e54{NqMzId1(kJV5j>G+PLZ@Ddid8(+_nM z>NR#6G;b+Sr87p~a6X}*QUmQ^r}%yLVd6h}hQkzf?c?(^g5ku)Prk*dAyM178)Q%+ zFZ-WvB3HYV5c`EnoJU3&5|`2;GO;j7E57aE7U-G+o=0rJbD*viVcaEF+pLaD{DE#; z%|!D6OJmh;UZL8_``=zd_ZEgOAlt`2s#*0+eDK!7+6JZO_|(fobz2D-Wcvp>T5uK_ z9W}6#4U^;jDL?ud6ZaojS0c{@dZ>|Hx~LFmsbeC-E~d{YqFJh__-3ghK@s}`Rcx!u zYvOZgB3i~&og;Rt(LCLoHN>)H%2hEFMTzxZLRhm@Ybkf?(wCXv+j6Ti7f#Z1JEPI$ zyqEP zrOBT;FItd5)WsYf)K*x|?5NZ8UL;*Lh@oKr>Q|D!t-cWx*=JFfr`OuI%sBI{~p11+9 zZmy$)BIaaHZJ~iu^kgom3oW_AuI}>&Gv`b-kXBJg6li}6MQ5^5W`A%9muFcIi?-;>Jq007K`*fg#M-0qE9=pYE zr;dHSij}@PK9F=d!(yu=sx`KMv?q?sMqNkXOZfFSV_?N0< zt$5*h4eTHtUfp2A`v&#=T4jfq9yImLoQitBjC#JPhBLe?ta`pVSIbWz{F@zf+xE=3VP|tuC00{MbGSj{ew`x%J zJOtqEa3P;q-H3Y%(}u2D+rxTpU?dH#Yg(|>X<%I-;oYY=gtZ;zfs=xf5o_&ZGW{I(UZ zCEV73rCw7LYQGC@eVS8ruB=Y`SJ$gT-Mws@Y`W}69RI8Md`-8_h7jot^U$5xC|N%8 zq$>DiZ>|(wTGFZlBc*DAk44bjfOrdY9i^ zHyOIk4t;!1?5>($b!FaE*E&0PSJkhB7N$v|Bl>CAJAiXDd)YGNIC=|hRmgoa`tnA? z{~uUv0sM^llbrk1mk_snBDSeEJ#O!EpWaigb|X?mpNKoxtD-+#+JIKQidOBdq%9cJ zj9iGaJ!$SUnDP})-Ogb12&%;y2U-x(x(Ux?lGD#E2VNcz`uq>$fqN3P}9 z<9jjs%O;c@?7%{26#DEg|Idi^e{gNm`#Q&x%&$>rAW`55+s?Rf4d4}+%Q^LL2?fZK zGUP?KJ2NKbdW3Myr*4mw?-3I82!1`Ac5+6DcIlC=^QObLTVSaKp8nnyX22%oR#ue8 z&iDvj!r7QoUZy`dWcq3PfetsZD&G%`8N!Se?Y~9)zoh-|)PvdBGG7(6G+JBQ4jhOa7c|HK5O2VyhS+q(gZfnhFSzWFRbSLX5m(019>JSnh-DW;% zlJtQG>!#7 z$AHtXmSm?ULx3RqlqRDD#`K!mlJwIJM^)7`Z4*|f(~Pf%jQ}@y`BzQ?v6xZ9Sl2jQ z>Wg+B>HcmHC+?nKClW=^x!%%8P>Ac0`CbJ&;~mAFegrqCiKvt#UW*q8!`-0$RU%8h zL1ISCMA&7vLh;hSsnFbx++lkU+Bxl-bLQD&CQ0-|e1Jo3ZsAh{kt99M;V!%yz27iu zL8I1ik&?NgSqd`qJU{(KwBuQ{V=HZ2amuzms{pm8qCMX+rU@4WICGxOh0a&= zXLzME#~VFi#~=>EY)rZjrP&luU7_&(;~ai?f|2u7I!1>5xqek;%g)XSI~%_+DTu4_ zt~~5`(Q4wsqZ}ODoQUsFXZEu#B_{P(J9ivGLpJBN<6OVB(TQ(Lx~;r0fblKfIqT6C z_lNj}O(36ej^Z-;YDLeUNy`_dG8@wVWdOT&3m94ZObK23G%t zi>I~TS-tOrEG1S)jt2$vj7*6JuqE8+4IKV6No|*H@_PHOyTj=BsR@@YNQ-+W_TLRp z7IXgCxokr|KFN}rr*qH!1>zkYKhFFqo%zJvOycY`vng|JeDd}I@@Sd}S4%o>Wsxz8gJFNr>e;}!WqWu4IZYj z7t`@)iwfcdoldPkQ9&kCSdfa~$X!OU24~iTvEFmTX$%|evuHTJk)HdXt)8(DXLo02 z8XQpnP1ieKy8Ey*Bi*g&|3?HBRD8T}t1dQQA~o|z`Z7m9)M(33+*02+#~v6ZaBI4y z5IrN2>u&G#&f`2kO_t~hb!=T%=CL#e{ucHkz()7nq;OqS&54{vOsmT>utj4ItBu%2 znyuy;+>7upvm>U!3AgG*I)1ipuI>cP^^fVq$9z|_*%iC?bO+y)x2|D$ubk$#zYkh( zIzuSxlA}Zw>#SNGJ}e*4@FX@y`_3Oaeg_z{)y&e;?sJ{}&l84uX*X@9&pV-uX##t{ zgAjW9qRcU7kGLt0ZQiir1y0}8DX~=HV24+8qZJ2xT6J?MENc>834wuT72*6*rvXBX z<6i@gV(~d!kBAmJk>N?s7HND1sP{Wxoa;BOQ^z7&AS3s_cS4$Y5qBFq+-fI1h%2Cs zNY_m(p4Rax=EP*6x(?A)B{^H7va}i7g~-XB&ssDduG+hcJh5rZ8=7O&u&^a!(^#p* z-!x%Pv1xcl_d04G5g*~Edf$QAnIi|1v9Aq4+t&aV70UAV6;7GW)zq@>N+TSjCmsot-& z%`mYgyUIM-w^eM#NZQpIc}97+lKMLTpWvGdU(=s=6C4NpPkQsW_tAu}yCM<0=u6*% zT4jGk-+xzEkLv31f!M`6-$=#I8sP5Yqp4X#sn`VrsV(ZGyUksCz!c&pE8gggoyFnK zC33JD7QFiNid4_0=qv&=V!eB4BC%@KbhWAJYE#qIrlzaII<7WVULDqSby(BYVNF*D zVLhuhN^?SmcP?}OBsh>FbmZk(m!hx+?~YqLR0`+tNt8tbAB%78{tJ@# zJhf-FVXW?=I^j+89K+NAtqu{cc4-BY(Ue2S8PQ+Xhk)&&<>!&a*`kViZ0pP%NHLhowO!wXupA+iUYCg&mEc?WlR828hZHH(UzyQ2u6EZN{WoY!PZXfQRLlb zq>bTPQX09!%3EtHUs2vIM%)V#Hzl*6!pPHEuQqdjCjD-dWZK@veUdEVCre6?#>iNC zQnB=a@(p#;>COTKT`<(Sr4ORJ&0Ttk!-2Fyw4dtMGD@v6F;FR7Vy%UeLL2`712uAGT~BEH@6QdRD$zXv8r?Z%h`9$TinV`wZf8rn}}@U-I_Um z;taeSJDCk6nJKyl;;*^$>fJ+}Mv;iTP26|FW%U+upZnP9p7F6cNi=xmeaWx%)P zI+C!xHR(ssW|n{nn^KrrVQX+#a>f!N(e2D_6AhJA{q}dBp@4>TMou&70(0Ys({Z*G z=FCJE>nJ3mD%fz0O*qU>V^0Us6J`dqQ&<|9!>f;}JWf9(9>8oY$UfM{-fb6MY2h&O z5!ly$>qMT!Qi&+%Rq|vOhq1*E#1FcQk>I>G0&`9zmfL+2VRvwLt9De9y=LA_DuPf^ zt|L#l^P1dL6|kxJIN}_BDC&=U_Ad0MeB+HN5$|(L`3tJ{rvDii#Ej5@Ra-MbciA=O zFx3m%y^DyF{j-G$@0;^j#O`Rn={afdo0rCSAZ8p|O$qN$7Py1n1qsp|g;~v?$Lv*A zz;2Us@!t+0`WX(9PedBUUm}+4Y-Tv0bO+*iZ=ZDBhuEP_dHtp{6YeFcWPD@7UBdU~ zEW+~PU9>piUUO-}y(%qbq4U|I(Cb9P`}Ruq#}n{NV->?LJ7<~OvA~_1@GiPsQBx@b zmZn1ZwF!X%l9v)eJVW{0SZ&01T&xdNiH%HUm+Nu!xr$OzkXUQNo6LejPR9ErvBQbU zrzPBu_Jr5bkZ?~!b&}eteb3}24d|%11k>Rqmos74_8SV#ZHo{U++ovdocQ46x%CPF z?pWl`t;cML$x1YG5#a)Ky#1ZuqbED;e%JeHg6Oj~Cj{qy?dXiNEDnRfg9-1FY9f5d z&Xl>2ZlT@I8KrUwx>bJIf`;8(>^_#>+*URy^X9Xd4C{MnQ^Wk{w{lF&8*vo>l4@d- zxYQ32WwYTEWeX+)ld;zm&l4iMX7-OX`ww&S%8DqREq@Hn4@iu4rn@Y?pr{f+A4D>uB>j zm>V-)d`mqIySzr;iyv{X!jRuu%})1(Hn9OZJH8FEwgi?sBy`;|VxO9xAWbFK%X%CzB(bus!?Kjz*-#v=0@s@6AVwEEcCe!{6y2*Z? zKy(uN3KMjbJzWWzlkRpRJJL)b%<1Mx6wz0_CNm~qxwKJGumW4#r!L~nhklid}f!|G0(ns$h)Sdz?4WV zq&YOso4bJRbWbpC#@QeVIy3pL=8+PjC+-MN>WE`gfX2k+LSJ48!-zw7Ph7u9`Z4>d?1&ng^Np|H9a z9vWQ3j}F_RaqBQKDXUAny5n}Ym& zYrzzQ?l1INcm8sE!V`$mJ`tYS0f=~jTDM1}pzy~VFTbZ*2qzM}(-{KF`gx&Uy&qkGiO%)rr&XuoR+|y-b+4&JFek(xj(}UL zKALcUBtFz+@7Ko?UZ#$|oF0+@on0^rI-wHQk>qxy-2IX5$mpsn;!zI{tMQ6i_V6^nmroNW#X*zQ_7T%7{_ zkFoXV7m2@hB75Sm_*I{A;_p%+?k%E=$V6(!i9DoD-n^gi#J%d$wELKQi&&#_@8kzG zO#LooAcmd;2{%*6FPQrdLpcRb#CCIowv5DDpfaJAL9Rj zH(%rBcJHbtc=WCTB;;xo{h~uQ{kqq&m`Y_?7~Qe0)J7`xqmgaYR{UYp2fIHq)X!fU z40d*?V?cO7BxP<{&yU-&*w!eG_X}C7^D0g?-R$;=NpDKEp4=i1*vZ~>E<4@(4F{~k zR^P0(hYUz^wsLZp)MP}NgJ3e+X9)ULg?#cbsl3K+6qmFaHAZ?8m1)K^gO1DpekIv7 zj<59QUaLM#(&$~#V19|BsGoJsNpW^X6sjh&IZzIa5 zrcf}RXAC?*tY%mT(IHw5jA8XNo`BCc5~A)51yZYK|I@m zJs8iK8$cT~XHAtdHCV8{Oan6PnFlj zewOjU0-%36Kz~tgv{cu^Dj;xgj?H@5{4m>o2UuTgpS4~jI#~{g-C%vDHm>ohcskk>X1@6j`1uH4eL5JJv&v znfjr|qWN6EfdL=oW*84fd=yvTrD`hkBRmQle;#hBMhgX~C;&K>d+0fVoMlpS&i=?4 z6c8Um;nCq>@VBErt_z_6bXuy7NTk}Z5)Sx09YWK?ZZA-4It8kXavzc`3RIi7cX)FZ z(L9*O*yCjw?2WThooj(+r^je^Wlpm>&7$8h9#H_BQR%p5s%f`pP$CF)`IdFuNbNHk z=ckF`aGbBw&D>Nl)UzKQC|y)i$%bH;g94wTn%7W*mgTs=gJ5CwT|9sVtU%7VajWc*H#dctz`D))inNjkq)cr%#X6uBUlfdFC|?u)vyM%bNZY#BP{OBfE8;R8*!aBuEXJEnWn zo5cgAsMa5XEDfabL5`2ioOBjRR6jF)0~hG1EGRHOM1VcL`yJu}a@D9MM@zA$AUgvf zK#>}b5kr14{&QwhLfbw+um{=>TyxNs0VLQ)ZMInzXVITgaaML!Qc}A&mx;Y}15*#D z8#*qVL$I{`HFqxiX;($jW$MiRg<)iXUVO6ai2`QdX85`mji-%|@QB0{nU~9ssn>phWMck4%xG^D+Oh+C?BGv6osG_}MNHSF%qnvc*r%6;IjR@RjT{uUHlf)4I9IUY{?X+n{(Q z{Dmq0m9Y3{v)58QVwm+bV(@3*miEu9Gky>@@T()F4|NbDbRAKC+;?;^hWq9_&!9u7 z9R5vhbj`V_p{ud2?rekIqpA9M4Kam9Pb4PX9nAIJpp57#@K?}B5mb*Sf*M3nGgbtGfmQ~V zp-=|00}FABHW;^WMo)1)k%l;sKs}5hl?XD>SMxHcaShYRfH9>VhlJNKjtl~J>nYQS zBc}xo5`Yy+P8pDe#sVXcQ8K76l0p4=GH5^s4JBkyAId;1jnxAY<9Z@8)B{_H(Sv65 z3Np}F^D<~~4b#W~WZYhh3|h;}pm~f8S|x*^;=@^F$Um|u&;za3{*l%+2Fj0!HhD`p zqJ~f$+K05B1|rxWc@=FJ$@#W{@xP~4v@dB!3~C)Ti7{5114@8XXiO5g}wh$wO+E51iYF-9au3;J(5Ng#C8exOTD&25ol0kY{bB#fpH51=UNHbxBNhn0Q} zkX0-UqRcfHm?Y;s7{LTis3wuSBwP8;uW!6j92vJgW;9& zL}2jBSP>N9l_DAB@QUHSN1#iL15KZdT!2@KWFWj^Wst)w_SBwD0$16q>296cr6-o^83gHmgk%aHwCtfK$Z=3bA zz!eOHUGAnXcYAi*OZHQOJ%MERDLv_S*wE6nQn_?IG#1MyWr!@+g;Y{D-76Kdfp9e zWtqzSMBsrHGRT4@RYVe4{UaT-i@eYyns}RY13jayU2NbaYwYd969o|lsSsVRjC$*Y zKd7t|at(H$i>_j$B%ETsC}n#c4p8)Ku(=SAHNehYQ=Rz!Bs+l^f)Z}Gig!$yfnv@G zl!i{&G;qc>Y{IREZ|zE9K8P%sV_aOxCMvQyAp?u92`|yQqpan(MiR&|$*8_wNWsV> zm}D17L##^#4Ej$KfNIfoz`yJ!CHb%M)(M7;;(sv)mp}mGp^N}Tp=*kOZ9`mUtr_s$ zZhbQ+6oNXDlSMFBGQ+%>p1WIvc_{&yO3bVmI4G`vi(vXy{RNB{)cuRO`d@6!Ejb0K zA5Q=c-Z}w~(EuLf>+WrJ(Jhz4M7xVW~A z0E7&R1t9oR$azjTiW&f1qw}($1a)pz!iF3&=@PTF3yu~xwwCpxGT$Uxy>-S6q<~;f z9VZ|*{@XGF5J?C?Un>-VXh#4B#khuZ1fWsdUD@iI4jXJQYXG<<&;apJMgSrS0jT^!0f=@4U?7ZZI7a{)vfY(cuK6MY z!0vc)RT%*Y6BG+TSYe_9FsQ`}pd{y5S#B4q5bNH$BG9tWT?}Xm1Rx&D2tXtu0F_iI z0MU*B41RG9=LkUKwY##;wO`9ziSha3nlb_qASf1qfWkxtP&^38P*PG3P2M_zjnNvA z9|goi83BkS1fcQ@1t8iHz)W5yRh%P$HY0#0*L;zKg5bZd4F5C7@Za`6_zz4h!5|<= zQIh{QZ=EbXqxr|e5-5OJD8s)vtG!Ob-BG&AewhTET(ID*uZOzqt4UjYZDA4IsQ4>`;_C|2xXF$@Wxq>2S)L|tvd@rE zRQyd8@2u~(a#(d=D2LqIgWu;k7*{}F1XTPF6dhkN~l|DD2S$hflRW+rRny4826^Y~8ub^_Q z-69Gp*r)g#&e@};4C`+*ugHGIv;165{x-vT-hO2yP}Y9M7e?8y^yGutub`%+2#o!T z#8DzBuwNC)AZNdV68YQAo5p@+9vFWcFNF3hlJhc<{mRN9XTKUp1{VF@Ur(9ETF}6g z4{pDLnvyaw_A3%c%b-4IzbcYJ=w}fz*r)g#>Oq4k#QNLJE3#klEH4AuudEDm_N($T zXr}mL8MN|bVlBbiulRnzHDWDmzk-syF~``iM0{sPwP)qT}GN|Lp`;fte>{o_v>u=*SHywUWk;VXhBBz-SzZRRUs)OC>{sPw&`9ycGHBw-`;fsX`xVrb)C1#hBXP7I zfCjA|ScXRHfr!C=#otf{O{S30e#K3md1Jp4yIzx#LC$_vD1s99D@qSU5ZbSJf(Sl{ z{R)D{w_lM68XV8x29@RfZP0|jjUvQw=x^gTv|oKj>4$Oe{eNk{`gq`RgSNc=iks}z zz_0~XdHWSN*;n@pK><3g{p!R2Cdd@nuMB)CW51$cu)M`F*yX;pyX691O%cP1;xYh7&?N{WUp#6$+ zM%k}avI(WNK{5r>(6~RY{fbYPoVv(wzv3eS%XE5}G{?7JL07&> z$bQAE?nLcZkc0q)QVIniRD%G_ppX5^3P7W_wO^4N0UXnQMIprk5Oz7X04%?w>{ooU zqz1@-McQZ$0JntpE2u7`0U`+j2%;1UK#&Fj)bcW^;v5aokZtW(gb> zCMtjl*{>i(tYg0tNitU|ZnD^ZRbBuh2^NJ<3I!lMg8b@VCMtm9L7%ras7 zRXg&sZZxj4*99ZC^Mi`J3lq4>?jXTpBY*nAe-TaWPL#9je8oEU zh?OIbnrWOTlu=;U;SduWN6qHafj^J)gYFlq$ivsH;;4B7d_BGbhmIB%+f}s;p9}{h zVYry~WqaBNC3Pu?8h@U((OIL8yg&J9F^oF5${>R-L<%|sf~eUmfhg+xMXCX>53)*{ zU@>-$;J~A37%V1=ip@6(Ywdwc!J*KSV~iO@QWHw1&mjszsTYRsJVM{BJFh<%LoId% zHu5}5BtjfC54Ic|31g^3VZimnLBJfra)CQ9U|-NA7(0vE$Dng-fQJg%mq91s-(Wfg z%a!I|B*K#gM4kmio*)E4N_;dwg(g|sDBHFJb|Imf@6#rtR_cR z`X2R^Wb`$c8GJz&VW)u166 zayD6S9+A`I*1u@Nq{G+3s)m1yg}h3`zqQ^N1BQD|EBvc?_@^IO82a)`@h?14%)fxg zvH3Txe@TFag8CO$DOvv*ac&L3P*ME@h64Q;6J_`pO_*~izkq)Wg*-u_&~jsp7i=p6 z|N0*MW6D_=y7Ef#Utq&w@~-YcxMQOH2T(}-mt@=oOhbsY0U3)jv=u;9pFXsejRg8K;1Nq|%Hp9!SAPPBG0a9T;Ga6iG~^=?J}t}tGk^7H;KZnA3v*w$T`z)kj> zCSm%uSMXi@U45nfT@)c)#7{YY7v%*lBV1p`6I8=)8Dk@M11JD6Dq2-j!r#@6K*sfV zkvPh*nO|Q9l_mULkOBhYZ)n$ynlh}v%e*3g7tg{D!>%tQ#eyQczKq*k<0!qpj4zDx zcj?Io^LIf_Nf8)-mm$A6HW7FftS^JkybN;wE+~<|D_|TbWF8oQ7cYeVt|A!-ACZO( za{exEOUZx%&ctg|X0aAD@Z^L0yT+4&@pqMw0T9W`pdLE&GRXP6AO&uE{Ab%Gr$ROwM;on!St!~l@^8_J+6FN0e13VKjkBm?=oNI?cUe;2o9WKc`-#WJYl$@`FjflGGD zZOM+nz@>nB#cOk!n=KakyP$Kd3`7hdiNB!?R6rQ7ZC*hJwM8hq;=kMY+Xs$&8>lVSRucx@; z`ftz^+vyal0kQ}UUglNf-KnRgW8n#66$K+gcDVt*H} zPT1cCNwC;FN&w9~MgWx*O{zFY02;Nezsm~XnEoybDHed>!m$Nl`3-D5fd&Xdl+*zE zyGR?Y0pOO<-v!lWG(aT5qRKDSfJz=C00Uw0cTolc(2#BYT~+|c^mkE6u>gb>CMtly z$Rh!i&@sOsY6X02;5Yzsm~XnDN>a zQY?Tbo=j8##e;w#OG!D%-$mMJ4FItO8Xz9Z2tXvkqRKB6KqHS4z)W5yRh%P$Hh$O_ z9esDWjPGHl9qB|G>->#%qtqzx-V#_%HBxL3A1ZMG_nevgG*3-z5fvcx@mH z84PBbu)hlzR^adADi^QK&NO)#!c7pbt%wut&GR==K!~;|DmL5n*UH~jeBP6P){Nw7}{fUCe_U!LYmG^D> z!CR04CZq~$Ldu^9!(1WUrwE3O9f?C!%Is4FodH}9?MR~hgW8d(#gY>STx>m2634eA zan#3{y;-7=f}M!J;e5fC5!jLRitI>~o3|fC@wOSx^KsMM<|YiK?MPy|c-_CAd@wuG zcp@-%q_H9>h?|DaybN-7B*T4Ajd|0=O8ilw{^a&{z$!A@iux9k1`aUg|e^NQ?9MKUmUBqM{o z9jUAgn#ahXRWg`ROR#pNJlBY|yd5bz+KwdJ%iEER3`Atu7FzQ%s0?M$TqFZyM=~)*18YYrV&2-3U>7@*WRQ!S z<}NoZl&~Y^MG)GNtO!1c9SMTQw)(q6a5TSc?(-DM76u8h@+ds|xm!;tmZ%YCHT$dI zQBhG-k-e5hbo!F}T(B$<(3|}<-!l(i2_KU4lTQZJO)n&SdPVklxEAyjR-K*$lO*gP zk~j{e-C>I-vp1h4Y4hPz3X3>}%6uie;fbL5Qw!5ht;qh2Qo`a-%@t3=Uym-nS;cE9 zqvEFkt&3cweHssqP-_c?T8qE-O(RrIDE#SftvN!nFn+;CTEov&6|F`byB}$he|A-{ z9+9t$UUPa$1vlAR&OJf)eO%yrq~v-;iZHmkzC5mO9)+l)gtAQx zO=u(?wVxJRP_hHHxVpLwuC6bEr$mZyb8`+$MEO84hE&5}fUB!V<7#nUfU6~evg;AW z@+e%*lMjfi#}R?W)ni0Zh^q@_kjK^H9$al1$3JVuVQ_VQ9#yXv9>1-QCU263Xn&$Ime%HV1vgFLP- zD}!c=FP>YpN(S!-SLbT}n7F!r46cUuW8iAZKt$$ob*?Q`hB9a_l7Ye1Mh1CYT~-E_ zV`NY@VHuRf)j5fj!qsE-pa55w(gP7AT%DIeRbCHjLm5;S$-v-hBZEAyE-QoDF*2xo ze=?XDuC~k@T#b-IQ)e-*E+qpIBix*qL0w)3jiC%`i)3JMwUI#{SC^GR;}{t#2xJadGs@+A3pl=iQwvj4HQbm;}`6w^>DCJ z0`e^I&w^O402>8}rNA%>V(B8Gz(4!l>jawu|Ez&8<@~etvQqWZT8roW=%{qLs*F(nm1{#nvSDL|2bwyXd|63hyyk_MMr#1LCFh?ls{tYj z4N&=o0uZD@00zRyKWhX~X9S@Aw5$M*>7N}V0AYoR3SdJ1*?@KYvmz-3Eye2*p}I^b zD3TC>@JXQngl7f0ne-8jv3a z#6uYYh$IA{@(TqZFoOVQ@-nI7-1uiD0QqN)0FLRO9m9Xy``~|+e|9|n<)1CVf1!W2 zEdL@24h30q{NtY$gMoh*$U+8#StjnEZ8x4+cJIX6mHiCHKLbM+nWuI=V#T70>?tH* z=8@eI-{jRV2DY1G|LiB;eQ)%BT4%g^^;_gE@XkII+T2DNZH$?!yCQojC&&cWCm0Tm zIv}AA5{%VM5&sp0uKoL=_bjpPg;pN8_;YJb3m6HDfQxzhwplS?8EJ-*>=KIMgP6p^ zoKW!xA(gimmVG<%a-2XDl6QBGyt^y1KPCb4tnE$YolLogslLJ@`i$*ui#;Z%g4GTM zmaE+r*~=)!(7nGfVShz7IlB0J4!&n<1dF#nea?zaL5<{1l(&#U=l>SiCpUJ-rm+|! zHjUG{6R~NDhI#x=>zw;(3mTSP5!=^yAXfdQCvTXnW9_T|8id7xW1nz#9KOPdeTH)Y zwU_6kd7hfJEfu?9M`}wyWOOT+d6M4YxHYfcXI>B9>PyWU zBI`hE%Yd?)yYztLCSHrCdNxIzS$ktQ|0yrD^dXVupS1R2ucn9do;aJT(_8RcDs=%h z)ze4jjn}=<(if{%eN>zJfL!XM+SEri^^xk?+g)(TK7I4#nM54jbIV%&qtuycH{Gx>?duO$joHC(QDr?FXKp}WdJaav zok6AQD2emVGSTm)B11=a=lARNr##a;xq_^#MGo3GW$UQ>M@HTM$Ef?C>At0pBCwyY z|8Er1GaTtTIQ82nQrO4&ZtUJ@C8^z}eCSQ}?u@N|O8E{(mw)5iZ9NAgvDMh~xt|p4 z-O5GM?QiM3BJssZ%WH!7{1is}!7CE8s?J;ShGEXuN6*2^Snm&brKK-T_7`ow^sMN% zf z93Q)W6*pZRv)H?Jc}v3G#x~AZ@^%7MY092HjQ}Wr%0fNhxb!BPHYBI@kyxS+{W1QB zgW12q1mD}Y@)N0bJV?a{IwM=sv-YQA9l!10Q`zZ0*7I5<)_WD~r`!=So>z3|PpJBK z2*~dF1?8pI({EI?&yGpu;2r&4cvc!H8tV4|Jofe!n{H9>p4)r9`24N{MrBDbdOAlU4JW2 z6R}^N8%g_@O-lOnew|SMLm&C}>EsQwUA=fc9lg#M(HD&W!(a9f975XO{oa(TFX(xt zx%<%Z-+s#J$u{?l99_P%e|I$P{yq`uTN6Do)zcptPV=^rQ^KG3502aCbRU{>^{0dP z8hLGarO6>ub|(GVKi%`6mJjX+9KZdi!wX3_qz|9Z)mr2e=ScUhsh&d(E53a``WxPE=CydA`CUaPXB9@lCfWPMw0&5 z5XLsAhrG2$80V4g;FPN~Mi{nS$G;LeJXj=$-A>Q2k;CK2AraxozbBkE(MltTiw&FY z75+lRuz`G&N#9sc8-9OiR{kXA#ps_@*uy>3KFrhuO1ga>co^d#g_1PjpgZO=V(DdxYFhVRn|j#sWJo7+z+TV548PgKsS<;shZ>qE+Q z+~)QVmo0A^IjfbkvRrvJ(^LNZvpVT!%}Q9gTZcc5A2b+u!v03jHwYgvo>MBHv--aN@=t%UVnadvp+Du{ z3e(B|XgB$T?sV-}ErE^hkoz#lbc-rK+MV*7dfRC|DR(&ge}5X_(%ZNEba!Q~TbtU_ zUd@)d75rA39KCNZpPX{fwq4+#{BhyoO6m`T@>2=7PvhBRB|b1qAK<7(zOlqzR-0_; zOKKQ>W$eco73%pmWHFXx|ENV$Of)oiQZ_F)+^3^kQ|`g+r{f1n8Ay3#1B@*HDAbv` z&j#d`=GA}xgG0c+J=rVFeRFo|IU~B?wRUY#UyK@C*v&=7LGpvC`xqbfF9z8B*4c29 z>VFv&xuss8TS;jm;FOdhS-TTRKGlTB^8T0kxT!7E&)f3bQ|ogDnxPDE8vCvQycDIN z=+jlSmCXuD4`p*m;xGJ6p=6q~f7om#Gc%CPnfIM$ihezNQe#ds&5}$b#I;M6Lj93^ znzPrRaVUtFKq|jeJzBZ_o`QL@E!3X1Yn=r_4L4J133o8T(Bu9-_K&F>e$RF@4Gd|* zA?|{PMkWqfKZriljCl6x48ZNN22{BY{u|l|Ix}b_Cs*bi?RNLHOFsqhk9O) z#qQnOpPd|e_zY&y6>fje*2p`+`tFKYvR`*6=&oW?a96$RIqss|^*kTxe}3xm8{A!0 z-OfAxOeA?@m%FR`p@?pYF$r!bncHf6dy*2&0~NUozLG6F-x>NTh1SMauVhFCI!yh} z7uO%h6Dh0Z`0Xw2%TI5AdvpErQ+1N_&hCf0omJ26CQoej8@%LhAQ3!!D%Z)D7nm1U zbSKQ6zGxtmnPV!nSxe6ik}$zIINp749_fp>OF_LJFO z;RtQsJ>c$oXXi;3-PIL(T+ic|c>K-|zS7-XvFh2`e`2a&cqdQ6)1QN#c7$na^>gjK z@%Dyxb8|*FviVXspI$ykBJ5oNt;63kA8xlSR1W_wx9+ZjtfwmL>NJmgjwE9@cW^O$ z8ZY)7Ipw++tne$MZ*QcyDJt$$q!+l$=r2Lv+2j6VgYmYkqzne?{XG);Isdjwt?-orzl{rFe zkZy=~?$y2HRVV$szV*g8+Q?Mv_&3KEte&6rfAqpjPp>3f9R=x0Y#Ygql(A~g8#nX3 ziPy~~LkBP2dC%W|ou_S%{|j@OZb(7X$9_`zFFZ{<{(qXwbi+JKc>ELXN%z`@D#yR? z!Y9-J;Vx~cas0c?qI zdjm9dPQPmvd7B;o{x9^Oc{X`lDc4*sZ@3(KO@?&CVknz*^GhG614c|g{MU}|@9|nY zpZL?WcU1CP!tsCh#uxsthai0^q?^3yhGo2Vf91!1g&bBw*;$8gJmlWk&`o8K5ZtXc zcQ?PZV&gi})L)VI5BuKzJa;#myYB^eYi-)XKmY7+N&CLJ^Mbo|_HNqqU%!g9+icF@ z?sjwcy=|BN<22HKZ0>Fj?tWtLdLDb?F4FF_IfJ{qZCcyBY3Dnu_U#_5o&|Ty5w=)z zRt@~wfBk18FWqCZdCErmwFr3mcfWcm3F?>O<*lu$y-EKUMrPk{cz}mYv16+b(dT=J zv;VoMEAcS>3=q=7rX~7 zHF}*KgAU-B>89Q_Id&vGOMw$9EMsRu4)f{P6W%?B{8DA`uEQ7|e1FutCWY@}AM1BS zd;jnh0&w(Q2{+NQHPWAGd0j6*Ci?qd3bL3_sy38mN22ARsNZ5rc{#{p_*34*N!b>H*Ya0?!!lTOZ>VPI|x}>mn zsKKBewjAX3s`1_{FFU<8x&e#!mSKIZgr3fnKzFnZb978iDaK);?HDp|4P@T_L1a$( zO@@R-OX=Q+Im|J>-w=Gi`2&8x?ik;%J;wK|gYVaWknaa=ZoGO+v^-m?;_O?`ma4Gv zYumm=@2p|YbOzErW9Kqs=*H^P2gw@s zRl0*AGubleL@-(GN^k;FWg>#oGe0r(=aPqlDu-S?}ely>yMI$FK30L!~ObWrTiz zUg40XFCB-?Lws)0ctu`bP^7Ie+v04Ii^~+bbi5*$6%<+6h;5O} z%M`hCydtk1zsPZlJ5Z{q{owa*x}9-LQwBjsdN6^@@yaHbL6c*-7OMZ;K2C z<965sMFv_9@i_yUOZRS0i^wulIrS=I`Uxuk0W-G?$`0ojE!!yj0I%L|ST5Ofs!krT zlfTks>(iQljG;T>S50z&Fb|jsN0OP-sLs$d3%zb;f}{IGZ?&EIKq7tP*j~}lrKw`s zy3(|9oJu-WN&yB7N-Na%L`#2UhYNBVR9|m~hJnboL`$GWL*}Xa<-W*J%l?QN1I@5t z#?XF^tUF2;u+vg8WIDqv^DhcWw2VXshhHDTpZLpm7#RLREVKuElNcW(-s~tpPSl%S zsozR(c9njsHmvm~nN*u*Q}jINk1II8Z)U>#u~8Zg$I{jmN0qvd;DsQ}WX1XNXU|Mx zPVPM#>m}Zal_YK3))GL%_M^r@Fr3O+y?Zv`MciDO{gncuX1%*Y3)ONyY7CO?nz}E4 zh0-qYn+AaS>%=JN zKDlOc?A~)DmZWp$L{x|hThnon=ZDUjGigo7A+Fv%XU^m`9q)2=_?$V>H64e!I&#jO zDQh~8aP{6fbEdB8c#o^2=gc{7O~=t3bJ<}9H+da6gpNzkdVWQ35naxOcogt+%+vXc zI3aAXgfUdy0J(5{zF)IVAwRtrfOytAUTxA_2x!?F_>qY&aDU(b+7#-)Wq-om-t*Gr zL}ZuO_HT*E!_KPVIoA*VceDZfc~P$Z*G`P=BCE}(K4pWm>R|mJ?%TZL=PvG+fy&OF zzRHAq@!|BWoh!ZvigGU7pgMR9iq7*}k)f4mQuNG=I=|Gr*gF%V=NU{RqGu%GKHR_W zMCj>xd2+&Q{be$;-C5Nyni4JhojC9Xy!3cMZskLNZB~;- z5%}5pxP&J|C!hMt;nb|hV!dC-E@|miJ-g@R^1@8Yn@u%L?wmz{OC$MW_fB@s!IZys z4ZgpQh;vSRWX){+>G!rzI;UgOn%R?dIr*H9$!lg$)@AgZj;MFen%Pm^OgX1x%9`0z zbUF2$j;U*APu1md=X4ymX7+Ij@8YPwKSmygL$FF9jQ_>kyMRYgosa+7kYEsSf+iZQ zO0YqRB84i-D%vdU>O?n)#VB43DEm9XG%uDTZ`R7z}FeQ6O!#6H93*%S-3DYU%jKweO2yz zN1f*W9J4-rm0WJ!wd8{zaL`Xt+2ssgY!fM7S&YwDa7|{mryo z4?`H}tZOvqKFB?Ulx6>rMi-{W8`(b~bPNk>np)m+1|suknS={7p7kG3?)mitvLX|+ zLj#*x?qCICe|D%avfmSO(rBa^K&EHVbz{O0VxL1C>dqNu(+`2hH5S$HOMeZ=( zkJG(LRcml&|MDawoKL&tb){qPa^b+oXCiLlTM;aL#sj052xPiZIXY+r#s!UviMkQ! zv8HT8u`QN$MU`O!k}tcDL_wp$8s159Gu)%K`@LXt&Hq^&jdV{&@xlL#VrJ=ft;C4}y+o1iHD zaVJe6=M7EJ73t`*{sjVq<{2j0g1UL)Bm6Yy{+>F#&(cem>v2}yDxQ$+X zOS$e%-r&F~`GV2+=#nfaEjEoh+RNwEZAtK?8lp1Z6r!qQkq<vadS zYI}R{zk!S1-mI*7*UGZ~4_Se$HqJ@+xrR2(0f1xPmlO1KX^U0{&AgyzZ)9Jw78Tuc z*8`D#Wm;^5bYY%jtZ_Q1+bo@HvB~l{);;GR@*S39gCwmU=BY&H>7l;-4pJv$H&PM= z7>$FcvsnCJnN!AXZ<5*67P+G-i!z#1q)kQx0@9<=WDxW??^k-{VD0@sXDCwL`URbo z)t@8idtd?;T=`ab@DgZltu}vv^kYu=?aR5I@f-Ab%>h@wpb{{uJzV{dTKrZk)<1ic5f1)oZ< zlD{@j-s|2bZT<)H2>fsUoVCkyY&n6UPhQK57GCJQ`H>WKCsB)@!=3Htj{~>+JoIZx zODux|oypds8>QTiR5?XWdB6-c6_a>q&dxEqb-Wd(cW~sI0PM`=KRwiRQc}pL*d9G=`8N6Dd{;(@|n7EJCbF>Nm3nozpJf98I8F5y z7OSR*{#@=+>E9W@HhD}6J{@!e(6`VZrpMc+o4)*TQZiRg(T&OZ)}KBSm;vv8+Q{f* zY+wCcFYPAZN$DFWe^h1$WvfMHaqI5WXzxNZw}^rw-o>eF&K<}d?3GsDqptyN3(@o8 zkImeVb!8N6wT3`Q$q)MI)689~UWIQnb6dD#B|Q8ZbN(XNGUw>9S{eoDc9~9Vo2W4lC%lmtZ24`!JNWym+TLXL)YtUZy z75Mox5Hap4sun@;U0+;>{D&B1rnihv;oEPP4G9_zL2u)oc>{C|l9hLo>6#cF^tObz zVr=xIPsxRQP7o03$-BD-^X~WaNCnu)1yzaD{`$L5un&xKY0>HhtGkk4{y~z2fR;x+RJ4Hdg+?-xIe2Xz|BB~Etcn} z0cF82z*g(%K6-KR)fn_PfG;d!@0vTG&%_rjXOO>#yH+>RnYL+tNC^!xT3r3?V&_xs zWqqLYFe)^JM$Rpl`UwD34V2HCHYw<7tUI^=yjR!VE7BjHB^u)9~v;PcGS!`Pd4X z`BBb_>U7PIvDKQHzi1X3QvZL(Kd1-mI=&QiQXaoNUk0%v^qw#7Q&a-}8~fpZGW42o z@IM*+H{3Y{j}LlXsp!?5T(Y;d!5Wd`v!Hq6KC+-l!~>z{Rb1^eR))3mS(kv*c6U(H z9>pE}JL3v>nspN4fNi#DFJC4YE(gPx4|9N9?TeSESZO5~1|NPxDvFO1(8a~T)pBQn zz*X*D6W&ViP9J4iK~Gz9Fm|yovQs9Zz|?c_caJcq4S_S>3&hsW`$$Nv!qX--7B1Yd zwZFZ8*);upa(J+K$%wggxL#+gyU3s{{S0-b-rl`KFKy6yIOD4R)fXyJl=1A)`%00w zj+Mzigio##$1l(mj92_uZIrM+xSZ6f#>kc0|c&2w2D7aG&?^T#MezV|%6u-)imh+{HibOSqM`8>`E;xg-s? z3gAY=C~2*3GYw@8S`$RyHS8>gtXM{p46&|xzPb*17Z}tc>o0@W_y#qG217|loG))f zX9#)gb^GNeT*gkR+!^$TgbwG)&2;I!Pu@`0mI`@Jh0xnl=2TTijl+I!BhFdhze=Vr zpLF07ZCE&~TFY;dja=2*cUtbOq2`HaP?O(LpWQY<-mc-l28IkO$8Nd%bne)?buCZ7 zQ@E89cLCA0xof!6^212|<@ss-wOiN5Q1jEZ(%L^%YnAOhJdFk#8wb+nayE@MR%=%* zOFj#|@6qOtddlgvK>&G%YktqTMLoN6xpeIUvh%JprFEeGbS;l9icP3+dT2}auv2>Y zgdX0Z2cXYq|Je-2`kkStQ__KZI9CF9wRYul2X@dT{&HPs2h^v>pD$6rc+DgYD-$J- z*+9O)AiArZP(kE2=n*Qzhcs%)CZ_X`r_9n-}})!k1Tyx-@6$)A;aw${ie0Gk3EioyXNK<*W*lL1=TGVK*ZT! zs5cMfGAsF;l-&^@YTP;?tG96L-{>t~_%JuvR_=W)fdtO&l2=CV&&#kNZU>GGfxb}j z^F*;Oo$x?Km&L|K_6~*5z{l+ZoLQAUI=;_MYu8o$D4$c}^@jbYuuw~&O=7YseXF*t zBs&k+-e3Qp+H>Pi2toF^&?NySv15oM-?Ty?(i`kkdJ7+Ah^g0o#4hvM-#<=`bhT)@ zldXdrkXC^M<;Lx zgx?$A>x(O~VJY}y~9;2DrA5?q)z}^|5PmSi_ti2b<{bw^3fi4O;`ovpvVD7cL z8R+uGuPy1F8lQA_>F2l@g|{$`9_&+VFd&vknmw!v1Kv%EDS0EKYTZ_5!jkpahMru~ z!){Jo;44j3%t}nr7Ws3teDxRgmU}-8FZC^vyizAt@k(|~Os8Ge>+LwyJ;dS1Fed9p zxtlmli~f{5yMRA^D0J;R2X8@wFNzziz+2Lg3c2q>dl92p!ailrOEKhmyU}F*k`l!B z-MD>PqbPcFJSl04SvXNQmEBRuMkmb7&`_%woD1Wy4`BceC__DkuS4w3w{`PK**SJA zL%>JZn+FJYh^tlQ%ma2{CR2M`2%s! ztmCBstUQ!-?&RWh{br&iyhvG_{oyf>M^u0%bhGYV6+Tt>Y~ohJA%qYqd$wiSS3H=5G@Rc>xb(I|FjE@=$-&SY2+cr^^cCt;oLK z&~-X6e914#vx2Hk{F3tKoDwyHSZ_$vP0jkQym3ZVZdP#aA@@dCc{4_O-#{gNB#cKe zbtNa{SSn9jW;gA$x^`>E{F-&@D~#eVhKeJwgLD75>91o!B^&c5HMQ7B-F33P!V{hj zHFQVhTaTX5x7q6@o5`p@K~*qtJ)Amy_B?S+YaRh25yyj4=8vpLxaK9I-0VM9Gg)u27yJen|S zv2_3tf@YvtsyVM6`s*iu>N@j;7*H(ImmcwEp*GMgy74GTC)m1Ld!#XF#5%aiYt@?r zIu}e%V4C|o!~LBpzgq11BK7umxwHQGE;oedjeuo6rmk_<;IBdB6SZEBgz~rOW=y)# z7G*{8iobgtk}WV=>ITMt92ifq=%o&Bnge6xnQnxM7=)+MyW9#C#qMvH``e>_jfx`5 z!c#9v9iEu^N3*yYcG(A3}*Vp}^nj|fH)L^hS>oJGUs-|Ir1&muBlZo;f z56aU>%@|r*i5bfxLHgE^*(P zRu1=OU<@i*rm|mP)v+6mgTAG_kp)F?5$i@Jt!x@oD|y#3kT=`fP!yxx|mo#=6)JL6#Aeh_WZ6|4?yV2jYsagqJ( zhTeljAHN~VsROlOHEYtT;W5Vh+M%^K(H4==waxAEpA^R@mRJ$Fy9OVEg_9&i4JZyrM_D0?elL z39y`{#X|CA(M1Csc(U!&1^0@coTsuiE!!^Ssqa<(^d=up)z^(0*-m~$>OLUA+;x(W zL!gblh%5s1hS{!A_S&S=wFh4Zng03!Ib>C>)*S@E&571e`0){K@|#tyv=nG@bzvN4 zGXfo2^je0d8;ZLF#)kpp4JyM;9WK42&30M2giDPk#l|~@+Z(LUX%-zuc}p5LYC3$z zXY@@~)s(fnRlMS=4(YR%pd_@PVr)G=2d#W^1wQP|e-T zaKM6ht8xS=}gCVYR!iYd!!dU=xHEPb~u7?Ye`QZ18G2lOI$^uw5DSe`>0Yg!31;} zO-Ua@2{|Pu`Z6?UFrG6k=mo}Gza<0RHup$hq?5xM>e)%@vgb7!t>3|8KU+dCWhz86 z->lHn8-BxIf4Ux@;)!*KpQPdBOMU!=T+GMDP17?oJcy;%8aBkX0cHSIm5 zud5HV=m0wH8&67Jp71sp6TM(>-Pf-LnZ7prQCd*+?~r%E_`)UYfYF>RM9#~>C%slT z3sXWeB|u|&xQR^632*De$b+9D2Gfw-BR#o#=?Mxu{m3|#QE%&yDUkiG7l+XGsXwZSNSJ#4jea0rZ)pHPLvCd+I&aPf9%E_Q0 zrJ`6;X7*GV2LZ4rXn4v!aQ9xdTJV*V^-M~_^pI4@Q1zvf^?IJG1qZ zH`UZ2sRBH3L|$$FS5KEK^3J5%|2$2pDO$ZJB`37#?qd3g2j&=6EtnKjgw1@cG4~pQ zR*ow|KO-*ZFie3m;m#AN?(o;&Iz^ORcyFLZW-@e(5E?EXKM3Xm8qFD|djnbGTM()= zE2v#VD|_`>C^GytZ;P%?ZNuHB^tY@(5}8zT{yKL$)LKIob8rxfr5=l?R0|-<{DPG# zF)s+!9lKSFUIVEq|B!X2JnR0I0;R~ODe^omkIT(tMWWv-gD|S5*`IUv zkfMi=mDW0xd4Z}%H01S2mE^#UZOQD7ZQ{n56=RUlI&s~Z7Rzx=!WcW3jvOKL7g7V1 zm|gI5#H(XtpPmWpKj_tw(` z>x-_`oNCb*d8fLNR-E>k8tKex0vk@-w`tLvvDP9zH)+u)VA-ZX+YRhZ7rPSO{lz#f z`n?f?puh~H>KUPYcK@n~f+MJe0gS-22CD($-}dOXJVj@<i_feY=;7p9dHs3^l5izP;ctlAD^Ve~s)-lb>gmBjVpD;`HV~SK1#|X@{YbbDt zL3JY#C?Wkov5c;&Lj~!g;6;E`_G`c?5*j4-5+j(m1C@bqVowkzjaV}vvf{gOX$yaK zHNkjn`-@YyJwEi2G!$7ySY6q1GQ%k%`dGkA5fM7*dstWy5u&V3dKY4fKHw75qX{+P zv41cJV#WW3Ur;UlII}!HPr%aVXQOAZn`THS0xRq3K_Wz9Nt87e9Zqh_nK%wgnQ7fl z=Q1huFA6ZW4-sGnMvMMEfczKN0rqe6gpX&+!8i`g>CXbt_1F*sA=ZKN3{sBioD9db zj)9~-@534ALb3umkhIDufDSL93QpN)HIo4gR2>2;U^HWT2*4bA(2?(p>|nuVH)%)$ zXKsNoN`Qc2<&6>vd!q@^&a1gmYE$I}Ejkqm#6;C?tp!>Vi(x<|?@ESK(yT!X9D(zM z)h3rUFX+a^NMH;uX0LrUMVUNQTbAvESCu?JtlLnJRihf6q4eOPLNw(zJcOaN1op!I ze?xU%42X=+(V>%IpszA{Tpjx9^8ZPP9^P$u0HiX_iqL-sJ2C-tpp+@}*&!ZVT6?mb zp^O~AaYGxCZ{h!`bPT#<$53y4H~NflQ5be7p3CP&gbv^nbd*E`_9wVgy6i&G;(8Ui z>CVG%T1CtHtFe3}ep-z^0#RZgr}V;$ly&sNeZ1h54dcU6we$zoKnXb0>xg!>id=zfOcOvbOJ3&)2`PsTrJ^&2MRM^yVNgGL-UNGj8Z!`%*=l`~N} zH{uE=vVFB*`~WO=!GIEfoafi{4!y2shNN=ceG0QNL&SIm%Sw4cV~zEEBfZHJYbRI2 z4dq5-dHh~^IX+SD99~o2{6G)Y<)0qe(W95{t80)t4fcRN`g6MW`mx%g#@hW=_|76w z_n#5Yx3A&~eEXVmvWasHlu(Qam-U3iCQ;A=5tGgccW8@_imnK?*Y2wdt;gXyIC0IL zZ%$mPMcxL$s8Qluux=W3Fxcc z$H9oLupS4#X|eGX%9McnfmIOPy$qQ=1DULPm&h^91LGZ+7Oh6MeIx_VK<)8}*EDK> z&zw8SS_pNi5yUpkJ=w8;B1w<6W4jFT zR+bN{h~Fv^9Sh+4WCFE7TzWOiN(Gn#M821*z;J`__MdGbk{tvr(W#c-yHkrHE&vgu zW`fv7VwQ~->Try&Tj@E)m-8vej)dbPpLz%*d*8w8SI)@iYIzYeF3bsAs8!6r+KE{q zA1S@UWptDvz~4a&?V9yBLa>5*L$$fVGNX5d-T`M<-@5Fjdy9{MgSFHMY3NYG&Z1ImS| zw3xS|q$W@Y3B8rJ5b>%x5*`_n9hj(vc9atUi`^j33UN`t*9x6$UnxG4qCde;xpd&* zr-E^$@bg`_3iwgM>XW%oqo&zDM%q}2iy`L)UX&eK1##ezm_oj(hjpuRluqRN?9At> zz>_*(*r@8tocPBC8p0H!qQtt1&me1{H#Cy9Ia$6L4pFi)s(UMYSQ^cJjS`shER7!F z(q|XCq?oDAvJGfnBvl1xDn);bMi%x9O76mjP(eztO<@WY(2j3xqczn*k!clGd3(1$tZp)xz;}7HsD(G2gZn( zN*r=CnLpyERzdSjc2ovMY=y1IHH*!vXD}I`a`BGV)uM&STh3kz9a*jtM+b^<$7W?x z;VsA-dllU)c6QLH>@YsGhS5GMzQc(sBNB!B#kj_Z!jk2vvDjv8yvSCpmZ%te@rrRQ zo7{*mAgx#<%d@gJ+&WGq&~0el;CVOT{u<&iMtaZKNFbc1$Ylw1g!4#A$^F+<$@(Ey zeWOC0vSfE_!)W#*={e6n3&L?M>~?T6!@5IKjuzFl;RFh4&Md2+q}(EWIPeG6&uf*1RlwS$rCq&pO?;U!0)nF1_dP_weudiO{b6w(x z_R*Xf=G3ad8gCaH7-Ttz^Bf7K3+7W4DhByIA2PMdjl~gGo?nKGZQV?=nSc4TZnAYKE%&G*m_o~Yr;u1p2Ta-Cc)z-bNICO=SJ{q)48Xdm4-1yA5 z^fm=un;t*^`SJl-$&+Be-L&SL*c?6u@i-5m(Ci6BLBcPXB-b;wJ_J&qPavgXpyP7ic3)jj9@93^L*N+2Sk^#Ur==5c1%OO zmE`D!NY0BLWLS56NJFx)+ySr@))4I87TjQNQQT?K{wC<5UBNJM>jNyB0ptO7)S8PK z3b@D#dTWZbNITvlGtdV-^VwPv|8cMNJNgWIZzuwvty<(LS?+Y4t)Q`keVNIzu3;K9 zZY9u!F%ZmL%moBE_EYGSc+;y$L>{o-s0HIUrd{vwYlQf$_{%beTc;)8bk|D&k-etM zv>yk8`cJ7H;E|*MC}*@JnK;KgAHPCrc8Pc)?LJ{rtkX6^POkUQFglvDsiyS6*Q9pXuj8z!X?g_imuX@zVQMi~?8TUcac7TZh}f-eXj^n{tOQcCk9D4l zNVX#>O$t|V=#oTB$a5I^zJTb&cI!t&WHU46>Mz7@i18u1feKx+N>#T*+#dw$tu3jb4H^|Y?b+nH%6lQ3 z*;)3*Ok79yoECi-$6k~yDG9JnO7h-7FRF_-kxuynOo9mxwbH~L!Vo#>cl~8SF z+I1aPIqkZ3-EZ8c6<(tM6z7ZP!`bZ}icq&ILRFUBhKXrA?iSh_q>l=`zy`D3XeI`@HpdpVGqgx<&GC{DH^%(1Sv>S|H zsq9&_Q2hy@Eq5~YYVV)OS+>z6>=88B7qKn;3nxhPG#WT9drlP=c4g1S{{W#%_6+0c zVf_MU%$t<(L^P3wlFCTYq7igKI;wQIfVcf;>Zz%lt)}j))W%w-+kPAgsr*q@;jY70 zK$z7?nC1^s;m4{1dIlrNJ{EUKB&MihQNykbHCY$+VlYI{r7)Pp%ZY{C1s(sRclnpU z3yS)@OUO+L=9GguS~aGE$LbW1UxIxacY9sFRfvrV91j}kdOyU+TcP4&IiJE$$dqV{ zIJc*|&g}@^_qYx&=CrpJ7x(1D0wD_$#R!iq`)Qg*$g=iRFC~reG$ zGimE^5lg!mixcL+Zcy$=xzTOZbdiniA$ODm&39X!&kHUbi{mjRyohZPaivDLS<{tv zTZW@Hz&Hs*o>lgGJoaxujNOb7W0um2x*y2$)}D5)zMiSjsr@2zxfqIR_k>sYPv6j+%l$DO;`I6x1tuDW$)106E_{fMXEp zdjq2}yztvM?U%ryh&3b*Yrf7hrgg-+^hy%aR#?)0k&<7BT5J{jN@QvVZfp@&DXVFh zOt>q#7XHn}kG+AX)IeAkOBh4~AF+gA3s~ZyZC>NXKi;8G-}*i3)@pKJP3G0tNb&DT zF{HS$m9LJA2uG45(v#IGL4ML&MbIM2uRxOb0vK8#p8NcHX-R$od)biXu?-^29YJ2Y z%zCG_PmbfIiWHwi9aoCaLFpmIA%VvnA-+io8rOi7^R!c_i2XH%idLSwrmL8(_Y01c zJ6$tP`UiTBjlt}yMJgS3$d(V7+=1ca=(4wgMbq=Z0h3Ez4!nFrn|~3o`Hc=0UdDO+ zlbB57xB1i|8TR$K8eccdDZ9O0P3@x{$ge}}d$Dy2uyu~MmmsASCGYvN5EEe%U?4tY z4_=zj*a(%0o{WCKZ{1gPGLfn_T#JMi7JQqPZ1S&aVYXx>(NiePq+JXO`(E7yvT#y1 ziXJ`0qgAb0t1?=$w~93uJAjI{pHz+y=kKU|lP{hH{bKHxih=a?vUbBnWqrj$_!aho zjgEcy4Rx5BVtWm3r>C58R(4o1)vru>C7xqdn>`W;tzZ3F!px_Mw)hV10~o*|Cf6Yc zV4Q-pWdq17e-Tn*?Bm2FmZbm!tz`3{Q4o-+Bp>^C*oeCMwNuCBJWB-Ye;LAcOd=$X zR(}jh*zD##{!B^5ukFL`#eGoZ@mRKi+fUE|Kpe9DdH`5JH`!)4EUVnRUW@IOP|MNu z3rT^upt0Q^_>EJinvfWzYT`v{;%#&x2g4ptDB(}8v4U?oLa7BZGQHCJgL1FNl zRCkv>r<)d4yqbd|MKXLnsnTPX9j1;;=EnlMBJ+jPju{t*K8!nKj}a46j@{ei>ib~n z{;BcnPbO{|Xd`=Mj5^vY`UJ$vjx(0Ne(SiyeMuNGgD3X;6p%@eo+{?|SN8W6?h|B@ z539PcU;QT+_8#%hvFTGQsy!gzEpv9N%!x8SvZ?r_jTV`D=Fg&4O?Zfj&kuN&i6`60Z3*ZsG{SG*(Bg{jzlum!q0VTb7})z11@)1jkSb(| zE1hi}N4u`3fGpFbn7`_9q&SU+)tt>1hyN?*%)Ur8d>V~yTEs@VI&w%-x$U1SbH8)1vS)_P{2E>^c#*{m#|B2HYor>@zggrp~PDoO!tKih|GE%vMf znIr*{LLD@!`lH;g=RI}WGV6rgIyBt_M=(cC{&BroG=V-UX1?t2_Zx55Y<9b(p*UBe z>T9XT?s4ei)y!TGenHw|{Ws8^eFym`Xv?{L*olNG#0={?qA7_{XEV(S>zo!xTPm+M zF!RFtG30XPe#p)O<;^A#18vCxj-RPTKX_Nr>8xA~74(Z|t3}`7G3qt>2W1n%=i2LK z9$9F3o)_uvm2CnDlFXE7rlAOVRw)lx+*>Nv&hcc0f1aW1TkM|@%2NJfdNu}n_zlQ!`-=8G z8>_g@7eOT()16AP|NVB^?mSaAz)NX}TXcVm+PvR5N^Rc9GGX&Rr%?}T&>m@sC4B7D z^XD~$-7Wg3Z4`E_AYxhBv7x5J!jd2Y)FqqAH#%#0(AM(X<$M{&@3)Tlz4{(%1$!4h zGuvXU;mbmD76WH(4{8Z{>sS=x?1gep2*|A)k2CX- zQI%bmmJ@7S^T8TO%4$e+f0MgS1MG z%Hk#9U#@aka(zS-}-y1J*RU1gqNu2 zG)E&(akB*DRtgJI6w_1&Q7{1Zm*1S(1eI=9EsUgAik>c~>PHR*S1P)sjYcL|)u-u7 z#cw;?IMS~(ul@d#9F0$d=G4A9q}s?SX&+P4exSX9|86Of69e+v8#bJ=qtKJp-q^Nc z)0Xz-ZCf|3*u=ACJZpP%Q$u@KyS1qSLi}Q5JO8Uv;|5cTjTO#ofi27W_iq$l6h9=? zD4lWJl6KuEAb_a|7;{QC0?S9g{jg(Epm;kU^9)_kp7?5bU06S`;SL3lg64!0;K(Uq z6h+JaD(5?fayGWLf3h+2xg3uo!pL93azv0n#>zm7_I$>=hMs~^y~G^+@mdcSlP}V9 z=G+r}bv-JTA-bM{3FllROdpkD;x6_aGw&yy{-M=3aJyK@*Kahev*Z}moLH+m@MGxq zu|lL*a@d9(axr$z>?H);Vr%ai;$zV^Un=<4?c>nny{#iTq=Z9N_{^T1Cc@uC`is|p z{CRKhe~5PUu1or3t4L4hlA=Q&IHV6Pav5)gwCe$E@4E7at;N2P?^g`s#9t21&uksA zK(>r)A&(0uIxX?N=^32qF?Nmi;1Q~&IY(D(qZ@2K+})SIA;-CpJUM73QE4$C)cPO1 zx-?@5b_;J(>!6XIg3$0KauSSV=#?_`EddXyj91YT`^h}^G%ivU(qA9QX)gbZyeN0% zg%*u7bU^{aS+Qi>M%i`Qry1V*zS0aSt>E(T?IJpy`Gr*2J-+={eZ-6q$e(b=85w+B z#7!n2&wyn!_?XuE_J6RR|C`v_Igns}ZqFE&<{wVWqsn4y?xFp>MG;36!TK+7lVW<2 z7hSNJ^rM!KU4*6Nxxg)aKkXZtXof~b10 z-X8Rx7TroYD(AVHw)=`IadfS&e73ES-r_iecbbsW@C*1n-E6`L3Ue~c>01W*tr-%CU#oPWBEYO1;syP9JA?eB4$fuENZ zS&f~LPf@A5P~Bf%SggQieKj7&fRY3EGQmFC0XzL74fa(P{lK=@DD=7VPLEe9yb2i; zaI>CA+kn$%?PuBaN^B9F_6=|oO-ZQ-DaBOPujZ|k7AVUZgiPCMqZ#0>^r7fR*lrw8 z?md!`_K=mLI=`~8L`r?2O4ZT`)6pM}5*Lnpr-p-l{r|x2f1v7r&hS*0d-bWb zx=UeShHxvKtHplIU;8=LRaur0Sh-vJaZ2yjez4zO$^#ews>K&chv8B3dHjX$IqPMP zWa@60)_Wf1>n}g=W1vj}*HP3=i}ih{^oey&?6HQ!l=dW5 zdCa@Qzrx4#+1QVd?LVF@2ZxFMq#Fe#8*(syTr)~6vrL;OrAy_vzdohP{~!L^0U!C}f!?MbbMURN?bo{GXP8)sx)w$_Lkd~t|a44$ronINUr_u&l*qKr=x!G?P!D<3_swi^7 zoRSyUJytvV4J+=ezem zZ%bFMm~$u+Lia$0@g^y;JysYE#zLguJR8ky1`Zf2{iVD4;zwl<$8n+4=8GxpiyWLl z0wGtCnmHu2bOAP3By=s}3Q(+1>S#s|KWHZiY%RRSdAbQEvA|H92^UrC$jP`(yZy5*(WbX$K zB(HM$)~vXlb#4^?k&(GWfUSg91fn1a^plk?rxj+N6PBJ2GawZ)=tF9K{&Gg5j^9~f zUXcSh^Ow;V-%~Rx5AZ#NfcM?|!+vvazGUg}JpbJ(T22I8w_T>{@o$GBMb?~~fz6E7@-o)#H!C`w!|AoyhthfM97is!UsC5cJEz=Oo%7Od4;q&;-G!d6$YV4Qi+#*T zD2&D=C-{l}G1hRpD9dO(cQC=MM3*sP=9Ho}R-}Vf-DVrRGks13IL)gS9IbFBnqZ9a zh7V)W`TAf*r}gWf&XBuUH2$7e}@ z|9!L)Q1N?5AefAI8+voS_vC30H`Ace1;QfRM}#X8HhTP$BF=$`7u0bO?re?&6H@&|dHVo3JwEcKF?Q(wVY_GH{ z(N3pnJwEC1O>+cW4=YU83#RM~XejsWQ=CmlrMrCVZaM(dI^ALaT9Mls%RcM=p9&<) zY~n`B{_Q8<>N-cmK@x*)1@e^R;TNUHpNet(sVplu-mH*R*+*HbB&-=<%#Zci&$u?n zv9M*`3pCAvZ9E02X3|`GBb+(XGnBC*skV~|MK;N}gUi?S?7=e19_Ie^dt(7B|UXdqveaHS6Kh+EU z@tmcTR)$8|Cs6TZm4L7FCGeUuz7*h-GdiT#0A)IR*hM+4RZL*15Z(Z6yV>6xm>!I#!hKr)sJO9wn=5y z3Z;g$p=#MTQ`*%x^4*w0UH(C>T67;ElRDqUiPR;sCfdbZa>e;h(WA&2pLB*6`#T9` z&4CxG&gmuolI(OT4%A^H)hw>fXEbI7$D@o3pB;?*ob&2gt&#SCuAw4c=HX?i(;qK; z+eIGXs66eVCE#BgLU1SmwAX!5NEr?HKpy9SFUY2aHnWYY7aX}iMGh9HZ8lkyGdO=d z2pp`C^wJFA-1Q-#w4hw*X9Ql2S@lABX-m2EHh%|$Le{aFB=9017T(*A@sBV~YZg~yhInR1utp3wsv$6wt zf%A7G6qGfp2?Z6dD@KAmE;!o;vP#q$(%XEI?Oj?-a=sNZv6wqCm&xv8k#h2EAvw#e zSneMX?i3us)jd9Az269T`byuFCB|aE1Q8mn2Y)C;7w&{arC`9b9lJr5i{~86mlp!d z35z0ejQIV?W)Q=^n1_ua$V9U;$M0RE#lJU{8{@x$()BX^3swPA=uDqyJ#5;;!2yJy zc{%}f$dN?a!@nI2Su7S5$bZcNOMY~Nj|`YM)MK=CO8ICvJ(w}+(#4nGc+>^J?`_o{ ze)32`5k9KV*heysu`3|fX5|akV>0$|%lNf$(hIv$5V`*yE&^Cmwie3$&`$2nz+y^2 zyT`B1EzCKdZ|E5R_X1#)vhU&vWA#{xNG7 znwRETQN%KfytT>;G6IYBSr_$rLf1v)WuS+zrdZcF1$(5R=hui}h;&AY&Y>#`-n11<2+J(Uc3m%_Dq-x%o5( zdUsk^Bk5>oF>tGg@cR}k;5=*rWs4;n{iR#s**OJhhh_7I`ps!<+#*mp2rBWLv+|p# zKseG0-^?IVjTe+k;l_S$gv({1{W5{ndw_2y`FhTcEh^tJ%`?_ zeT0mf1J4U=a^2;~Uf*j%%xp+DYdSs6M$HRm&2n!~jZ-nY3ef?degL0#5JYLVeuKqm zR(=3+GUWQ8itl#w7nO~p$`P5HmH&1LBedp&Hg%8$e&Fl`AEfsXZw0bG27{=to?! z6U_&1#T6W zH|#u1)_7|xj8>+!>w9wAzDyCTUKhoq9$9rOAGDkkv_-;x00!Db6MYcbr_K9!WQ#_7 z;7(fNU~#70Qf)w&CQ#=pM*_`&Blp+LqDB9)#}<5#)lx%VT7VS|>`_b5~2&r`xLWBkz(RG?&oeJmH) znOf`~#DBTbqVPf9hbZinIjZbXU+IcK{0?;P+wxVghwfokIG$DM=l=+cBHXZokmrb? z)%Y=HO$)w2e9}d>PVNxyi4?N0Rogp6i)}$$U{Ru5AN(`0nHOyzaG8}) zaPs8-o!Y}=X#!!TbWBx34ZE}zJw8|z(c{puWACIsVJb*no@xBp`K0g>-(?~9y8w=7 z#$OSC!Y+%DfYp8&4uo`R51b01BI=@3b5*$V{DH?1&~yY7$McN;*!OxdL!t0q`+8+@ zWLdL>LS$DV>bno;fO2h^RYi1`~8q8?Y0;Q8wn7>n%|9^yxfMhlek&5|2lv`6tsiDm0p zT0m4qZte6${!c6baU*&x?T6CAX6p!kX|2aveU*s%gmg@fp#d0sF$)^3KhIzypM!x| zPrhnG&oIp2$N>+MA@{#r2Zk#gMYiW-xAETrzTo+bH;`gY+JjM?r`_6^CRu;jt(``= z@p&`w6vA(>96=KO7%YfYUPS2$Ptn%w6FKT5i=JFR3|xgj7R#IhU3YDb1fKV(FASRD z=cP%1X&0>?^cmO~_6o);(2iC@vDx0wJ=L1E2W5AFKs%Nm=)2j0?e{$O4+?J!n#yib zd|-wXq8CpTH#N|y0(|TZb*$xm#u3&B*C|vjw$?cpE!IlsVxiR_7ZBGHeyQv82J*D{ zBcRgtLKr805)>BcVXOUcbpZ+lLkjtI)bmL~w9{WkWFpU1zyA1?5kA5_#u1c}S>p2p z+p*5ZU5;!W5gN9nn9`-~>wd~t>1w%D2E7b)4(AlWef6BV zt~L>gG7gwJ-#RlZx1qGzQ4rbE<4Fu^jch?=RKY2D&$f?h3Sa)xZb+0hvB(vW$l1bk zu6*4#lBOKSfrG&Q`7dZ`u2QTt92RHiw+z0t+1PL0J_{IYI)yaFib8PR=P_pyb$P7K>RmXO6x1#cm`3zv*&*_Qg#oa;gtc~C zH_sGO#McRQmUiJd1v>5fki)L4EJrM7(XCnW#4Dqy?=OAdXz{Mp9`2>X#e^1^uR;qc zmmZqGv`wGIg7#H8E2&i4pwA*qL9oDn9qw8pu^*pz1%8bR@8mLTP>KC(hytnbtcx?{ z1{?`}1GR89cD%M=tw>MD8(_TLIEMXyxB?RnU;SRmM$x&rLd&eBj1BC}m-Se3OleJ= z3O|e_lSs#tbn24ndcykEc zQJGNAphc9ag?6*T!V18TXPs|ykw{a7=+t;lZSp9rrJTqd-0Rr47%Qh7-T853^9c5C z(86Jy?a2i|>|$hc+@H^3IGy%R<_Zr(#?om0^fG4nOd=+%ta-Hgn`vhXt|kOW^sYB~ zWPH+6PjA5678>q1Hu#ACN|bjeA*1|xHep`R+T<1}&hH5?=2@P$;Ll*oM{rzrL!{!A z%#zEwA^=^Sq$Oo#r#%5J$Ql)7{-T6OjLL-d9z~&L+~3NCy%J)U35~u(eRnwCn&op{ ze=Dhka79nIuZS`mxw9s+MaP{x`%NB_7mG^yF&`CP7p2 zoL|HXeD-)QnRojL*;|7E_#?k=L-eRE_>0gElhZv}`uerpv8ClI5{Q^J^LEZu3iQOU za26E(3yX}Ed*6?286h58V`w1pbECp?2VkECT+-DOa6Zq#Jh(xxxC9$p03rFrV|FWO zv21Gagq{O6^+rv-y$dDbi?sCm)^+#?L!}8MpBCLiMHglTX6z~v9rTA4?1Hd9d3gKeUXs^@Xf1B<3YM((;!3+IdNGvRwZS>?Rxe zKi9#gJ_I+?z>4+OlrEU+Yo|jfKLP9^ZNr_ z#@B)?w#9#bK^fMvYEFXjW zD9IPOA;9jegt~tx`Ih82^k3heD3FdbiTRKnW~{?&zki^D_FeOmykPvkBI`U`5##|ieEWAIIHS_Udmdu zH5_j)n@wA<;J7pA?$Vn!nS-e$M#+kJMSRE+L621)Kj9JG+cx{$)cgcYIn7dm!WS4@ zT?mXd)yA{~4K_eE@M*hhLsy+s^Ul?nZJ}fR=Uq1>bh^-f|8*u3POf!PkN#G+e;G_VOg2UR@TJ5(4*aHnj+)4TO^KrgGBnO0H zRPo7Vy?&_V>5??4MfcK&ENpG$*La`z1WPU-I*e{2TRfNpwx)Ro^LX+$Uw3s8OE zn!-(Pii>=Fk$U3lKc$8r-U4nX9LO0!+T%Tv?mNNaTJn^}S;vY$tMb|NE5~7XG^sbI zZRnqrBZ)K*->xv#zZbuY)-KQ~cn%}d1g#IzG0k=h5I>Y>=ui=N()rVLVF$T!@G8|V zaEhq>WL1qOPIHT2E5%Rb#vL~!-35y93-i0|y=qaRmfo`DyF6R>Zg5r>?1{Wc&0GG2 zBH9p8-sP!)vYKB3rDp(bH>frM_sR)*($_zodjk#OAqip^baKxSfl6XQl9^z%sSlIN zq%cGI6aGajGKx98V?{$f`?LE@j%$x?m{Ta_e#SGIuW39}-;$SykGc=fjS>%z`MiV5^yg|YfYfQgvTn$?hG_zLR_fF#nh2}$YsarhKH2AQj8C8}9_+hcjAfMd$}*s`CHrpSVzFY! zuT>xG6nkIEhtVoq0r||3yPL|wdFGT7@08Je@Xs7jyS8u zniBi<5nkX@l^dLu5<0?@9MOlLLq}HO-5WZ`oSrAApJk$AGs{_*V(bV$LQq7bm7O_i zs)gC#(L|8hD(#}r1+#$?(D@*yF?|S&4aE*$kgchFdn*FLWxSuaU1`|Nl&I1!W6F^3 zDT8vt=ZZfF8knzi{VDzHhqt>ZS@1D0BuUu8f9mObJdNBu#ADwFTp*EKzLG>fTIRRg zeP&s{@t(I)POe$4O?{7bWc7LLWm@@uZ;!U%WkGOrnVNz4mAw+`{yC2%H|}0Ggzrrb zUr0tAl#*>uFOihH=_R`NU}zEr1UKEwg|w!Zc&Cq^yIFgED(F0>dwFqam9^+bTA5yw zT&3!B6mxO9feakY9ZN%*jcjxqSm~hjcDI!#cYKOU<&)RQbeJUtW=oF^PNbu|TJ$Uv=p5L3zl*xA-WrO{! z@8|29AJS}R3&M$3;%bTKb_urIfmN~%?OT`_nP)4)V3M0t@@QPZoR$ab^XU#*8lJKE zbeW62jk2B?zSP&#Cd|Gl=g3IMhonaM>T?E3+KL|8 zHz15Da~WGU+wn*(Iq`|irsdZT6~;+*h0xDv%_aCC~ls zZ-1-M{?Sn0V2#9>^PBe#@p+qlT1B&p)@pjBqs#j4gW@r)V3Q}u68%&%-h%P#ONuXy z4|$8oF-I35^Izq{fxm7?FUG!cpMZex4phGQT#}-;%VC+uu2;rMm028n#KA8It-lk0 z4SKhu$|a`uErp+M=z!UVkbQT!YsyinM=X9-yjQQk8sn-R-Dptk;FO7 zY`|Df=7!g&UASCdx3m7jURnsRmlZWNie5lcz=41l7H$G*Mj=V|p)6=-IKF(^K z{jq})aCGMg`#Hv{{G^neNU058&z=bS^vEY3+Af2tQ(9=bf1RzLJl~A0{picb-GbhqSucX;qqB<%o~*ne9ro*(>z;4SD^n z@r8$>!mP3=4h;FsdgqiyEi-TIp%Xi2~h$t@W7rs(loco5@zfla23v@UdpBjNa zq*dP%Mbj>Q*c+q|g-1w3=0ycs^!OE?rh(%)H&YUdQzVN#K(axY&Wt)#TjElLF^&tP zN1ai7zHHgkVkhyWVpgxi5ymb~nYNxpk6s+lxxk_7yUbx* z$WzJ*Ydml&P1^VKhx1z_pOWs;>*x}H{aA96vYRgSj4Ssp*CKI>0IARyIZ1XGfV<5x zS#(E74hW%Ex2kh14J2Pv_~1-3yOgfMLwS65wtcpU_51RYulFCMm!=OH84a$E+*`~%{D|2wXAj{R_ll+rv3Fh_Q5KgD%DS6t`NST!b$y7^ zWwkrzA>rgcS|DQSKSDbEtMwWCIX||1$y;wa|9pIDUBvH*tP1b)(COlmp5h4L5iBe~ zI>C{o%J&Qi=lhzn#>hfrAAh%0#BcPJ@7*kc@`jxQg7HbesPOa#OUcO_$JfA6E`#nG zgt=V7d9#052(IRy9yF|g5~99RRxL2d{tN?D%p!tpD>8$|Dm-6U6Mx84Zzm~U)C%Q^ zasNGrMGIb90IJd^WA+ekPuts^pao}Nn2>+{Biw>N5lPWCT&Lxcpa>5HB>0*FS!a~T z!yXYC#mVUo{~SgRh5ko5-Fsl4znNg|iN7&OBT70KvMm(eMwtxx`N91u!IN4P|Va@2gp?xi#_6Hb95IODNzR+XLi z`rdZ?5h|qU1M$rq$($Hs%4Bkd7Q31!88((S{|7wKXOZ;i&;iC!x#u%$9HUQ(kx8nr zG6a6wl-A~pJaNaL);DJoILs(CZ#!IX%lQ|Ojy;*dJM&Uud;}?~Oe_I%!CjQF<7xo4 zGG2GTWTX?foXAz=o`Ns1-}oK~@3faME2Mm#lxeIm&t* z4_;27Zf31b$o_5WK?3Obfu7{?E}iuEtRT+N+4vvIUe0jETzgr$9|Zdvtw_}&)Q3|- zn6gu;tG@lSf}gQ;YaPQ1;KIYaPs1ASvF6bxt2^E5^K8fm9M^p7G^|wom$BN*mEG0G zbV)6@yO{u&&QtCGTNYP17Wy7gja<=Qo?et(FZ*3CcRY+@birfy(eGzE=S zN*d@;u+N*AH_K;UmhUf3km@!+2hmm9iqiwW=d)W&@FsWNbBE#*<#T!>l7W7J?0agt zV*`zVx4n%@GDM%}bzJW?E*U~1Q)ze8z;KDZPWox~Dfh+K?UPo{pqQ%uUq(yyZjS1Y zwNWmzrHqdpr<}ESWlc}b7bHfPg%m}E4n$+@S6VarDs`Zz`9t^>JA_XwED@WMgIneM zN*?WX7FFK2;xq({gvQArLhm~=cil}*!h+{l^6zf;6c^m!AMmZbVw2H>Ko-GRmiP9FIw`GaUf)jt#rgDN> zJH%kcWLfVLJP1z2dLPm-S8T7ywcl%2m5t?DEX@ zZ|A%o)>>F_@tc$LH@F3($a*~q`P?;0SiH8k zmlVtjw%4#fu+eG)k)jw*Dqs&O9ZyT2>(e|rAHwF_4Px&npIoTw5HV=9c0;gIXXh~) zb=-Kvm*Kl-Xu2h7FAb={AECIrc-(ZR_lD$^uT-agcN;!gI#mM*V{F#QH1^N zn!fQJ?T+ur{^N7BhZ8rG{q~`3MHE!tceCO%@z#Z!D9RGv!0_RH19mmpDsiX*nZR zGNpf8!j|%S6x#)4;%6YdReTB=Nb%&`%o;@Me!Ii|w!_+f?4cB0$ZXn!)6e_xw-$;{ zJ}r&w^j+E`0@XN^f+q1tl;~(K5kOOhC@G(s&r07FzO;^Z$cRuAnc6FiR$@4qJK;gf zp-9p%0f#Sqk^M($4?fCWg|@Wg6|oX3#Nil_BkOn=F6`syQ?LQJ#CXRS;mnh|j|A7r z(;a=_ef!SA=IngLNxd9viqlXJ8{Oe4Z?JO^l3H{p<0r}y>CiZ1f$yJkYhIEcTQPSa zJ0p!t@);qEO)s;R=B`E+{b)q2?dD$ zlxeXSxJv7%DIA9ivvH4Pi>#PoeODeR>*Nfic6R7gMScX0Yw4h`o*eevk8XqU@Fv~+ z|FQS(@ljP*!+$1BAVBaW8Z;_M(AW~i$_TYYL2_UQ&*(()j<;%!_14-V%qS{^#7Q)V zaS&VWgFarc)oQhU1g#jrOD2INfMS4(APNC*XBdzm2q8q~{jPn^nWCp)dY`Mn_aTko zqzf5y_P`+-nRK?Uy}x?L7}+og|>3GoL=}L`v>Vh?fsp;qK(>|?b08G8wLML z#AxAJhxEM2lD2%1&l{_rt@R#wlnz(jS7{%XSxG7z?@GQBd!+aUw93I#O3rvt!ReBq zzV6nklPo!_$?N)!Oi>tqR$QDZZMG*2gg*U79hLD@FwV~TU*xLMEQR7;iURK`Nm4v1 zr$`ls+wW2E$4!`#uBK0ETfCf!UCBR6KKkM-63>yjUX5F5x@?*~08qNBVILnrei=aV z@3?X3jC9&#dzpRX2YJ~IUw;&M7j(iCcDt7+Iyml8*=>B;BI09fc@>ZGBYJPUSYa&j z{}G^Fqx~>{`idPjf^zjO+kLQ~9-{NeyqkHNF`!lg>VbF=J!nVbuuT22*`SUy-0 zvi%ZGa7hc6*~+K$7?iKggaI{IHu^pz6;>n|gusb?vR2?iRYVuBRUYKgh=x8heNP0U zXWjKpI#}O=i|4$=dH5S|h=lgarbR|ksI4rUt*K`AJVLh{r44c#9Am%??Ukc?WXDN+ zZ>0c~^=0_L>7hDxgbzmkGp=a}p68;U`)ztmfm zhN(ibMd%-U5Nk3GPyEU5$ME(MMoCZb%sm2z!N`0bdHs4Ll4{Qp_0Amfhv{>;(KUH9eSwv^#;*CV-JN5?FE42 z4zt>=au+#Xdz+!jc`iBFYjBgHEn18Ii9HgwM0~a310k(4KuR`9VKjBtV=$WdY?wtC z1xS5#rRSnnOWo8$ZEaSRY$)g6AH6rzF8X-D_)CwG(u2oKnH-%%i#Zc?jTB6gD-q4g1`zusm2@;AEwjn(te9?ZK^a7lV+E8V`pv7ElT$EX2*1{}Mz)99+(WZJ8i$@(_(U^il_ z+jjQ5iQxdPXHm`DDz+!bVFVjr!(5EP%%MhKiwr!dM>>N=miDlS4Aq=>9WAMq&as!y zr+xueRS(6VWvEJ4kldN)3BYyhaW6rC;~~-=-qu{Ox(U;%lKGN))6DtSomjy!m?}XX zG!Sk82j9fcJ3`jisaDUdmk?<+@xkFmh>>>BbPvP96JkJF^(b(iJ}IV8;&>B^sYg}N zc@LqB)>A&+!7Cx`hh;cO9z_fCo0* zSl>0e*svvM(SzQ;E5v>XTbm;KZ6Oe_6)XSTSH5XxIX1D?w_)g#kyQ?nur_ndhfb&Z zX^vr#?9pK|@noHzxyBZ9ynUGl#Ax5PlThP4I`GtO>8#J`zW8(0$L3p3uS@sok={Le z+U{h8mRf7h7BamqYZgVZ(xkrt!l|YjbabS2Vgc$f73ZldpXt+V7X~ zRZ>nf-_vVE#5R})t@#s0OuBJyAfhs(hss1L_a4(%tMn@7tkR>uq6l?>;{j^2zn&j4 zkOjx!%^$r4n-;~|Z+B?HZ>}a6c6ae%P90C=nxYc23Csb`r$a1-QlF4$<4LX6Aw=oj z5<=cYGX_AaB~|+Z91u;^eVK|10n5QmBFEI6Ptj!Lo=M^9&pXHYTWvA|nAGwSK$O}E zcCRd6*maMeMok?GduK~J4rtc%a1u3grA=abn3_TclN49>nsjOk@6mkC@yo#@-|e}^ z=Cb=KPLX?j4CR?v+vXCXdRQD*RK?|l=Lc07KaviX zIPS5!?}y#+*xGR$cT$7e&rWALNp7s&xb?HaG8=AbDgV+JJeH`f*f@0$XhnQf0w;EV zlLG8q9ecD9VzP-%e#+z#?h4ph#OB4!kx3k$?1W(MkA+^-Sa}niiDlagtT$s1^p=;w zyLl!AsvVdTH!Qios`YbUD^Xk}W|^FoCc&cE2(t3cn9cY5uF;;b15r{^=E_uvXChB# zON2NT@o&Qe148{R-HTMLf&}rcgm2j~Rw~$(bZ^q(`1)KXksagyak5}@t zwx}P_F~O;GRc8`tVV8jh98TC<$YJy9y6jw2Ujd= zZy^%v`eJwd07Z7nBZuub+x9p(hfU4(n;-hIz`iF}dsLRVtmKX8b$Nm4ukv7grR)8% zZRr<9#~fGU+7{{Ki=<<1%q+ftHzxeV^+L}&^*TaNp%Y{y8DD^u|EeBw>5*))#AcV+ z%`ReNz}1SeHmxZ{8UAg)kW-;JlwfVuAtuJ*t*$`PN7EX7k$xioRlY=J0r!mhwm4m61&Ldd|jc zK#UZ9c+NqPqJj-CJKUtYI8EXb~43SC-FxJy$Aj)b~MpAS&!CoC7zcaDPn4f_@-m>$WfT) zRm~;lN2c!s!;U`2q6cS}s%pt(`dZAkaLY%!>5^+7<%B49OXfjNP{t)is~W+RtfQxJ z^+pPn`Ilz}1|Iok$EM^{=rbnAbmrDRlh74!!wwt=xwR9c?h#<if$x??o0M8kW{);0u54fTH=%`R@3Bs03TxoNy5!;q8$FZ7KcR(r%=824l8xzFmm>C?U985ZS++_99-tfg$=h8 z6oY8=Es*EJI`gV|_PFu7Zd@SJWuxy=`4X34QPMx2ec?8D=vL%4ajR<4m2`wv@>v_w zVcw!5XE85S+kG(~-^cW7!<8PWE|6-b005Z28PNKP0FVc(iPUJ^A+969a^gvL<ouw$%f z+mA9q`%|r16{Ig!Y8J&4S*%Lx%E|qtgJckkt28de>O(KBDjzVB5|)2+U39z4teQf0 zWr|QmJi{98(mDj<&V>Q%s19o^;us=-xg+w!73ND6j4aXZ`kI2LM@pL1{uqqZ9}9nz z$xF>KZ<94D~L~=lJ9|NkUEf`m$_%NsuG=+)Eb&o zR0`t@9?Qe&7p_ldhB>=Md*rSGGS_4aNCpIMijxP7mybv%*dH_tom=_v#Nu9d{D(T> z@F%FEYS5iS+y@~v8FgzReEezvKWGj9%reT)?5oNikOxG3(3^-gGasLWRWhG4LYeYJ zd^uxHI5whM<3*i4*w&-+ms-B?v1H30EZ2nB;oofjL@&kBtfMHVMc<|a7~+uNuC+1) zbH7RoN&&qH_k{b3VMXI#Xwd0oKl%E+3r6h2xN~lZ-eTS8#neHBq%%P9>=k4zpa?QT@Nt z*$%n!1F2^?){B-{!$cI0-1q@%z?#D-LaY35fHwL*5ZDl*jD|;rwhZ8QfrnzlyqoQ$131esOf_tzXK!++)zng*3oz(q&pke%` z#gC;B^4kncL6k7eaBin|vZ#9|>*%$#`3)qh0ySul%Jzs68MqYUAX>r)n8cX`Wy#L1 z6Qc%m0W~4^1VA5qNk(UtgbD|L17BOGX!l8ByIQ!3w=9@YVSAEhhN(2VOkB$#6vg_t%Z{rMS$ytW4Ye9Ph3JF z%LqvgkJF_5qYe+KE2FQSLPWZ=W6T|}54>Uqq}vr|HaU(;J3ia!lVx@^zk+i`W>$*@ z{z-g|%zVXH_`M#vvcRoJeJ&jQiH}(rmq1k!7KxFP4N?7vaLW(Oq&%8!k(o7x%}6@o z11|0PSXEM_rRVD^*90@g%>P&PN@V6dmu~?~;ZYZ2(GLWJQd6ea^p!)6uUP*C8xDOz zim#Bc9H%`te#%aP^)gSMpcj2;HsPqeywEqVFh&W4UNTDndDWxL>A_*J=xTU#5LF-3 zy&NCQ7Z9z$R}B@8bmJ??DNebRSxlMolG#%^8yifBoKS_Q?!DaU@9-HKSfJuN&EqU1 zw;uj-h}YFZaDon^nV>JpSJMZomRBgH*?Rp{DYOGs3k|rD$(c~Q3)myABk6Gvf=V=- zMDmqVBPErTm#%BiH^A4b<_qQ>nxkl6C1TGrst(X$=+^*%Y1Z<=iim_!Fo>+% zPDAFUS19KKC|t-815>y~{CA8R2d@#|2deF$=h7xKDwBoTWR}#JB_G5;W?oQ4Od`n* z@rvqU{|12}#;vLOQ+iNhjBqgWP0$SVGgnEt%tF-wuDpRZOo-+VXM5*ls2$XZ*wAb} zK?hJnx=Zka-2a0@c@y0P+nFCQXUReQrAMeKo(Mz| zoif5&PixU&qEXteo6D>d=yJLWZx|uXLJ&_<82dcyA9lidrtcN2LWGd3USa;n6SB$$ z2}%PaX?!Cvmzr1)g7Ok#S_x~+PG{@9Bzg<# zATg=;N~2a-c@!k)30H1{vC4XJfOyrwoOWA3oFt`&=#O8|k6!}ov96cI(qYTvE-H>< zp1RYe3#6y4o%yO;o9WgCw9Om~sX!84ctew4QiF6MM8Ik0R+egHH7#JOsgJ0sgpAMC z>O&itv#W$4gz&4rp-+JX{n?3#G9>aEn{e}C*EJ5Ytj70BwTnun3bkI5MyN2?(oHIm zKD~ry-DRDHRUupTBYgNYc#D4BF@uKf_UuFK5y9eb;3G02H+%po>vQg9GvKju8I=?A zq~}81a#eA9Vl8eo#B)o`y?&M>diez-f_u8@mvQu!{g?raQ(-9#c5Tj|$&N&bv6RFM zGUoZTcWa%-H3fC1h2bjk8+b*$ z5XG+~k_{M*%zQMeCyN@jM~|T>%uU#~rd{UsGGrLEj08s{gLlRsB$LA$;%})vi0o~$ zMyP|b=fez`?Y?t&NTjQaBq{@o{<;wJH;8@>CI-xmG8-mBk(^A!flrTAt1mYYy;|n3?|8CjsOk!C z?SO5}^FbbrNJersYXm#WEYQSbQ^}b&15*{33d?d6v5yd)!|ipIc1Baw7*TypBs3SA zkd`oYQ(g7d)^FLdA^>>$UvOxVRwZ=RKcrr!T%PJg2(%~WAA=Ub?^+5JkUy&zF-QlE zk&=!`sHSLlXbG_uWlej6OgKb_sQj5~Pbb?InJ>NpsSI`y??XRJk0b^N-u*@EwaUln z5(uv(dT){)U2j2hOi}P_NW~fYdUfx3F0xVQK#mHinUA99@IA^XDQsuHcFkO%yVkMs zYtHO&eWIHmn=|LdMdfQ#pq%5NC=f0uMA)n`JG@Nx*1;2HaLV9-t5`GhO+C>gamvK&$qO=S*ajrj|wsRm{(sZQcD zkWxt}G2Uec0_S3qF0+p8;AGNJrW$F0ykf6d9pPv;Sl&Q^7q{%OL|;zt|MQ`k4pfy%_Dn;}$T|BWm*JY0mdN zL8=+=BFIAR1LUgL&{y)dN&MpLWKH%zygs_nX*R{DF#{6DQ_TsBF}PDP1yqF2Wj$gF zJbAV=m7|ig${_`r%4BZY4~ZhkgGx33C|M-FknPPQOm|UXZnTUBI!$%jC?W1tZ;1?X zNIH!VaS8k;ka7y6+-8Gg3(BV_nUBcY{WmpsvVYwydS+VDaRmau%1E=NuCFngTIM2h`HQ_;(1=YiiSll&V%@? z#xmHEIUf5SE=GSja#DP?!#Wk{pn$$2PsqvK#WLd(2i>YmUnHg6*kARA^de!@NTKmx zf~-(KeP1n|v=;CVjVMREuA*e?9`~nPSl8FauK`#Oo^%0Z;HeEin3smcVfRk_4BmC$ z{^+S64)3t_^8pTSR_ghGF(B`-+AzQ}B4h7qOox(3l+PNGrd9qEK7n|7htVhoVUG_96?ZVr(AdQu`Ptq#4068UrC`m?+=735F>ci4a>~#F54^ft#?bE2B ztmG0gE~Y5O?u|UK5qqvCvU+1z&?Y}&QPgzC zQu~gjw*WF=j^qAjvyZj0kV>h2ruYJevooL3V&>MY-XgBN&g;=xy@T5wOM2!99U(x- zdyk_R(iUBePP^V!K1O2EdM8m0CMn5&u+!IN;&!+1et%D>1AS z9)jV!Ei7y+mf9u&!pxx3`Ju;>sP`KTQwWsUmHL~GQSchZtWAD>j?@@l5_UHlH z!O~E4OB~E`IUj842}L0R`R?VbqIVWsrzv7qG%QF^`!H9l8w9~m z%~QcE@d6Jxqs98&PZ{Gy-BK1hZ^6uY82qhb)t1Brla%azrNFK~1~( zk6B;1s%VS$*nO&kSEA`|hk2YW^=`-h?Z0R+X5pdyqAj68Dhk?M-Vl^Q;;yD4pUARr z9;xNIg*scWolaLyq9})D%%nK;AfF4@VY>VeX8b~lE~Q3hd^<>li(Kte%TL8Xm zsr^Oz>J2(OMK7uRbI33KhmE*sE92)gLCLep>7fS-4^s7Gk$cPrRP<*u{#AX&kSfhw zxvnMFo`GszKh67OT5y2OoB=BQ9)Cn*l1e?ot?R}PWun`Iy(^PmZ*-dS_SsE(*~+Vm z0het&uen6D;)8m1C|oA!A}vn{b4h_GOr zV(q1IT%yJ)uxI+Fn7%1&k_z*Eg)9`|FTF3<>idLjm^B*F;yh(L>J`!`x-WNDUih0K z!E@M3T+pHDtgu~$mMa_LtTPT+&yh6DlDKQ6%b5vFhfUfD!qRwE&Mf-!CkyoC_20mZ_o&)G}*)u_b9#b!dyzm+0dtU#Ny|w zZ5&Rv67t+BWzABhb4ZrR_`)vZck@Qfuv$sW9H4e{;nwkCPy$=5a0i){?di(iH5YpL z(L5$ue1PBpF6sHbK#l*Fdeec@^`Eg~!L|M@(4a?h3znWrHF3LuJ68RIg3v)Iq3<^oGP>(5mGJ?K9z{w#M6K}kK{rykuNm#`#M zL=oRa@wQlWRm%G$I=sLry_WbN|KgN(J=T%oE&5{CP`zeQY@sNAxuH=oFNZ9-} z5WO?6r1Z;@=nc=NT^tR*gyZIr;4R+BG4JP-oOpQAiSEKr^mXwPj#3Xl%sV`yWgiAT z-2oV?GFw>JVy+>gnK`k8P`Vv<;;Ekp3cuiRm}gNP82EO`mxYG5_iNllX>-*!K5%CnXu zrl#g7IY0^z*X7HZQ^$EDB54J8$U|=e$)>sL%x1^RhG1gxC9DY-%Th)~US@B$vC8ez z3)e_JeNlIgXnDNVZiK@0%G%IQvcyytR!(U(zv4%wwefr8^z*vX>;G%|9`-*y>?6WE z3~{V04n)RQz9WHhN+#(d?&4y{kx-ml1Q&_)GV9Vq(G4#l~g zM803|R!Q>Y#rwBAJRxQmOn&R%GMCso%=)>*#+9Ow! zq39!Rj&M$+XwS6Y;ZD?N)*bqLvf0f!WgU^@aLn)(V*22-bj7^%*w^U+^Tt*jSbT-w zb;?T+B!(Dk#JC2hC?Z>$yZd4@F$tPG_wF53)*h_&Khqe3Wd0^f=K>Cj>)`bIgcqX?fYS z(IXQ(pywRU)|)H*0oCsgH~lxDr0A>Aw|b+yfQqEmWT-YAc5a~PG;y2&znQa6iyRl* z#->k;ruS|3n!TLX$9t(UYSS|foAyoP1Vt>2uW-U`A9j==w7lq%jOeru=d*c$K9>~( zNGxy9zfak>$f8RS$%}jU2mw7UZ`9gga%c|sz2r+(fN7g#y__Rei=ox2Zd_5~m%<@s z97>zja!D$;IG?61;UCfC&^Gjw3AJetje@<#i}=Cc_dN`qf+tFqB{}3VbCO{a<nIhfI2WaUh(nwPuT8jJ zx6M_;ZgO2Dqm-0<3Vy2+i$7vF^SRhiN)`o9N)(v!w>GAqd%(=&5G3LLGBGb-&+Hc-J4EVjM6ysm4&tvrQOa$jPm%Yd19Aj=>IGe& z6_>6jUSiL97Lof20wR9yOips5Nm_){V+|q!u%0vJ7BeU&9XS}i=%ZQN{N`t}e>bq` z!K|{=jnYOq7q3hXAvGVwq_BnJQsEpNdcjp0^^GO|2Yz#zAbbO=9siQZ}T?zYa=r7 z_&3Q&?JzCF6{^+Pmnd>OMRXhW>N``LHf@Q7imS#PKV5%~NV|gXfoANG=j#_wW zbogr}MZ2}I@J^(=5{Wk46=}Gn=wm2aWmo*y&?d0$!qDqC*B@Snk?HPfm--?(!ezx& zBB4tE6eSDim*RC*BsvbUhsE5sF5qelxN3=?3I7$Zoj}p{sh`R?7DztR>+S&D)P+@> zX7!cxOR?+;_Gj+Flb0zr*lOMc0k^46?H+rwbAC9C-qBWbTJ1W{=wn$(+hPaP{pQ}_ z6)@IYW(Wx(PHf~oFYSHDH3x&|8j)WJ)q4$dzeI1{VW0A3d4x_GAAfU%_zyV9#f2oBx2dT*f}f zaH!&f=Qvu_MEzXZ*o_YS8jYdou;xW_AF@tVM4{?cHAt~?_$)rCim%({PgLcP{r!Wg z$-yDvvFj?SgH|O@9@OIyPsxEBzI40d-_c4t(`76YZDI?aVrx3@VXiUEvBLxm3Qwbv z&2;E|q0yL;%{%q*a5r}MWBRu_AG%|6eZ-Gz&w36d$&DS#kRwc7d%V$7Y=4)P<#x$$ zjy>=)^pY_eA?s?v|6eG}h)&NVzD}-zB+5R3#AR(IsHgS9KvCiNa)~a5xw!jbPNEuO z`=Q#Bt6$P0v#R+h(i;g?2v^otA|I^ji!`HmM6T{ww>?nQFm*GA?*3>A!@=qbyxpXN zAa)D99W!(LV4&SgH$U^4w@VOk>sZhiP^2o;vF-e<6FkB0XVza0)7HrE)V+xnUG0_g z=DZPqu3i`m{UW8GV(jE$%#1ku@s>|s&8Qs!*M%152t8$F!mB;5L@Wq#MwD5(J#3?Is zUeV}aTs-a5ruG+J1C4AJYlurStsyL!u|!Zk^fd|0=`emmqDOxRr}((OJiMRC0!?~ho7YSaC;OF6kKXjXpM~8dJ#u*) z27s3qVq??9@Z)ErkbP|3w}{5A>$dr$7qwv~+B!}h2v)Re8lhY-+AC`Pb#ZUsmDq%f zHEb;;Et4v)>EUGm(6s>T%+w>vV)Th=e1%&T9$05}CX&kFwlTgAnn=Qpwdfs}J{XU^3VH!_R71?EOmA!8~ zJFs|<#dCG>8`200+N4)B$swpb!`FNor;nK{nR9~FoiixksTC|)qRBWx;n-)cV)>)5 z`-1o0z8k=g$$=l3C@NV#ynz+>MT5|&FeQdA<%|@)!a4`q)ZPuu&W*KXc+KA7-9rkS zSod*cvh1sNN}%v>&k6-a&b(Lw3_*TW&j+HMyck?KAzGRKp(wU`*Zf=%Tv+=fFsb>Z zNzO~u79CriUAZ=xqb)+6BK|y>{PH5StB1Bj{6RWrP@7k?VVh}wg8v5r(C}xBwXtcj z%D8iF(VQo>fNT$p?2MCsFBzBYLqJJW}Ppll>|D6tmir|tP@yf$yz{E3xL7Mvr{Lnto{$xxg4Q0g0qxFom{al_vuyv^kIz0pbe zs6kHBgR76`;hqT{c8Y5YG z*>=&NavWW@xkf31eT2nX7uVNq^%boQ{VTD`)()q%jdR6vP>2F}xrq~iBZC29)X(A6 zMa|PP%15V#@Jg=j92F{kv!p*pr5Cg^4+Z<*Ha=^;daUo@_DjKoQB*%w z6SI{x>+kmCy(h4oC!&n3`B<&J_bIvpyMI<#5>-H078`F&O|drjowX9Pja8J@05`3; zI4`YS=3~iQ|D*Ec9MW#(jX7d@-*%Q)QJR;Wg&n{O>sU!ySZ~A*y6@bi3cOerPqHYz zonjrUfS%=HJuBwq7u}}aTiZAxpMjLra(Zbw6A1FUHaOBchK#V@pns3{`%EpTKbJ|_ zS`GoLiu270`SgX|iY|h%Uc+RmF%1i*v>N$IB}mba72$g%EzywDPh2escLbYA#!kc- zHDU+ij?Z9SWfV0_T*U8Cp#X}-s;!AY(iz}lH!?Xeyb)nGIO(3Kq?^#D#& zN~-E)d_NxV<|=D5#sLszG}q6}0L=F|nvo~4|P8AvLS?g@X8Jw9nLRw?UiBZXc_3K4L8tj9; zFD&LQ>p`m2n1)?Snre;>x{IGU^SP~eAuybp~myy2Ojv zn-4EYyx5iB&u)g)Q;g8%{0()j?CNh&8ax)eKMd-OMqO!AwH#Ny>IZa)MPG-QfXLb>JkxO9`#T9!{wJQ$4~~wM6l2RbB02EmwQ5vd z7U1L`l!K%FY*lELD@bOTGYazc#j?x579fLBJaaKMFIE^#4qT;j+WHmc+6hq>UoV43 zjqixBnDOt&@Z>hLPipXY`;OndnWI{$Ue2w)>Ib_p_(4aiGy?{apNNS3tExlk5+_cG zCzZrz9m#=XRCPj6TBX#u8(&B~OBM8LR}G||Ow8>Zf8EwQO6D)7F3@NdLDhVR;1rl; zt`=4S)s~pctd9k~=5lK}S31yZ{A?-y@1K@zV)tzSWkT;H0>S(Ycv^ zxILv^CK~=4vQiYGDPbeht1SP8o7~_OXkSsNVjTd9F6VlkbG^v9p66W8aIPmg*M82m{R5|b z=lZF0UFlqxIM-L5>(kD4wsU>Jx!&bmuXC;!IoI=?>lx1VBanD8o$mNG^OCDH|D?M);5s z`ivRD-2ZMlHFr|)>gA;No^RO6&kqpnKQsAZ=yRi@LF#H$96|+}7FrGx*bl$yM*W6v z(*4}ISD+7MeX}CmHqNU}tPQsnYk#OEil-4BRHyw>?gEkH0z8n8LzK%1KZ%h=q*vms zCB;;PJ1>f@HAGfpY2YW)abMhXT)Yk-0Eu0jf1MTRO9^`B_4O%PTcNmO$14CJ#t&%4 zkSW~q{@8L}1dpweh)fc)kEv3tI-5p#&4@&$HX{ABYihL|Z^6y-Q*0&A+|M@LMF^9u zDf|fO-^vRfMzbfOR~)DXUg(#k$hQ9Fd?_~eLm%D(ChCkS5BEZ&6^Q=4@mX5(E+x3q zTrRW+XDxb$7udDA>=*CzMgFB3?>Vm^i;Tzr8>QnBywd3%$hcq zdH(mQg!)ec9Hnd8#A)GuyNYQpfPSQ&R3jw+Plaj+Bv_sRCC5nCrShGi@;R-Oe3BYR zEB4E6oL?%-k;tt`q>&i~28Xnjm>(NUB6B}Df7Wf!%@26C`aM5be>ekNFL`6ytAWYZ z1B?8g<+4dOQ@woep-bau|6*4|z|+E-pG{Be*XsSC->=*K(iO=o10MQddBB569Jel# zPY5oP4G$q(f(4Vns3L^(j3tB5x?^+uPru3zc)m6~7=rD#1}Q*4#J+yBuKMZ)hNn@a zkUk2;jDkBH5H~ArFPmPN_L&3(Rq%}HjDkr4Q|vFMO_I@fvtj!C3`q<*R4s0mISKiWO