├── .gitattributes ├── .gitignore ├── FastVideoDS.sln ├── FastVideoDSEncoder ├── Adpcm.cs ├── FFMpegDecoder.cs ├── FastVideoDSEncoder.csproj ├── FvEncoder.cs ├── Program.cs ├── Properties │ └── launchSettings.json ├── SpanExtensions.cs └── x64 │ ├── avcodec-59.dll │ ├── avdevice-59.dll │ ├── avfilter-8.dll │ ├── avformat-59.dll │ ├── avutil-57.dll │ ├── postproc-56.dll │ ├── swresample-4.dll │ └── swscale-6.dll ├── FastVideoDSInfo ├── FastVideoDSInfo.csproj ├── Program.cs └── Properties │ └── launchSettings.json ├── Gericom.FastVideoDS ├── Bitstream │ ├── BitReader.cs │ └── BitWriter.cs ├── Dct.cs ├── FastVideoDSEncoder.cs ├── Frames │ ├── FramePool.cs │ ├── RefFrame.cs │ └── Rgb555Frame.cs ├── Gericom.FastVideoDS.csproj ├── MotionEstimation.cs ├── MotionVector.cs ├── Utils │ └── FrameUtil.cs ├── Vlc.cs └── VlcTables.cs └── readme.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Oo]ut/ 33 | [Ll]og/ 34 | [Ll]ogs/ 35 | 36 | # Visual Studio 2015/2017 cache/options directory 37 | .vs/ 38 | # Uncomment if you have tasks that create the project's static files in wwwroot 39 | #wwwroot/ 40 | 41 | # Visual Studio 2017 auto generated files 42 | Generated\ Files/ 43 | 44 | # MSTest test Results 45 | [Tt]est[Rr]esult*/ 46 | [Bb]uild[Ll]og.* 47 | 48 | # NUnit 49 | *.VisualState.xml 50 | TestResult.xml 51 | nunit-*.xml 52 | 53 | # Build Results of an ATL Project 54 | [Dd]ebugPS/ 55 | [Rr]eleasePS/ 56 | dlldata.c 57 | 58 | # Benchmark Results 59 | BenchmarkDotNet.Artifacts/ 60 | 61 | # .NET Core 62 | project.lock.json 63 | project.fragment.lock.json 64 | artifacts/ 65 | 66 | # ASP.NET Scaffolding 67 | ScaffoldingReadMe.txt 68 | 69 | # StyleCop 70 | StyleCopReport.xml 71 | 72 | # Files built by Visual Studio 73 | *_i.c 74 | *_p.c 75 | *_h.h 76 | *.ilk 77 | *.meta 78 | *.obj 79 | *.iobj 80 | *.pch 81 | *.pdb 82 | *.ipdb 83 | *.pgc 84 | *.pgd 85 | *.rsp 86 | *.sbr 87 | *.tlb 88 | *.tli 89 | *.tlh 90 | *.tmp 91 | *.tmp_proj 92 | *_wpftmp.csproj 93 | *.log 94 | *.vspscc 95 | *.vssscc 96 | .builds 97 | *.pidb 98 | *.svclog 99 | *.scc 100 | 101 | # Chutzpah Test files 102 | _Chutzpah* 103 | 104 | # Visual C++ cache files 105 | ipch/ 106 | *.aps 107 | *.ncb 108 | *.opendb 109 | *.opensdf 110 | *.sdf 111 | *.cachefile 112 | *.VC.db 113 | *.VC.VC.opendb 114 | 115 | # Visual Studio profiler 116 | *.psess 117 | *.vsp 118 | *.vspx 119 | *.sap 120 | 121 | # Visual Studio Trace Files 122 | *.e2e 123 | 124 | # TFS 2012 Local Workspace 125 | $tf/ 126 | 127 | # Guidance Automation Toolkit 128 | *.gpState 129 | 130 | # ReSharper is a .NET coding add-in 131 | _ReSharper*/ 132 | *.[Rr]e[Ss]harper 133 | *.DotSettings.user 134 | 135 | # TeamCity is a build add-in 136 | _TeamCity* 137 | 138 | # DotCover is a Code Coverage Tool 139 | *.dotCover 140 | 141 | # AxoCover is a Code Coverage Tool 142 | .axoCover/* 143 | !.axoCover/settings.json 144 | 145 | # Coverlet is a free, cross platform Code Coverage Tool 146 | coverage*.json 147 | coverage*.xml 148 | coverage*.info 149 | 150 | # Visual Studio code coverage results 151 | *.coverage 152 | *.coveragexml 153 | 154 | # NCrunch 155 | _NCrunch_* 156 | .*crunch*.local.xml 157 | nCrunchTemp_* 158 | 159 | # MightyMoose 160 | *.mm.* 161 | AutoTest.Net/ 162 | 163 | # Web workbench (sass) 164 | .sass-cache/ 165 | 166 | # Installshield output folder 167 | [Ee]xpress/ 168 | 169 | # DocProject is a documentation generator add-in 170 | DocProject/buildhelp/ 171 | DocProject/Help/*.HxT 172 | DocProject/Help/*.HxC 173 | DocProject/Help/*.hhc 174 | DocProject/Help/*.hhk 175 | DocProject/Help/*.hhp 176 | DocProject/Help/Html2 177 | DocProject/Help/html 178 | 179 | # Click-Once directory 180 | publish/ 181 | 182 | # Publish Web Output 183 | *.[Pp]ublish.xml 184 | *.azurePubxml 185 | # Note: Comment the next line if you want to checkin your web deploy settings, 186 | # but database connection strings (with potential passwords) will be unencrypted 187 | *.pubxml 188 | *.publishproj 189 | 190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 191 | # checkin your Azure Web App publish settings, but sensitive information contained 192 | # in these scripts will be unencrypted 193 | PublishScripts/ 194 | 195 | # NuGet Packages 196 | *.nupkg 197 | # NuGet Symbol Packages 198 | *.snupkg 199 | # The packages folder can be ignored because of Package Restore 200 | **/[Pp]ackages/* 201 | # except build/, which is used as an MSBuild target. 202 | !**/[Pp]ackages/build/ 203 | # Uncomment if necessary however generally it will be regenerated when needed 204 | #!**/[Pp]ackages/repositories.config 205 | # NuGet v3's project.json files produces more ignorable files 206 | *.nuget.props 207 | *.nuget.targets 208 | 209 | # Microsoft Azure Build Output 210 | csx/ 211 | *.build.csdef 212 | 213 | # Microsoft Azure Emulator 214 | ecf/ 215 | rcf/ 216 | 217 | # Windows Store app package directories and files 218 | AppPackages/ 219 | BundleArtifacts/ 220 | Package.StoreAssociation.xml 221 | _pkginfo.txt 222 | *.appx 223 | *.appxbundle 224 | *.appxupload 225 | 226 | # Visual Studio cache files 227 | # files ending in .cache can be ignored 228 | *.[Cc]ache 229 | # but keep track of directories ending in .cache 230 | !?*.[Cc]ache/ 231 | 232 | # Others 233 | ClientBin/ 234 | ~$* 235 | *~ 236 | *.dbmdl 237 | *.dbproj.schemaview 238 | *.jfm 239 | *.pfx 240 | *.publishsettings 241 | orleans.codegen.cs 242 | 243 | # Including strong name files can present a security risk 244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 245 | #*.snk 246 | 247 | # Since there are multiple workflows, uncomment next line to ignore bower_components 248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 249 | #bower_components/ 250 | 251 | # RIA/Silverlight projects 252 | Generated_Code/ 253 | 254 | # Backup & report files from converting an old project file 255 | # to a newer Visual Studio version. Backup files are not needed, 256 | # because we have git ;-) 257 | _UpgradeReport_Files/ 258 | Backup*/ 259 | UpgradeLog*.XML 260 | UpgradeLog*.htm 261 | ServiceFabricBackup/ 262 | *.rptproj.bak 263 | 264 | # SQL Server files 265 | *.mdf 266 | *.ldf 267 | *.ndf 268 | 269 | # Business Intelligence projects 270 | *.rdl.data 271 | *.bim.layout 272 | *.bim_*.settings 273 | *.rptproj.rsuser 274 | *- [Bb]ackup.rdl 275 | *- [Bb]ackup ([0-9]).rdl 276 | *- [Bb]ackup ([0-9][0-9]).rdl 277 | 278 | # Microsoft Fakes 279 | FakesAssemblies/ 280 | 281 | # GhostDoc plugin setting file 282 | *.GhostDoc.xml 283 | 284 | # Node.js Tools for Visual Studio 285 | .ntvs_analysis.dat 286 | node_modules/ 287 | 288 | # Visual Studio 6 build log 289 | *.plg 290 | 291 | # Visual Studio 6 workspace options file 292 | *.opt 293 | 294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 295 | *.vbw 296 | 297 | # Visual Studio LightSwitch build output 298 | **/*.HTMLClient/GeneratedArtifacts 299 | **/*.DesktopClient/GeneratedArtifacts 300 | **/*.DesktopClient/ModelManifest.xml 301 | **/*.Server/GeneratedArtifacts 302 | **/*.Server/ModelManifest.xml 303 | _Pvt_Extensions 304 | 305 | # Paket dependency manager 306 | .paket/paket.exe 307 | paket-files/ 308 | 309 | # FAKE - F# Make 310 | .fake/ 311 | 312 | # CodeRush personal settings 313 | .cr/personal 314 | 315 | # Python Tools for Visual Studio (PTVS) 316 | __pycache__/ 317 | *.pyc 318 | 319 | # Cake - Uncomment if you are using it 320 | # tools/** 321 | # !tools/packages.config 322 | 323 | # Tabs Studio 324 | *.tss 325 | 326 | # Telerik's JustMock configuration file 327 | *.jmconfig 328 | 329 | # BizTalk build output 330 | *.btp.cs 331 | *.btm.cs 332 | *.odx.cs 333 | *.xsd.cs 334 | 335 | # OpenCover UI analysis results 336 | OpenCover/ 337 | 338 | # Azure Stream Analytics local run output 339 | ASALocalRun/ 340 | 341 | # MSBuild Binary and Structured Log 342 | *.binlog 343 | 344 | # NVidia Nsight GPU debugger configuration file 345 | *.nvuser 346 | 347 | # MFractors (Xamarin productivity tool) working folder 348 | .mfractor/ 349 | 350 | # Local History for Visual Studio 351 | .localhistory/ 352 | 353 | # BeatPulse healthcheck temp database 354 | healthchecksdb 355 | 356 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 357 | MigrationBackup/ 358 | 359 | # Ionide (cross platform F# VS Code tools) working folder 360 | .ionide/ 361 | 362 | # Fody - auto-generated XML schema 363 | FodyWeavers.xsd 364 | 365 | !FastVideoDSEncoder/x64/ -------------------------------------------------------------------------------- /FastVideoDS.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.2.32505.173 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gericom.FastVideoDS", "Gericom.FastVideoDS\Gericom.FastVideoDS.csproj", "{AC320DAA-A040-4654-A4F2-238224723834}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastVideoDSEncoder", "FastVideoDSEncoder\FastVideoDSEncoder.csproj", "{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastVideoDSInfo", "FastVideoDSInfo\FastVideoDSInfo.csproj", "{BC08ACC4-8B61-4801-8532-D5D054795809}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {AC320DAA-A040-4654-A4F2-238224723834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {AC320DAA-A040-4654-A4F2-238224723834}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {AC320DAA-A040-4654-A4F2-238224723834}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {AC320DAA-A040-4654-A4F2-238224723834}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {BC08ACC4-8B61-4801-8532-D5D054795809}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {BC08ACC4-8B61-4801-8532-D5D054795809}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {BC08ACC4-8B61-4801-8532-D5D054795809}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {BC08ACC4-8B61-4801-8532-D5D054795809}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {35CAC4B4-A8ED-4DBA-941D-7E4438178987} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /FastVideoDSEncoder/Adpcm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gericom.FastVideoDSEncoder 4 | { 5 | public static class Adpcm 6 | { 7 | private static readonly int[] IndexTable = 8 | { 9 | -3, -3, -2, -1, 2, 4, 6, 8, 10 | -3, -3, -2, -1, 2, 4, 6, 8 11 | }; 12 | 13 | private static readonly short[] StepTable = 14 | { 15 | 7, 8, 9, 10, 11, 12, 13, 14, 16 | 16, 17, 19, 21, 23, 25, 28, 17 | 31, 34, 37, 41, 45, 50, 55, 18 | 60, 66, 73, 80, 88, 97, 107, 19 | 118, 130, 143, 157, 173, 190, 209, 20 | 230, 253, 279, 307, 337, 371, 408, 21 | 449, 494, 544, 598, 658, 724, 796, 22 | 876, 963, 1060, 1166, 1282, 1411, 1552, 23 | 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 24 | 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 25 | 9493, 10442, 11487, 12635, 13899, 15289, 16818, 26 | 18500, 20350, 22385, 24623, 27086, 29794, 32767 27 | }; 28 | 29 | public record AdpcmState(short LastSample, int LastIdx); 30 | 31 | private static int GetBestTableIndex(int diff) 32 | { 33 | int lowestDiff = int.MaxValue; 34 | int lowestIdx = -1; 35 | for (int i = 0; i < StepTable.Length; i++) 36 | { 37 | int diff2 = Math.Abs(Math.Abs(diff) - StepTable[i]); 38 | if (diff2 < lowestDiff) 39 | { 40 | lowestDiff = diff2; 41 | lowestIdx = i; 42 | } 43 | } 44 | 45 | return lowestIdx; 46 | } 47 | 48 | public static byte[] Encode(ReadOnlySpan samples) 49 | => Encode(samples, null, true).data; 50 | 51 | public static (byte[] data, AdpcmState lastState) Encode(ReadOnlySpan samples, AdpcmState state, 52 | bool emitHeader) 53 | { 54 | if ((samples.Length & 7) != 0) 55 | throw new Exception("Samples should be a multiple of 8"); 56 | var result = new byte[4 + samples.Length / 2]; 57 | var resultSpan = result.AsSpan(); 58 | int idx; 59 | short last; 60 | if (state == null) 61 | { 62 | if (!emitHeader) 63 | throw new ArgumentException(nameof(emitHeader)); 64 | idx = Math.Min(GetBestTableIndex(samples[1] - samples[0]) + 3, 88); 65 | last = (short)Math.Max(-0x7FFF, samples[0] - StepTable[idx] / 8); 66 | } 67 | else 68 | { 69 | idx = state.LastIdx; 70 | last = state.LastSample; 71 | } 72 | 73 | int offset = 0; 74 | if (emitHeader) 75 | { 76 | resultSpan.WriteLe(0, last); 77 | resultSpan.WriteLe(2, (ushort)idx); 78 | offset += 4; 79 | } 80 | 81 | int error = 0; 82 | for (int i = 0; i < samples.Length; i += 8) 83 | { 84 | uint nibbles = 0; 85 | for (int j = 0; j < 8; j++) 86 | { 87 | int step = StepTable[idx]; 88 | int sample = samples[i + j]; 89 | 90 | int best = -1; 91 | int bestScore = int.MaxValue; 92 | for (int k = 0; k < 16; k++) 93 | { 94 | int diff2 = (step * ((k & 7) * 2 + 1)) >> 3; 95 | int sample3 = last + diff2 * (((k >> 3) & 1) == 1 ? -1 : 1); 96 | if (sample3 < -0x7FFF) 97 | sample3 = -0x7FFF; 98 | if (sample3 > 0x7FFF) 99 | sample3 = 0x7FFF; 100 | int score = Math.Abs(sample3 - sample); 101 | if (i + j + 1 < samples.Length) 102 | { 103 | int step2 = StepTable[Math.Clamp(idx + IndexTable[k], 0, 88)]; 104 | int bestScore2 = int.MaxValue; 105 | for (int l = 0; l < 16; l++) 106 | { 107 | int diff3 = (step2 * ((l & 7) * 2 + 1)) >> 3; 108 | int sample4 = sample3 + diff3 * (((l >> 3) & 1) == 1 ? -1 : 1); 109 | if (sample4 < -0x7FFF) 110 | sample4 = -0x7FFF; 111 | if (sample4 > 0x7FFF) 112 | sample4 = 0x7FFF; 113 | int score2 = Math.Abs(sample4 - samples[i + j + 1]); 114 | if (score2 < bestScore2) 115 | bestScore2 = score2; 116 | } 117 | 118 | score += bestScore2; 119 | } 120 | 121 | if (score < bestScore) 122 | { 123 | bestScore = score; 124 | best = k; 125 | } 126 | } 127 | 128 | nibbles |= (uint)best << (j * 4); 129 | 130 | int diff = (step * ((best & 7) * 2 + 1)) >> 3; 131 | int sample2 = last + diff * (((best >> 3) & 1) == 1 ? -1 : 1); 132 | if (sample2 < -0x7FFF) 133 | sample2 = -0x7FFF; 134 | if (sample2 > 0x7FFF) 135 | sample2 = 0x7FFF; 136 | last = (short)sample2; 137 | idx += IndexTable[best]; 138 | if (idx < 0) 139 | idx = 0; 140 | if (idx > 88) 141 | idx = 88; 142 | } 143 | 144 | resultSpan.WriteLe(offset, nibbles); 145 | offset += 4; 146 | } 147 | 148 | return (result, new(last, idx)); 149 | } 150 | 151 | public static short[] Decode(ReadOnlySpan samples) 152 | { 153 | if ((samples.Length & 3) != 0) 154 | throw new Exception("Samples should be a multiple of 4 bytes"); 155 | var outSamples = new short[(samples.Length - 4) * 2]; 156 | short last = samples.ReadLe(0); 157 | int idx = samples.ReadLe(2); 158 | int offset = 4; 159 | for (int i = 0; i < outSamples.Length; i += 8) 160 | { 161 | uint nibbles = samples.ReadLe(offset); 162 | offset += 4; 163 | for (int j = 0; j < 8; j++) 164 | { 165 | uint nibble = nibbles & 0xF; 166 | nibbles >>= 4; 167 | int diff = (int)((StepTable[idx] * ((nibble & 7) * 2 + 1)) >> 3); 168 | 169 | int sample = last + diff * (((nibble >> 3) & 1) == 1 ? -1 : 1); 170 | 171 | if (sample < -0x7FFF) 172 | sample = -0x7FFF; 173 | if (sample > 0x7FFF) 174 | sample = 0x7FFF; 175 | outSamples[i + j] = (short)sample; 176 | last = (short)sample; 177 | idx += IndexTable[nibble]; 178 | if (idx < 0) 179 | idx = 0; 180 | if (idx > 88) 181 | idx = 88; 182 | } 183 | } 184 | 185 | return outSamples; 186 | } 187 | } 188 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/FFMpegDecoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using FFmpeg.AutoGen; 6 | using Gericom.FastVideoDS.Frames; 7 | using static FFmpeg.AutoGen.ffmpeg; 8 | 9 | namespace Gericom.FastVideoDSEncoder 10 | { 11 | public unsafe class FFMpegDecoder : IDisposable 12 | { 13 | public const int StreamAuto = -1; 14 | public const int NoStream = -2; 15 | 16 | private AVFormatContext* _formatContext; 17 | private AVCodecContext* _videoDecContext; 18 | private AVCodecContext* _audioDecContext; 19 | private SwsContext* _swsContext; 20 | private SwrContext* _swrContext; 21 | private AVPacket* _packet; 22 | private AVFrame* _frame; 23 | 24 | private readonly byte* _rgbData; 25 | 26 | private readonly Queue _frameQueue = new(); 27 | private readonly FramePool _framePool; 28 | private readonly short[] _leftBuffer = new short[2 * 48000]; 29 | private readonly short[] _rightBuffer = new short[2 * 48000]; 30 | private int _audioSampleCount; 31 | private int _audioReadOffset; 32 | private int _audioWriteOffset; 33 | 34 | private long _curVideoPts = -1; 35 | private long _curAudioPts = -1; 36 | 37 | public long FirstVideoPts { get; private set; } = -1; 38 | public long FirstAudioPktPos { get; private set; } = -1; 39 | 40 | public long MaxAudioPktPos { get; set; } = -1; 41 | 42 | public int VideoStreamId { get; } 43 | public int AudioStreamId { get; } 44 | 45 | public int FrameHeight { get; private set; } 46 | 47 | static FFMpegDecoder() 48 | { 49 | ffmpeg.RootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "x64"); 50 | } 51 | 52 | public FFMpegDecoder(string srcPath, long startPts = 0, int videoStreamId = -1, int audioStreamId = -1) 53 | { 54 | AVFormatContext* formatContext = null; 55 | if (avformat_open_input(&formatContext, srcPath, null, null) < 0) 56 | throw new Exception("avformat_open_input error"); 57 | 58 | _formatContext = formatContext; 59 | 60 | if (avformat_find_stream_info(_formatContext, null) < 0) 61 | throw new Exception("avformat_find_stream_info error"); 62 | 63 | if (videoStreamId >= 0 && 64 | (videoStreamId >= formatContext->nb_streams || 65 | formatContext->streams[videoStreamId]->codecpar->codec_type != AVMediaType.AVMEDIA_TYPE_VIDEO)) 66 | throw new ArgumentException(nameof(videoStreamId)); 67 | 68 | if (audioStreamId >= 0 && 69 | (audioStreamId >= formatContext->nb_streams || 70 | formatContext->streams[audioStreamId]->codecpar->codec_type != AVMediaType.AVMEDIA_TYPE_AUDIO)) 71 | throw new ArgumentException(nameof(audioStreamId)); 72 | 73 | for (int i = 0; i < formatContext->nb_streams; i++) 74 | { 75 | var codecType = formatContext->streams[i]->codecpar->codec_type; 76 | 77 | if (videoStreamId != NoStream && videoStreamId < 0 && codecType == AVMediaType.AVMEDIA_TYPE_VIDEO) 78 | { 79 | videoStreamId = i; 80 | continue; 81 | } 82 | 83 | if (audioStreamId != NoStream && audioStreamId < 0 && codecType == AVMediaType.AVMEDIA_TYPE_AUDIO) 84 | { 85 | audioStreamId = i; 86 | continue; 87 | } 88 | } 89 | 90 | if (videoStreamId != NoStream && videoStreamId < 0) 91 | throw new Exception("No video stream found"); 92 | 93 | if (audioStreamId != NoStream && audioStreamId < 0) 94 | throw new Exception("No audio stream found"); 95 | 96 | VideoStreamId = videoStreamId; 97 | AudioStreamId = audioStreamId; 98 | 99 | if (VideoStreamId != NoStream) 100 | { 101 | AVCodec* videoDec = avcodec_find_decoder(_formatContext->streams[VideoStreamId]->codecpar->codec_id); 102 | _videoDecContext = avcodec_alloc_context3(videoDec); 103 | avcodec_parameters_to_context(_videoDecContext, _formatContext->streams[VideoStreamId]->codecpar); 104 | avcodec_open2(_videoDecContext, videoDec, null); 105 | } 106 | 107 | if (AudioStreamId != NoStream) 108 | { 109 | AVCodec* audioDec = avcodec_find_decoder(_formatContext->streams[AudioStreamId]->codecpar->codec_id); 110 | _audioDecContext = avcodec_alloc_context3(audioDec); 111 | avcodec_parameters_to_context(_audioDecContext, _formatContext->streams[AudioStreamId]->codecpar); 112 | avcodec_open2(_audioDecContext, audioDec, null); 113 | } 114 | 115 | if (startPts != 0 && VideoStreamId != NoStream) 116 | { 117 | if (av_seek_frame(_formatContext, VideoStreamId, startPts, 0) < 0) 118 | throw new Exception("av_seek_frame failed"); 119 | avcodec_flush_buffers(_videoDecContext); 120 | 121 | if (AudioStreamId != NoStream) 122 | avcodec_flush_buffers(_audioDecContext); 123 | } 124 | 125 | if (VideoStreamId != NoStream) 126 | { 127 | var aspect = _videoDecContext->sample_aspect_ratio; 128 | if (aspect.num == 0 && aspect.den == 1) 129 | aspect.num = 1; 130 | 131 | FrameHeight = (int)Math.Round(_videoDecContext->height * 256.0 / _videoDecContext->width * aspect.den / 132 | aspect.num); 133 | 134 | int mod8 = FrameHeight & 7; 135 | if (mod8 != 0) 136 | { 137 | FrameHeight &= ~7; 138 | if (mod8 >= 4) 139 | FrameHeight += 8; 140 | } 141 | 142 | _framePool = new FramePool(256, FrameHeight); 143 | 144 | _swsContext = sws_getContext(_videoDecContext->width, _videoDecContext->height, 145 | _videoDecContext->pix_fmt, 146 | 256, FrameHeight, AVPixelFormat.AV_PIX_FMT_BGRA, 147 | SWS_LANCZOS | SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND, null, null, null); 148 | } 149 | 150 | _packet = av_packet_alloc(); 151 | _frame = av_frame_alloc(); 152 | 153 | _audioSampleCount = 0; 154 | _audioReadOffset = 0; 155 | _audioWriteOffset = 0; 156 | 157 | if (VideoStreamId != NoStream) 158 | { 159 | _rgbData = (byte*)NativeMemory.AlignedAlloc(256 * 192 * 4, 16); 160 | 161 | while (FirstVideoPts == -1 && PumpData()) ; 162 | } 163 | 164 | if (AudioStreamId != NoStream) 165 | { 166 | while (FirstAudioPktPos == -1 && PumpData()) ; 167 | } 168 | } 169 | 170 | public AVRational GetFrameRate() 171 | { 172 | var rate = _formatContext->streams[VideoStreamId]->r_frame_rate; 173 | // if (rate.num == 50 && rate.den == 1 && _formatContext->streams[VideoStreamId]->codecpar->field_order != 174 | // AVFieldOrder.AV_FIELD_PROGRESSIVE) 175 | // rate.num = 25; 176 | return rate; 177 | // return _formatContext->streams[VideoStreamId]->r_frame_rate; 178 | } 179 | 180 | public AVRational GetVideoTimeBase() 181 | { 182 | return _formatContext->streams[VideoStreamId]->time_base; 183 | } 184 | 185 | public long GetDuration() 186 | { 187 | if (_formatContext->streams[VideoStreamId]->duration <= 0) 188 | return _formatContext->duration * _formatContext->streams[VideoStreamId]->time_base.den / 189 | ((long)AV_TIME_BASE * _formatContext->streams[VideoStreamId]->time_base.num); 190 | 191 | return _formatContext->streams[VideoStreamId]->duration; 192 | } 193 | 194 | public int GetAudioRate() 195 | { 196 | return 47605; //_formatContext->streams[AudioStreamId]->codecpar->sample_rate; 197 | } 198 | 199 | private bool ReceiveVideoFrame() 200 | { 201 | if (avcodec_receive_frame(_videoDecContext, _frame) < 0) 202 | return false; 203 | 204 | if (_frame->best_effort_timestamp <= _curVideoPts) 205 | { 206 | av_frame_unref(_frame); 207 | return false; 208 | } 209 | 210 | if (FirstVideoPts == -1) 211 | FirstVideoPts = _frame->best_effort_timestamp; 212 | 213 | _curVideoPts = _frame->best_effort_timestamp; 214 | 215 | // fixed (byte* pRgb = _rgbData) 216 | // { 217 | sws_scale(_swsContext, _frame->data, _frame->linesize, 0, 218 | _videoDecContext->height, new[] { _rgbData }, new[] { 256 * 4 }); 219 | 220 | var refFrame = _framePool.AcquireFrame(); 221 | 222 | refFrame.Frame.FromRgba32(_rgbData, 256 * 4); 223 | _frameQueue.Enqueue(refFrame); 224 | // if(_frame->interlaced_frame != 0) 225 | // _frameQueue.Enqueue(RGB555Frame.FromRgba32(pRgb, 256, FrameHeight, 256 * 4)); 226 | // } 227 | 228 | av_frame_unref(_frame); 229 | return true; 230 | } 231 | 232 | private bool ReceiveAudioFrame() 233 | { 234 | if (avcodec_receive_frame(_audioDecContext, _frame) < 0) 235 | return false; 236 | 237 | if (_frame->best_effort_timestamp <= _curAudioPts) 238 | { 239 | av_frame_unref(_frame); 240 | return false; 241 | } 242 | 243 | if (MaxAudioPktPos != -1 && _frame->pkt_pos >= MaxAudioPktPos) 244 | { 245 | av_frame_unref(_frame); 246 | return false; 247 | } 248 | 249 | if (FirstAudioPktPos == -1) 250 | FirstAudioPktPos = _frame->pkt_pos; 251 | 252 | _curAudioPts = _frame->best_effort_timestamp; 253 | 254 | if (_swrContext == null) 255 | { 256 | var inChLayout = &_frame->ch_layout; 257 | AVChannelLayout outChLayout; 258 | av_channel_layout_from_mask(&outChLayout, AV_CH_LAYOUT_STEREO); 259 | // if (chLayout == 0) 260 | // chLayout = av_get_default_channel_layout(_frame->channels); 261 | fixed (SwrContext** swr = &_swrContext) 262 | { 263 | int result = swr_alloc_set_opts2(swr, 264 | &outChLayout, AVSampleFormat.AV_SAMPLE_FMT_S16P, 47605, 265 | inChLayout, _audioDecContext->sample_fmt, _frame->sample_rate, 266 | 0, null); 267 | if (result < 0) 268 | throw new Exception("swr_alloc_set_opts2 error"); 269 | } 270 | 271 | swr_init(_swrContext); 272 | } 273 | 274 | byte** outBufs = stackalloc byte*[2]; 275 | int outSamples = (int)av_rescale_rnd( 276 | swr_get_delay(_swrContext, _frame->sample_rate) + _frame->nb_samples, 47605, 277 | _frame->sample_rate, AVRounding.AV_ROUND_UP); 278 | 279 | if (_audioWriteOffset + outSamples <= _leftBuffer.Length) 280 | { 281 | fixed (short* leftPtr = _leftBuffer, rightPtr = _rightBuffer) 282 | { 283 | outBufs[0] = (byte*)&leftPtr[_audioWriteOffset]; 284 | outBufs[1] = (byte*)&rightPtr[_audioWriteOffset]; 285 | outSamples = swr_convert(_swrContext, outBufs, outSamples, (byte**)&_frame->data, 286 | _frame->nb_samples); 287 | if (outSamples < 0) 288 | throw new Exception("swr_convert error"); 289 | } 290 | } 291 | else 292 | { 293 | var leftBuf = new short[outSamples]; 294 | var rightBuf = new short[outSamples]; 295 | fixed (short* leftPtr = leftBuf, rightPtr = rightBuf) 296 | { 297 | outBufs[0] = (byte*)leftPtr; 298 | outBufs[1] = (byte*)rightPtr; 299 | outSamples = swr_convert(_swrContext, outBufs, outSamples, (byte**)&_frame->data, 300 | _frame->nb_samples); 301 | if (outSamples < 0) 302 | throw new Exception("swr_convert error"); 303 | } 304 | 305 | int firstHalf = _leftBuffer.Length - _audioWriteOffset; 306 | if (firstHalf > outSamples) 307 | firstHalf = outSamples; 308 | Array.Copy(leftBuf, 0, _leftBuffer, _audioWriteOffset, firstHalf); 309 | Array.Copy(rightBuf, 0, _rightBuffer, _audioWriteOffset, firstHalf); 310 | if (firstHalf != outSamples) 311 | { 312 | int secondHalf = outSamples - firstHalf; 313 | Array.Copy(leftBuf, firstHalf, _leftBuffer, 0, secondHalf); 314 | Array.Copy(rightBuf, firstHalf, _rightBuffer, 0, secondHalf); 315 | } 316 | } 317 | 318 | _audioWriteOffset += outSamples; 319 | if (_audioWriteOffset >= _leftBuffer.Length) 320 | _audioWriteOffset -= _leftBuffer.Length; 321 | 322 | _audioSampleCount += outSamples; 323 | if (_audioSampleCount > _leftBuffer.Length) 324 | throw new Exception("Audio buffer overflow!"); 325 | 326 | av_frame_unref(_frame); 327 | return true; 328 | } 329 | 330 | private bool PumpData() 331 | { 332 | int ret = av_read_frame(_formatContext, _packet); 333 | if (ret == AVERROR_EOF) 334 | { 335 | if (VideoStreamId != NoStream) 336 | { 337 | while (ReceiveVideoFrame()) ; 338 | } 339 | 340 | if (AudioStreamId != NoStream) 341 | { 342 | while (ReceiveAudioFrame()) ; 343 | } 344 | 345 | return false; 346 | } 347 | 348 | if (_packet->stream_index == VideoStreamId) 349 | { 350 | avcodec_send_packet(_videoDecContext, _packet); 351 | ReceiveVideoFrame(); 352 | } 353 | else if (_packet->stream_index == AudioStreamId) 354 | { 355 | avcodec_send_packet(_audioDecContext, _packet); 356 | ReceiveAudioFrame(); 357 | } 358 | 359 | av_packet_unref(_packet); 360 | 361 | return true; 362 | } 363 | 364 | public RefFrame GetNextFrame() 365 | { 366 | if (VideoStreamId == NoStream) 367 | return null; 368 | 369 | while (_frameQueue.Count == 0) 370 | { 371 | if (!PumpData()) 372 | { 373 | if (_frameQueue.Count == 0) 374 | return null; 375 | break; 376 | } 377 | } 378 | 379 | return _frameQueue.Dequeue(); 380 | } 381 | 382 | public int GetAudioSamples(short[] leftDst, short[] rightDst, int count) 383 | { 384 | if (AudioStreamId == NoStream) 385 | return 0; 386 | 387 | if (count > _leftBuffer.Length) 388 | throw new Exception("Requesting too much audio data"); 389 | 390 | while (_audioSampleCount < count) 391 | { 392 | if (!PumpData()) 393 | { 394 | count = _audioSampleCount; 395 | break; 396 | } 397 | } 398 | 399 | if (_audioReadOffset + count <= _leftBuffer.Length) 400 | { 401 | Array.Copy(_leftBuffer, _audioReadOffset, leftDst, 0, count); 402 | Array.Copy(_rightBuffer, _audioReadOffset, rightDst, 0, count); 403 | } 404 | else 405 | { 406 | int firstHalf = _leftBuffer.Length - _audioReadOffset; 407 | Array.Copy(_leftBuffer, _audioReadOffset, leftDst, 0, firstHalf); 408 | Array.Copy(_rightBuffer, _audioReadOffset, rightDst, 0, firstHalf); 409 | int secondHalf = count - firstHalf; 410 | Array.Copy(_leftBuffer, 0, leftDst, firstHalf, secondHalf); 411 | Array.Copy(_rightBuffer, 0, rightDst, firstHalf, secondHalf); 412 | } 413 | 414 | _audioReadOffset += count; 415 | if (_audioReadOffset >= _leftBuffer.Length) 416 | _audioReadOffset -= _leftBuffer.Length; 417 | _audioSampleCount -= count; 418 | return count; 419 | } 420 | 421 | public void Dispose() 422 | { 423 | fixed (AVPacket** packet = &_packet) 424 | av_packet_free(packet); 425 | fixed (AVFrame** frame = &_frame) 426 | av_frame_free(frame); 427 | if (VideoStreamId != NoStream) 428 | { 429 | sws_freeContext(_swsContext); 430 | _swsContext = null; 431 | } 432 | 433 | if (AudioStreamId != NoStream && _swrContext != null) 434 | { 435 | fixed (SwrContext** swrContext = &_swrContext) 436 | swr_free(swrContext); 437 | } 438 | 439 | if (AudioStreamId != NoStream) 440 | { 441 | avcodec_close(_audioDecContext); 442 | fixed (AVCodecContext** audioDecContext = &_audioDecContext) 443 | avcodec_free_context(audioDecContext); 444 | } 445 | 446 | if (VideoStreamId != NoStream) 447 | { 448 | avcodec_close(_videoDecContext); 449 | fixed (AVCodecContext** videoDecContext = &_videoDecContext) 450 | avcodec_free_context(videoDecContext); 451 | } 452 | 453 | fixed (AVFormatContext** formatContext = &_formatContext) 454 | avformat_close_input(formatContext); 455 | 456 | if (_rgbData != null) 457 | NativeMemory.AlignedFree(_rgbData); 458 | 459 | GC.SuppressFinalize(this); 460 | } 461 | 462 | ~FFMpegDecoder() 463 | { 464 | if (_rgbData != null) 465 | NativeMemory.AlignedFree(_rgbData); 466 | } 467 | } 468 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/FastVideoDSEncoder.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | Gericom 7 | FastVideoDS Encoder 8 | disable 9 | $(MSBuildProjectName) 10 | Gericom.FastVideoDSEncoder 11 | 12 | 13 | 14 | true 15 | false 16 | x64 17 | 18 | 19 | 20 | true 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | PreserveNewest 39 | 40 | 41 | PreserveNewest 42 | 43 | 44 | PreserveNewest 45 | 46 | 47 | PreserveNewest 48 | 49 | 50 | PreserveNewest 51 | 52 | 53 | PreserveNewest 54 | 55 | 56 | PreserveNewest 57 | 58 | 59 | PreserveNewest 60 | 61 | 62 | PreserveNewest 63 | 64 | 65 | PreserveNewest 66 | 67 | 68 | PreserveNewest 69 | 70 | 71 | PreserveNewest 72 | 73 | 74 | PreserveNewest 75 | 76 | 77 | PreserveNewest 78 | 79 | 80 | PreserveNewest 81 | 82 | 83 | PreserveNewest 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /FastVideoDSEncoder/FvEncoder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Runtime.Intrinsics.X86; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace Gericom.FastVideoDSEncoder 12 | { 13 | public class FvEncoder 14 | { 15 | private const int AudioFrameSize = 256; 16 | 17 | public volatile int[] JobProgess; 18 | 19 | public List<(int frame, uint offset)>[] JobKeyFrames; 20 | 21 | public uint[] JobFileSize; 22 | 23 | public int MaxGopLength = 250; 24 | 25 | private FvEncoder() { } 26 | 27 | private record EncoderParams(int JobId, string DestinationPath, FFMpegDecoder Decoder, int StartFrame, 28 | int EndFrame); 29 | 30 | private void EncoderThreadMain(object encParams) 31 | { 32 | var (jobId, dstPath, decoder, frame, endFrame) = (EncoderParams)encParams; 33 | 34 | var dummyAudioBuf = new byte[4 + (AudioFrameSize / 2)]; 35 | using (var outStream = File.Create(dstPath)) 36 | { 37 | int audioRate = decoder.GetAudioRate(); 38 | var videoRate = decoder.GetFrameRate(); 39 | var encoder = new Gericom.FastVideoDS.FastVideoDSEncoder(256, decoder.FrameHeight, 30, 0, MaxGopLength); 40 | 41 | int inFrame = frame; 42 | int outFrame = frame; 43 | 44 | while (true) 45 | { 46 | if (inFrame < endFrame) 47 | { 48 | var frameData = decoder.GetNextFrame(); 49 | if (frameData != null) 50 | { 51 | encoder.SendFrame(frameData); 52 | if (++inFrame == endFrame) 53 | encoder.Flush(); 54 | } 55 | else 56 | { 57 | inFrame = endFrame; 58 | encoder.Flush(); 59 | } 60 | } 61 | 62 | var encData = encoder.ReceiveFrame(); 63 | if (encData != null) 64 | { 65 | long expectedSamples = (long)audioRate * (outFrame + 1) * videoRate.den / videoRate.num; 66 | long audioSamplesWritten = ((long)audioRate * outFrame * videoRate.den / videoRate.num) / 67 | AudioFrameSize * AudioFrameSize; 68 | int newSamples = (int)(expectedSamples - audioSamplesWritten); 69 | int audioFrames = newSamples > 0 ? newSamples / AudioFrameSize : 0; 70 | 71 | long curPos = outStream.Position; 72 | 73 | int frameLen = (encData.Data.Length + 3) & ~3; 74 | uint sizeField = ((uint)frameLen & 0x1FFFFu) | ((uint)audioFrames << 17); 75 | outStream.WriteByte((byte)(sizeField & 0xFF)); 76 | outStream.WriteByte((byte)((sizeField >> 8) & 0xFF)); 77 | outStream.WriteByte((byte)((sizeField >> 16) & 0xFF)); 78 | outStream.WriteByte((byte)((sizeField >> 24) & 0xFF)); 79 | outStream.Write(encData.Data); 80 | for (int i = encData.Data.Length; i < frameLen; i++) 81 | outStream.WriteByte(0); 82 | 83 | for (int j = 0; j < audioFrames; j++) 84 | { 85 | outStream.Write(dummyAudioBuf); 86 | outStream.Write(dummyAudioBuf); 87 | } 88 | 89 | if (encData.Type == Gericom.FastVideoDS.FastVideoDSEncoder.FvFrameType.IFrame) 90 | JobKeyFrames[jobId].Add((outFrame, (uint)curPos)); 91 | 92 | outFrame++; 93 | 94 | JobProgess[jobId] = outFrame; 95 | } 96 | 97 | if (inFrame == endFrame && encoder.FrameQueueEmpty) 98 | break; 99 | } 100 | 101 | decoder.Dispose(); 102 | 103 | JobFileSize[jobId] = (uint)outStream.Length; 104 | } 105 | } 106 | 107 | public static void Encode(string inFile, string outFile, int jobCount = 1) 108 | { 109 | if (!Avx2.IsSupported) 110 | throw new Exception("Avx2 instruction support not available"); 111 | 112 | if (jobCount < 1) 113 | throw new ArgumentException(nameof(jobCount)); 114 | 115 | var context = new FvEncoder(); 116 | 117 | var decoder = new FFMpegDecoder(inFile); 118 | 119 | int audioStream = decoder.AudioStreamId; 120 | 121 | long duration = decoder.GetDuration(); 122 | 123 | var timeBase = decoder.GetVideoTimeBase(); 124 | var videoRate = decoder.GetFrameRate(); 125 | int audioRate = decoder.GetAudioRate(); 126 | int frameHeight = decoder.FrameHeight; 127 | 128 | decoder.Dispose(); 129 | 130 | long partDuration = duration / jobCount; 131 | 132 | var decoders = new FFMpegDecoder[jobCount]; 133 | 134 | for (int i = 0; i < jobCount; i++) 135 | { 136 | decoders[i] = new FFMpegDecoder(inFile, partDuration * i, decoder.VideoStreamId, 137 | FFMpegDecoder.NoStream); //decoder.AudioStreamId); 138 | // if (i != 0) 139 | // decoders[i - 1].MaxAudioPktPos = decoders[i].FirstAudioPktPos; 140 | } 141 | 142 | int ptsToFrame(long pts) => 143 | (int)(pts * timeBase.num * videoRate.num / ((long)timeBase.den * videoRate.den)); 144 | 145 | context.JobProgess = new int[jobCount]; 146 | context.JobKeyFrames = new List<(int, uint)>[jobCount]; 147 | context.JobFileSize = new uint[jobCount]; 148 | // var jobProgess = new int[jobCount]; 149 | var startFrames = new int[jobCount]; 150 | var endFrames = new int[jobCount]; 151 | 152 | var tasks = new Task[jobCount]; 153 | for (int i = 0; i < jobCount; i++) 154 | { 155 | int startFrame = i == 0 ? 0 : ptsToFrame(decoders[i].FirstVideoPts); 156 | int endFrame = i == jobCount - 1 ? ptsToFrame(duration) : ptsToFrame(decoders[i + 1].FirstVideoPts); 157 | 158 | startFrames[i] = startFrame; 159 | endFrames[i] = endFrame; 160 | context.JobProgess[i] = startFrame; 161 | context.JobKeyFrames[i] = new(); 162 | 163 | tasks[i] = Task.Factory.StartNew(context.EncoderThreadMain, 164 | new EncoderParams(i, $"{outFile}.{i}", decoders[i], startFrame, endFrame)); 165 | } 166 | 167 | Console.WriteLine($"Encoding video with {jobCount} jobs ..."); 168 | var stopwatch = Stopwatch.StartNew(); 169 | while (true) 170 | { 171 | bool allDone = true; 172 | for (int i = 0; i < jobCount; i++) 173 | { 174 | if (!tasks[i].IsCompleted) 175 | { 176 | allDone = false; 177 | break; 178 | } 179 | } 180 | 181 | int consoleWidth = Console.BufferWidth; 182 | int barWidth = consoleWidth - 3; 183 | Console.SetCursorPosition(0, Console.GetCursorPosition().Top); 184 | Console.Write('['); 185 | int totalFrames = endFrames[^1]; 186 | for (int i = 0; i < barWidth; i++) 187 | { 188 | int barFrame = (i + 1) * totalFrames / barWidth; 189 | for (int j = 0; j < jobCount; j++) 190 | { 191 | if (barFrame >= startFrames[j] && barFrame <= endFrames[j]) 192 | { 193 | if (context.JobProgess[j] >= barFrame) 194 | Console.Write('#'); 195 | else 196 | Console.Write('.'); 197 | break; 198 | } 199 | } 200 | } 201 | 202 | Console.Write(']'); 203 | 204 | if (allDone) 205 | { 206 | Console.WriteLine(); 207 | break; 208 | } 209 | 210 | Thread.Sleep(500); 211 | } 212 | 213 | uint keyFrameCount = (uint)context.JobKeyFrames.Sum(j => (uint)j.Count); 214 | 215 | var audioBlockL = new short[AudioFrameSize]; 216 | var audioBlockR = new short[AudioFrameSize]; 217 | 218 | using (var outStream = File.Create(outFile)) 219 | { 220 | var header = new byte[0x1C + keyFrameCount * 8]; 221 | header[0] = (byte)'F'; 222 | header[1] = (byte)'V'; 223 | header[2] = (byte)'D'; 224 | header[3] = (byte)'S'; 225 | var headerSpan = header.AsSpan(); 226 | headerSpan.WriteLe(0x04, 256); 227 | headerSpan.WriteLe(0x06, (ushort)frameHeight); 228 | headerSpan.WriteLe(0x08, (uint)videoRate.num); 229 | headerSpan.WriteLe(0x0C, (uint)videoRate.den); 230 | headerSpan.WriteLe(0x10, (ushort)audioRate); 231 | headerSpan.WriteLe(0x12, 2); 232 | headerSpan.WriteLe(0x14, (uint)endFrames[^1]); 233 | headerSpan.WriteLe(0x18, keyFrameCount); 234 | 235 | uint jobOffset = (uint)header.Length; 236 | int headerOffset = 0x1C; 237 | for (int i = 0; i < jobCount; i++) 238 | { 239 | foreach (var (frame, offset) in context.JobKeyFrames[i]) 240 | { 241 | headerSpan.WriteLe(headerOffset, (uint)frame); 242 | headerSpan.WriteLe(headerOffset + 4, jobOffset + offset); 243 | headerOffset += 8; 244 | } 245 | 246 | jobOffset += context.JobFileSize[i]; 247 | } 248 | 249 | outStream.Write(header); 250 | 251 | for (int i = 0; i < jobCount; i++) 252 | { 253 | using (var partStream = File.OpenRead($"{outFile}.{i}")) 254 | partStream.CopyTo(outStream); 255 | 256 | File.Delete($"{outFile}.{i}"); 257 | } 258 | 259 | stopwatch.Stop(); 260 | Console.WriteLine($"Video encoding done in {stopwatch.Elapsed}"); 261 | 262 | Console.WriteLine("Encoding audio..."); 263 | 264 | stopwatch = Stopwatch.StartNew(); 265 | 266 | var audioDec = new FFMpegDecoder(inFile, 0, FFMpegDecoder.NoStream, audioStream); 267 | 268 | outStream.Position = header.Length; 269 | var sizeBuf = new byte[4]; 270 | 271 | int f = 0; 272 | var audioTask = Task.Factory.StartNew(() => 273 | { 274 | Adpcm.AdpcmState lastLeft = null; 275 | Adpcm.AdpcmState lastRight = null; 276 | for (; f < endFrames[^1]; f++) 277 | { 278 | outStream.Read(sizeBuf); 279 | uint sizeField = BinaryPrimitives.ReadUInt32LittleEndian(sizeBuf); 280 | 281 | uint frameLen = sizeField & 0x1FFFFu; 282 | uint audioFrames = sizeField >> 17; 283 | 284 | outStream.Position += frameLen; 285 | 286 | for (int j = 0; j < audioFrames; j++) 287 | { 288 | Array.Clear(audioBlockL, 0, audioBlockL.Length); 289 | Array.Clear(audioBlockR, 0, audioBlockR.Length); 290 | int samples = audioDec.GetAudioSamples(audioBlockL, audioBlockR, AudioFrameSize); 291 | (var data, lastLeft) = Adpcm.Encode(audioBlockL, lastLeft, true); 292 | outStream.Write(data); 293 | 294 | (data, lastRight) = Adpcm.Encode(audioBlockR, lastRight, true); 295 | outStream.Write(data); 296 | } 297 | } 298 | }); 299 | 300 | while (!audioTask.IsCompleted) 301 | { 302 | int consoleWidth = Console.BufferWidth; 303 | int barWidth = consoleWidth - 3; 304 | Console.SetCursorPosition(0, Console.GetCursorPosition().Top); 305 | Console.Write('['); 306 | int totalFrames = endFrames[^1]; 307 | int done = barWidth * f / totalFrames; 308 | Console.Write(Enumerable.Repeat('#', done).ToArray()); 309 | Console.Write(Enumerable.Repeat('.', barWidth - done).ToArray()); 310 | 311 | Console.Write(']'); 312 | 313 | Thread.Sleep(500); 314 | } 315 | 316 | Console.WriteLine(); 317 | 318 | stopwatch.Stop(); 319 | Console.WriteLine($"Audio encoding done in {stopwatch.Elapsed}"); 320 | } 321 | } 322 | } 323 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.Intrinsics.X86; 3 | using CommandLine; 4 | using CommandLine.Text; 5 | 6 | namespace Gericom.FastVideoDSEncoder 7 | { 8 | internal class Program 9 | { 10 | private class Options 11 | { 12 | [Option('j', HelpText = "Number of concurrent jobs (default: cpu threads / 1.5)", MetaValue = "jobs")] 13 | public int? Jobs { get; set; } 14 | 15 | [Value(0, Required = true, MetaName = "input", HelpText = "Input video file")] 16 | public string Input { get; set; } 17 | 18 | [Value(1, Required = true, MetaName = "output", HelpText = "Output video file")] 19 | public string Output { get; set; } 20 | } 21 | 22 | static void Main(string[] args) 23 | { 24 | Console.WriteLine("FastVideoDS Encoder by Gericom"); 25 | 26 | if (!Avx2.IsSupported) 27 | { 28 | Console.WriteLine(); 29 | Console.WriteLine("This encoder requires a cpu with support for AVX2 instructions"); 30 | return; 31 | } 32 | 33 | var parser = new Parser(with => 34 | { 35 | with.HelpWriter = null; 36 | with.AutoVersion = false; 37 | with.AutoHelp = true; 38 | }); 39 | 40 | var parserResult = parser.ParseArguments(args); 41 | 42 | parserResult.WithParsed(opt => 43 | { 44 | Console.WriteLine(); 45 | FvEncoder.Encode(opt.Input, opt.Output, opt.Jobs ?? (int)Math.Round(Environment.ProcessorCount / 1.5)); 46 | }); 47 | 48 | parserResult.WithNotParsed(errs => 49 | { 50 | var helpText = HelpText.AutoBuild(parserResult, h => 51 | { 52 | h.AdditionalNewLineAfterOption = false; 53 | h.Heading = ""; 54 | h.Copyright = ""; 55 | h.AutoVersion = false; 56 | h.AutoHelp = false; 57 | h.AddPreOptionsLine("Usage: FastVideoDSEncoder [-j jobs] input output.fv"); 58 | 59 | return h; 60 | }); 61 | 62 | Console.WriteLine(helpText); 63 | }); 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "FastVideoDSEncoder": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/SpanExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace Gericom.FastVideoDSEncoder 7 | { 8 | public static class SpanExtensions 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 11 | private static T ReverseEndianness(T val) where T : unmanaged 12 | { 13 | switch (val) 14 | { 15 | case short value: 16 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 17 | case ushort value: 18 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 19 | case int value: 20 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 21 | case uint value: 22 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 23 | case long value: 24 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 25 | case ulong value: 26 | return (T)(object)BinaryPrimitives.ReverseEndianness(value); 27 | default: 28 | return val; 29 | } 30 | } 31 | 32 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 33 | public static T ReadLe(this Span span, nint offset) where T : unmanaged 34 | => ReadLe(ref MemoryMarshal.GetReference(span), offset); 35 | 36 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 37 | public static T ReadLe(this ReadOnlySpan span, nint offset) where T : unmanaged 38 | => ReadLe(ref MemoryMarshal.GetReference(span), offset); 39 | 40 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 41 | private static T ReadLe(ref byte refSpan, nint offset) where T : unmanaged 42 | { 43 | if (typeof(T) == typeof(float)) 44 | return (T)(object)BinaryPrimitives.ReadSingleLittleEndian( 45 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float))); 46 | 47 | if (typeof(T) == typeof(double)) 48 | return (T)(object)BinaryPrimitives.ReadDoubleLittleEndian( 49 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double))); 50 | 51 | T result = Unsafe.ReadUnaligned(ref Unsafe.Add(ref refSpan, offset)); 52 | 53 | if (BitConverter.IsLittleEndian) 54 | return result; 55 | 56 | return ReverseEndianness(result); 57 | } 58 | 59 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 60 | public static T ReadBe(this Span span, nint offset) where T : unmanaged 61 | => ReadBe(ref MemoryMarshal.GetReference(span), offset); 62 | 63 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 64 | public static T ReadBe(this ReadOnlySpan span, nint offset) where T : unmanaged 65 | => ReadBe(ref MemoryMarshal.GetReference(span), offset); 66 | 67 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 68 | private static T ReadBe(ref byte refSpan, nint offset) where T : unmanaged 69 | { 70 | if (typeof(T) == typeof(float)) 71 | return (T)(object)BinaryPrimitives.ReadSingleBigEndian( 72 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float))); 73 | 74 | if (typeof(T) == typeof(double)) 75 | return (T)(object)BinaryPrimitives.ReadDoubleBigEndian( 76 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double))); 77 | 78 | T result = Unsafe.ReadUnaligned(ref Unsafe.Add(ref refSpan, offset)); 79 | 80 | if (!BitConverter.IsLittleEndian) 81 | return result; 82 | 83 | return ReverseEndianness(result); 84 | } 85 | 86 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 87 | private static void WriteLe(ref byte refSpan, nint offset, T value) where T : unmanaged 88 | { 89 | if (value is float f) 90 | { 91 | BinaryPrimitives.WriteSingleLittleEndian( 92 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)), f); 93 | return; 94 | } 95 | 96 | if (value is double d) 97 | { 98 | BinaryPrimitives.WriteDoubleLittleEndian( 99 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)), d); 100 | return; 101 | } 102 | 103 | if (!BitConverter.IsLittleEndian) 104 | value = ReverseEndianness(value); 105 | 106 | Unsafe.WriteUnaligned(ref Unsafe.Add(ref refSpan, offset), value); 107 | } 108 | 109 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 110 | public static void WriteLe(this Span span, int offset, T value) where T : unmanaged 111 | => WriteLe(ref MemoryMarshal.GetReference(span), offset, value); 112 | 113 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 114 | private static void WriteBe(ref byte refSpan, nint offset, T value) where T : unmanaged 115 | { 116 | if (value is float f) 117 | { 118 | BinaryPrimitives.WriteSingleBigEndian( 119 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)), f); 120 | return; 121 | } 122 | 123 | if (value is double d) 124 | { 125 | BinaryPrimitives.WriteDoubleBigEndian( 126 | MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)), d); 127 | return; 128 | } 129 | 130 | if (BitConverter.IsLittleEndian) 131 | value = ReverseEndianness(value); 132 | 133 | Unsafe.WriteUnaligned(ref Unsafe.Add(ref refSpan, offset), value); 134 | } 135 | 136 | [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] 137 | public static void WriteBe(this Span span, int offset, T value) where T : unmanaged 138 | => WriteBe(ref MemoryMarshal.GetReference(span), offset, value); 139 | } 140 | } -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/avcodec-59.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/avcodec-59.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/avdevice-59.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/avdevice-59.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/avfilter-8.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/avfilter-8.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/avformat-59.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/avformat-59.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/avutil-57.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/avutil-57.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/postproc-56.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/postproc-56.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/swresample-4.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/swresample-4.dll -------------------------------------------------------------------------------- /FastVideoDSEncoder/x64/swscale-6.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Gericom/FastVideoDSEncoder/1a25c4fcd7f4975beaf8312c0d8cc87496992ed6/FastVideoDSEncoder/x64/swscale-6.dll -------------------------------------------------------------------------------- /FastVideoDSInfo/FastVideoDSInfo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | disable 7 | disable 8 | Gericom.FastVideoDSInfo 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /FastVideoDSInfo/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | using System.IO; 4 | 5 | namespace Gericom.FastVideoDSInfo 6 | { 7 | internal class Program 8 | { 9 | static void Main(string[] args) 10 | { 11 | using var stream = File.OpenRead(args[0]); 12 | stream.Position += 0x20; 13 | var keyFrame0OffsBuf = new byte[4]; 14 | stream.Read(keyFrame0OffsBuf); 15 | stream.Position = BinaryPrimitives.ReadUInt32LittleEndian(keyFrame0OffsBuf); 16 | using var csvStream = File.CreateText(args[1]); 17 | csvStream.WriteLine("frame;type;size;audioBlocks"); 18 | var frameHeaderBuf = new byte[4]; 19 | int frame = 0; 20 | while (true) 21 | { 22 | if (stream.Read(frameHeaderBuf) < 4) 23 | break; 24 | uint frameHeader = BinaryPrimitives.ReadUInt32LittleEndian(frameHeaderBuf); 25 | uint frameLen = frameHeader & 0x1FFFFu; 26 | uint audioFrames = frameHeader >> 17; 27 | stream.Read(frameHeaderBuf.AsSpan(0, 2)); 28 | bool isPFrame = (BinaryPrimitives.ReadUInt16LittleEndian(frameHeaderBuf) >> 15) == 1; 29 | csvStream.WriteLine($"{frame};{(isPFrame ? "P" : "I")};{frameLen};{audioFrames}"); 30 | stream.Position += frameLen - 2; 31 | stream.Position += audioFrames * 132 * 2; 32 | frame++; 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /FastVideoDSInfo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "FastVideoDSInfo": { 4 | "commandName": "Project" 5 | } 6 | } 7 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Bitstream/BitReader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | using System.Numerics; 4 | 5 | namespace Gericom.FastVideoDS.Bitstream 6 | { 7 | public class BitReader 8 | { 9 | private readonly byte[] _data; 10 | private int _offset; 11 | public int BitsRemaining; 12 | public uint Bits; 13 | 14 | public BitReader(byte[] data) 15 | { 16 | _data = data; 17 | Bits = (uint)(BinaryPrimitives.ReadUInt16LittleEndian(data) << 16); 18 | BitsRemaining = 0; 19 | _offset = 2; 20 | } 21 | 22 | public uint ReadUnsignedVarInt() 23 | { 24 | int clz = BitOperations.LeadingZeroCount(Bits); //nr zeros 25 | Bits <<= clz; //remove the zeros 26 | Bits += Bits; //remove the stop bit 27 | int r9 = 32 - clz; //shift amount 28 | uint r6 = r9 == 32 ? 0 : Bits >> r9; 29 | r9 = 1; 30 | r6 += (uint)(r9 << clz); 31 | r6--; 32 | Bits <<= clz; 33 | BitsRemaining -= clz << 1; 34 | if (--BitsRemaining < 0) 35 | FillBits(); 36 | return r6; 37 | } 38 | 39 | public void FillBits() 40 | { 41 | if (_offset >= _data.Length) 42 | return; 43 | uint r10 = BinaryPrimitives.ReadUInt16LittleEndian(_data.AsSpan(_offset)); 44 | _offset += 2; 45 | BitsRemaining += 0x10; 46 | int r9 = 0x10 - BitsRemaining; 47 | Bits |= r10 << r9; 48 | } 49 | 50 | private int ReadSignedVarInt() 51 | { 52 | int clz = BitOperations.LeadingZeroCount(Bits); 53 | Bits <<= clz; 54 | Bits += Bits; 55 | int r9 = 32 - clz; 56 | int r6 = r9 == 32 ? 0 : (int)(Bits >> r9); 57 | r9 = 1; 58 | r6 += r9 << clz; 59 | if ((r6 & 1) != 0) 60 | r6 = 1 - r6; 61 | r6 >>= 1; 62 | Bits <<= clz; 63 | BitsRemaining -= clz << 1; 64 | if (--BitsRemaining < 0) 65 | FillBits(); 66 | return r6; 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Bitstream/BitWriter.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Numerics; 3 | 4 | namespace Gericom.FastVideoDS.Bitstream 5 | { 6 | public class BitWriter 7 | { 8 | private readonly MemoryStream _stream = new(); 9 | 10 | private uint _bits = 0; 11 | private int _bitCount = 0; 12 | 13 | public void WriteBits(uint value, int nrBits) 14 | { 15 | if (nrBits <= 0) 16 | return; 17 | _bits |= (value & (1u << nrBits) - 1) << 32 - nrBits - _bitCount; 18 | _bitCount += nrBits; 19 | if (_bitCount >= 16) 20 | Flush(); 21 | } 22 | 23 | //Elias gamma coding 24 | public void WriteUnsignedVarInt(uint value) 25 | { 26 | int NrBits = 32 - BitOperations.LeadingZeroCount((value + 1) / 2); 27 | WriteBits(0, NrBits); 28 | WriteBits(1, 1); //stop bit 29 | value -= (1u << NrBits) - 1; 30 | WriteBits(value, NrBits); 31 | } 32 | 33 | public void WriteSignedVarInt(int value) 34 | { 35 | uint val; 36 | if (value <= 0) 37 | val = (uint)(1 - value * 2); 38 | else 39 | val = (uint)(value * 2); 40 | int nrBits = 32 - BitOperations.LeadingZeroCount(val / 2); 41 | WriteBits(0, nrBits); 42 | WriteBits(1, 1); //stop bit 43 | val -= 1u << nrBits; 44 | WriteBits(val, nrBits); 45 | } 46 | 47 | public void Flush() 48 | { 49 | if (_bitCount <= 0) 50 | return; 51 | _stream.WriteByte((byte)(_bits >> 16 & 0xFF)); 52 | _stream.WriteByte((byte)(_bits >> 24 & 0xFF)); 53 | _bitCount -= 16; 54 | _bits <<= 16; 55 | } 56 | 57 | // public byte[] PeekStream() 58 | // { 59 | // if (BitCount <= 0) 60 | // return _stream.ToArray(); 61 | // var res = new List(); 62 | // res.AddRange(_stream.GetBuffer()); 63 | // res.Add((byte)((Bits >> 16) & 0xFF)); 64 | // res.Add((byte)((Bits >> 24) & 0xFF)); 65 | // return res.ToArray(); 66 | // } 67 | 68 | public byte[] ToArray() 69 | { 70 | Flush(); 71 | return _stream.ToArray(); 72 | } 73 | 74 | public static int GetUnsignedVarIntBitCount(uint value) 75 | { 76 | int result = 0; 77 | int nrBits = 32 - BitOperations.LeadingZeroCount((value + 1) / 2); 78 | result += nrBits; 79 | result++; //stop bit 80 | result += nrBits; 81 | return result; 82 | } 83 | 84 | public static int GetSignedVarIntBitCount(int value) 85 | { 86 | int result = 0; 87 | uint val; 88 | if (value <= 0) 89 | val = (uint)(1 - value * 2); 90 | else 91 | val = (uint)(value * 2); 92 | int nrBits = 32 - BitOperations.LeadingZeroCount(val / 2); 93 | result += nrBits; 94 | result++; //stop bit 95 | result += nrBits; 96 | return result; 97 | } 98 | } 99 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Dct.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gericom.FastVideoDS 4 | { 5 | public static class Dct 6 | { 7 | public static void Dct4NoDiv(int[] pixels, int[] dst) 8 | { 9 | int t0 = pixels[0] + pixels[1]; 10 | int t1 = pixels[0] - pixels[1]; 11 | int t2 = pixels[2] + pixels[3]; 12 | int t3 = pixels[2] - pixels[3]; 13 | 14 | dst[0] = t0 + t2; 15 | dst[1] = t0 - t2; 16 | dst[2] = t1 + t3; 17 | dst[3] = t1 - t3; 18 | } 19 | 20 | public static void IDct4(int[] dct, byte[] pixels, byte[] dst) 21 | { 22 | int r0 = dct[0] + 16; 23 | int t0 = r0 + dct[1]; 24 | int t2 = r0 - dct[1]; 25 | int t1 = dct[2] + dct[3]; 26 | int t3 = dct[2] - dct[3]; 27 | 28 | dst[0] = (byte)(Math.Clamp((pixels[0] >> 3) + (t0 + t1 >> 5), 0, 31) << 3); 29 | dst[1] = (byte)(Math.Clamp((pixels[1] >> 3) + (t0 - t1 >> 5), 0, 31) << 3); 30 | dst[2] = (byte)(Math.Clamp((pixels[2] >> 3) + (t2 + t3 >> 5), 0, 31) << 3); 31 | dst[3] = (byte)(Math.Clamp((pixels[3] >> 3) + (t2 - t3 >> 5), 0, 31) << 3); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Frames/FramePool.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Gericom.FastVideoDS.Frames 4 | { 5 | public class FramePool 6 | { 7 | private readonly Queue _pool = new(); 8 | 9 | public readonly int Width; 10 | public readonly int Height; 11 | 12 | public FramePool(int width, int height) 13 | { 14 | Width = width; 15 | Height = height; 16 | } 17 | 18 | public RefFrame AcquireFrame() 19 | { 20 | if (!_pool.TryDequeue(out var frame)) 21 | frame = new Rgb555Frame(Width, Height); 22 | 23 | return new RefFrame(this, frame); 24 | } 25 | 26 | public void ReleaseFrame(RefFrame frame) 27 | { 28 | _pool.Enqueue(frame.Frame); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Frames/RefFrame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Gericom.FastVideoDS.Frames 4 | { 5 | public sealed class RefFrame : IDisposable 6 | { 7 | private readonly FramePool _pool; 8 | 9 | public int RefCount { get; private set; } = 1; 10 | 11 | public readonly Rgb555Frame Frame; 12 | 13 | public RefFrame(FramePool pool, Rgb555Frame frame) 14 | { 15 | _pool = pool; 16 | Frame = frame; 17 | } 18 | 19 | public void Ref() 20 | { 21 | if (RefCount == 0) 22 | throw new Exception(); 23 | 24 | RefCount++; 25 | } 26 | 27 | public void Unref() 28 | { 29 | if (RefCount == 0) 30 | throw new Exception(); 31 | 32 | if (--RefCount == 0) 33 | _pool.ReleaseFrame(this); 34 | } 35 | 36 | public void Dispose() 37 | { 38 | if (RefCount == 0) 39 | return; 40 | 41 | Unref(); 42 | 43 | if (RefCount != 0) 44 | throw new Exception(); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Frames/Rgb555Frame.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | 4 | namespace Gericom.FastVideoDS.Frames 5 | { 6 | public class Rgb555Frame 7 | { 8 | public readonly int Width; 9 | public readonly int Height; 10 | 11 | public readonly byte[] R; 12 | public readonly byte[] G; 13 | public readonly byte[] B; 14 | 15 | public Rgb555Frame(int width, int height) 16 | { 17 | if (width <= 0) 18 | throw new ArgumentOutOfRangeException(nameof(width), width, "Width should be > 0"); 19 | if (height <= 0) 20 | throw new ArgumentOutOfRangeException(nameof(height), height, "Height should be > 0"); 21 | Width = width; 22 | Height = height; 23 | R = new byte[height * width]; 24 | G = new byte[height * width]; 25 | B = new byte[height * width]; 26 | } 27 | 28 | // public unsafe Bitmap ToBitmap() 29 | // { 30 | // var b = new Bitmap(Width, Height, PixelFormat.Format32bppArgb); 31 | // var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly, 32 | // PixelFormat.Format32bppArgb); 33 | // for (int y = 0; y < b.Height; y++) 34 | // { 35 | // for (int x = 0; x < b.Width; x++) 36 | // { 37 | // // int pr = R[y, x] << 3; // * 255 / 31; 38 | // // int pg = G[y, x] << 3; // * 255 / 31; 39 | // // int pb = B[y, x] << 3; // * 255 / 31; 40 | // 41 | // int pr = (R[y * Width + x] >> 3) * 255 / 31; 42 | // int pg = (G[y * Width + x] >> 3) * 255 / 31; 43 | // int pb = (B[y * Width + x] >> 3) * 255 / 31; 44 | // 45 | // if (pr < 0) pr = 0; 46 | // else if (pr > 255) pr = 255; 47 | // if (pg < 0) pg = 0; 48 | // else if (pg > 255) pg = 255; 49 | // if (pb < 0) pb = 0; 50 | // else if (pb > 255) pb = 255; 51 | // 52 | // *(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4) = Color.FromArgb(pr, pg, pb).ToArgb(); 53 | // } 54 | // } 55 | // 56 | // b.UnlockBits(d); 57 | // return b; 58 | // } 59 | 60 | private static readonly int[,] DitherMatrix = 61 | { 62 | { 0, 12, 3, 15 }, 63 | { 8, 4, 11, 7 }, 64 | { 2, 14, 1, 13 }, 65 | { 10, 6, 9, 5 } 66 | }; 67 | 68 | // public static unsafe Rgb555Frame FromBitmap(Bitmap b) 69 | // { 70 | // var frame = new Rgb555Frame(b.Width, b.Height); 71 | // var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, 72 | // PixelFormat.Format32bppArgb); 73 | // 74 | // for (int y = 0; y < b.Height; y++) 75 | // { 76 | // for (int x = 0; x < b.Width; x++) 77 | // { 78 | // var c = Color.FromArgb(*(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4)); 79 | // int bias = (DitherMatrix[y & 3, x & 3] >> 1) - 4; 80 | // 81 | // int pr = ((c.R + bias) >> 3); // * 255 / 31; 82 | // int pg = ((c.G + bias) >> 3); // * 255 / 31; 83 | // int pb = ((c.B + bias) >> 3); // * 255 / 31; 84 | // 85 | // if (pr < 0) pr = 0; 86 | // else if (pr > 31) pr = 31; 87 | // if (pg < 0) pg = 0; 88 | // else if (pg > 31) pg = 31; 89 | // if (pb < 0) pb = 0; 90 | // else if (pb > 31) pb = 31; 91 | // 92 | // frame.R[y * frame.Width + x] = (byte)(pr << 3); //((pr << 3) | (pr >> 2)); 93 | // frame.G[y * frame.Width + x] = (byte)(pg << 3); //((pg << 3) | (pg >> 2)); 94 | // frame.B[y * frame.Width + x] = (byte)(pb << 3); //((pb << 3) | (pb >> 2)); 95 | // } 96 | // } 97 | // 98 | // b.UnlockBits(d); 99 | // return frame; 100 | // } 101 | 102 | //Based on http://www.thetenthplanet.de/archives/5367 103 | private static double ToLinear(double value) => Math.Pow(value, 2.2); 104 | 105 | private static readonly double[] ToLinear8 = new double[256]; 106 | private static readonly double[] ToLinear5 = new double[32]; 107 | 108 | static Rgb555Frame() 109 | { 110 | for (int i = 0; i < 256; i++) 111 | ToLinear8[i] = ToLinear(i / 255.0); 112 | 113 | for (int i = 0; i < 32; i++) 114 | ToLinear5[i] = ToLinear(i / 31.0); 115 | } 116 | 117 | private static int Dither(int color, double noise) 118 | { 119 | int c0 = color * 31 / 255; 120 | int c1 = Math.Clamp(c0 + 1, 0, 31); 121 | double discr = ToLinear5[c0] * (1 - noise) + ToLinear5[c1] * noise; 122 | return discr < ToLinear8[color] ? c1 : c0; 123 | } 124 | 125 | public static unsafe Rgb555Frame FromRgba32(byte* src, int width, int height, int stride) 126 | { 127 | var frame = new Rgb555Frame(width, height); 128 | frame.FromRgba32(src, stride); 129 | return frame; 130 | } 131 | 132 | public unsafe void FromRgba32(byte* src, int stride) 133 | { 134 | for (int y = 0; y < Height; y++) 135 | { 136 | for (int x = 0; x < Width; x++) 137 | { 138 | var c = Color.FromArgb(*(int*)(src + y * stride + x * 4)); 139 | 140 | int bias = DitherMatrix[y & 3, x & 3]; 141 | 142 | int pr = Dither(c.R, bias / 16.0); 143 | int pg = Dither(c.G, bias / 16.0); 144 | int pb = Dither(c.B, bias / 16.0); 145 | 146 | R[y * Width + x] = (byte)(pr << 3); 147 | G[y * Width + x] = (byte)(pg << 3); 148 | B[y * Width + x] = (byte)(pb << 3); 149 | } 150 | } 151 | } 152 | 153 | // public static unsafe RGB555Frame FromBitmap555(Bitmap b) 154 | // { 155 | // var yuvFrame = new RGB555Frame(b.Width, b.Height); 156 | // var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, 157 | // PixelFormat.Format32bppArgb); 158 | // for (int y = 0; y < b.Height; y++) 159 | // { 160 | // for (int x = 0; x < b.Width; x++) 161 | // { 162 | // var c = Color.FromArgb(*(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4)); 163 | // int bias = (DitherMatrix[y & 3, x & 3] >> 1) - 4; 164 | // 165 | // int pr = ((c.R + bias) >> 3);// * 255 / 31; 166 | // int pg = ((c.G + bias) >> 3);// * 255 / 31; 167 | // int pb = ((c.B + bias) >> 3);// * 255 / 31; 168 | // 169 | // if (pr < 0) pr = 0; 170 | // else if (pr > 31) pr = 31; 171 | // if (pg < 0) pg = 0; 172 | // else if (pg > 31) pg = 31; 173 | // if (pb < 0) pb = 0; 174 | // else if (pb > 31) pb = 31; 175 | // 176 | // yuvFrame.R[y, x] = (byte) pr;//((pr << 3) | (pr >> 2)); 177 | // yuvFrame.G[y, x] = (byte) pg;//((pg << 3) | (pg >> 2)); 178 | // yuvFrame.B[y, x] = (byte) pb;//((pb << 3) | (pb >> 2)); 179 | // } 180 | // } 181 | // 182 | // b.UnlockBits(d); 183 | // return yuvFrame; 184 | // } 185 | } 186 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Gericom.FastVideoDS.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | 6 | 7 | 8 | true 9 | 10 | 11 | 12 | true 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Gericom.FastVideoDS/MotionEstimation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using Gericom.FastVideoDS.Bitstream; 4 | using Gericom.FastVideoDS.Frames; 5 | using Gericom.FastVideoDS.Utils; 6 | 7 | namespace Gericom.FastVideoDS 8 | { 9 | public static class MotionEstimation 10 | { 11 | private static readonly MotionVector[] LdspDirections = 12 | { 13 | new(-2, 0), 14 | new(-1, -1), 15 | new(0, -2), 16 | new(1, -1), 17 | new(2, 0), 18 | new(1, 1), 19 | new(0, 2), 20 | new(-1, 1) 21 | }; 22 | 23 | private static readonly MotionVector[] SdspDirections = 24 | { 25 | new(-1, 0), 26 | new(0, -1), 27 | new(1, 0), 28 | new(0, 1), 29 | }; 30 | 31 | public static MotionVector FindMotionVector(byte[] targetR, byte[] targetG, byte[] targetB, Rgb555Frame src, 32 | MotionVector center, MotionVector cheap, out int bestScore) 33 | { 34 | const int lambda = 4; 35 | var block = new byte[64]; 36 | 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | int getDistortion(MotionVector vec) 39 | { 40 | if (center.Y < (src.Height >> 1) * 2 && vec.Y > (src.Height - 8) * 2 || 41 | center.Y >= (src.Height >> 1) * 2 && vec.Y < 0) 42 | return 999999; 43 | 44 | FrameUtil.GetTileHalf8(src.R, src.Width, src.Height, vec.X, vec.Y, block); 45 | int score = FrameUtil.Sad64(targetR, block); 46 | FrameUtil.GetTileHalf8(src.G, src.Width, src.Height, vec.X, vec.Y, block); 47 | score += FrameUtil.Sad64(targetG, block); 48 | FrameUtil.GetTileHalf8(src.B, src.Width, src.Height, vec.X, vec.Y, block); 49 | score += FrameUtil.Sad64(targetB, block); 50 | 51 | return score; 52 | } 53 | 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | int getBitCount(MotionVector vec) 56 | { 57 | return vec == cheap ? 1 : 58 | 1 + BitWriter.GetSignedVarIntBitCount(vec.X - cheap.X) 59 | + BitWriter.GetSignedVarIntBitCount(vec.Y - cheap.Y); 60 | } 61 | 62 | // var vectors = new HashSet(); 63 | bestScore = getDistortion(center); 64 | int bestBitCount = getBitCount(center); 65 | int bestRdScore = bestBitCount * lambda + bestScore; 66 | var bestRdVec = center; 67 | var bestVec = center; 68 | 69 | int score = getDistortion(cheap); 70 | int bitCount = getBitCount(cheap); 71 | int rdScore = bitCount * lambda + score; 72 | if (score < bestScore || score == bestScore && bitCount < bestBitCount) 73 | { 74 | bestScore = score; 75 | bestBitCount = bitCount; 76 | bestVec = cheap; 77 | } 78 | 79 | if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore) 80 | { 81 | bestRdScore = rdScore; 82 | bestRdVec = cheap; 83 | } 84 | 85 | var searchCenter = cheap; 86 | 87 | int count = 0; 88 | int bestIdx; 89 | do 90 | { 91 | bestIdx = -1; 92 | for (int i = 0; i < LdspDirections.Length; i++) 93 | { 94 | var vec = searchCenter + LdspDirections[i]; 95 | // if(vectors.Contains(vec)) 96 | // continue; 97 | // vectors.Add(vec); 98 | score = getDistortion(vec); 99 | bitCount = getBitCount(vec); 100 | rdScore = bitCount * lambda + score; 101 | if (score < bestScore || score == bestScore && bitCount < bestBitCount) 102 | { 103 | bestScore = score; 104 | bestBitCount = bitCount; 105 | bestVec = vec; 106 | bestIdx = i; 107 | } 108 | 109 | if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore) 110 | { 111 | bestRdScore = rdScore; 112 | bestRdVec = vec; 113 | } 114 | 115 | count++; 116 | } 117 | 118 | searchCenter = bestVec; 119 | } while (bestIdx != -1 && count < 128); //32); 120 | 121 | count = 0; 122 | do 123 | { 124 | bestIdx = -1; 125 | for (int i = 0; i < SdspDirections.Length; i++) 126 | { 127 | var vec = searchCenter + SdspDirections[i]; 128 | // if (vectors.Contains(vec)) 129 | // continue; 130 | // vectors.Add(vec); 131 | score = getDistortion(vec); 132 | bitCount = getBitCount(vec); 133 | rdScore = bitCount * lambda + score; 134 | if (score < bestScore || score == bestScore && bitCount < bestBitCount) 135 | { 136 | bestScore = score; 137 | bestBitCount = bitCount; 138 | bestVec = vec; 139 | bestIdx = i; 140 | } 141 | 142 | if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore) 143 | { 144 | bestRdScore = rdScore; 145 | bestRdVec = vec; 146 | } 147 | 148 | count++; 149 | } 150 | 151 | searchCenter = bestVec; 152 | } while (bestIdx != -1 && count < 128); //32); 153 | 154 | return bestRdVec; 155 | } 156 | } 157 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/MotionVector.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | namespace Gericom.FastVideoDS 4 | { 5 | public struct MotionVector 6 | { 7 | public int X; 8 | public int Y; 9 | 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public MotionVector(int x, int y) 12 | { 13 | X = x; 14 | Y = y; 15 | } 16 | 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | public static MotionVector operator +(MotionVector a, MotionVector b) 19 | => new(a.X + b.X, a.Y + b.Y); 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static MotionVector operator *(MotionVector a, int mul) 23 | => new(a.X * mul, a.Y * mul); 24 | 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static bool operator ==(MotionVector left, MotionVector right) 27 | => left.Equals(right); 28 | 29 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 30 | public static bool operator !=(MotionVector left, MotionVector right) 31 | => !left.Equals(right); 32 | 33 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 34 | public bool Equals(MotionVector other) 35 | => X == other.X && Y == other.Y; 36 | 37 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 38 | public override bool Equals(object obj) 39 | => obj is MotionVector other && Equals(other); 40 | 41 | public override int GetHashCode() 42 | => unchecked(X * 397 ^ Y); 43 | } 44 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Utils/FrameUtil.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.Intrinsics; 4 | using System.Runtime.Intrinsics.X86; 5 | 6 | namespace Gericom.FastVideoDS.Utils 7 | { 8 | public static class FrameUtil 9 | { 10 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 11 | public static unsafe void GetTile8(byte[] data, int stride, int srcX, int srcY, byte[] result) 12 | { 13 | fixed (byte* dst = &result[0], src = &data[srcY * stride + srcX]) 14 | { 15 | ((ulong*)dst)[0] = *(ulong*)(src); 16 | ((ulong*)dst)[1] = *(ulong*)(src + 1 * stride); 17 | ((ulong*)dst)[2] = *(ulong*)(src + 2 * stride); 18 | ((ulong*)dst)[3] = *(ulong*)(src + 3 * stride); 19 | ((ulong*)dst)[4] = *(ulong*)(src + 4 * stride); 20 | ((ulong*)dst)[5] = *(ulong*)(src + 5 * stride); 21 | ((ulong*)dst)[6] = *(ulong*)(src + 6 * stride); 22 | ((ulong*)dst)[7] = *(ulong*)(src + 7 * stride); 23 | } 24 | } 25 | 26 | public static byte[] GetTile(byte[] data, int stride, int srcX, int srcY, int width, int height) 27 | { 28 | var result = new byte[height * width]; 29 | for (int y = 0; y < height; y++) 30 | { 31 | for (int x = 0; x < width; x++) 32 | { 33 | result[y * width + x] = data[(y + srcY) * stride + (x + srcX)]; 34 | } 35 | } 36 | 37 | return result; 38 | } 39 | 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | public static void GetTile2x2Step2(byte[] data, int stride, int srcX, int srcY, byte[] dst) 42 | { 43 | dst[0] = data[(srcY) * stride + srcX]; 44 | dst[1] = data[(srcY) * stride + srcX + 2]; 45 | dst[2] = data[(srcY + 2) * stride + srcX]; 46 | dst[3] = data[(srcY + 2) * stride + srcX + 2]; 47 | } 48 | 49 | public static byte[] GetTile(byte[] data, int stride, int srcX, int srcY, int width, int height, int step) 50 | { 51 | var result = new byte[height * width]; 52 | for (int y = 0; y < height; y++) 53 | { 54 | for (int x = 0; x < width; x++) 55 | { 56 | result[y * width + x] = data[(y * step + srcY) * stride + x * step + srcX]; 57 | } 58 | } 59 | 60 | return result; 61 | } 62 | 63 | [MethodImpl(MethodImplOptions.AggressiveOptimization)] 64 | public static unsafe void GetTileHalf8(byte[] data, int width, int height, int srcX, int srcY, byte[] result) 65 | { 66 | if (((srcX | srcY) & 1) == 0) 67 | { 68 | if (srcX >> 1 >= 0 && (srcX >> 1) + 7 < width && 69 | srcY >> 1 >= 0 && (srcY >> 1) + 7 < height) 70 | { 71 | fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)]) 72 | { 73 | ((ulong*)dst)[0] = *(ulong*)(src); 74 | ((ulong*)dst)[1] = *(ulong*)(src + 1 * width); 75 | ((ulong*)dst)[2] = *(ulong*)(src + 2 * width); 76 | ((ulong*)dst)[3] = *(ulong*)(src + 3 * width); 77 | ((ulong*)dst)[4] = *(ulong*)(src + 4 * width); 78 | ((ulong*)dst)[5] = *(ulong*)(src + 5 * width); 79 | ((ulong*)dst)[6] = *(ulong*)(src + 6 * width); 80 | ((ulong*)dst)[7] = *(ulong*)(src + 7 * width); 81 | } 82 | } 83 | else 84 | { 85 | for (int y = 0; y < 8; y++) 86 | { 87 | int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1); 88 | for (int x = 0; x < 8; x++) 89 | { 90 | int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1); 91 | result[y * 8 + x] = data[y1 * width + x1]; 92 | } 93 | } 94 | } 95 | } 96 | else if ((srcY & 1) == 0) 97 | { 98 | if (srcX >> 1 >= 0 && (srcX >> 1) + 8 < width && 99 | srcY >> 1 >= 0 && (srcY >> 1) + 7 < height) 100 | { 101 | fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)]) 102 | { 103 | var bit0 = Vector256.Create((short)(1 << 2)); 104 | for (int y = 0; y < 8; y++) 105 | { 106 | ulong row = *(ulong*)(src + y * width); 107 | ulong row2 = (row >> 8) | ((ulong)src[y * width + 8] << 56); 108 | 109 | var a = Avx2.ConvertToVector256Int16(Vector128.Create(row, row2).AsByte()); 110 | var isZero = Avx2.CompareEqual(a, Vector256.Zero); 111 | a = Avx2.Add(a, bit0); 112 | a = Avx2.AndNot(isZero, a); 113 | var b = Sse2.Add(a.GetLower(), a.GetUpper()); 114 | b = Sse2.ShiftRightLogical(b, 4); 115 | b = Sse2.ShiftLeftLogical(b, 3); 116 | *(ulong*)(dst + y * 8) = Sse2.PackUnsignedSaturate(b, Vector128.Zero).AsUInt64() 117 | .ToScalar(); 118 | } 119 | } 120 | 121 | // for (int y = 0; y < 8; y++) 122 | // { 123 | // for (int x = 0; x < 8; x++) 124 | // { 125 | // int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1; 126 | // if (a != 0) 127 | // a++; 128 | // int b = data[(y + (srcY >> 1)) * width + x + (srcX >> 1) + 1] >> 3 << 1; 129 | // if (b != 0) 130 | // b++; 131 | // result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 132 | // } 133 | // } 134 | } 135 | else 136 | { 137 | for (int y = 0; y < 8; y++) 138 | { 139 | int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1); 140 | for (int x = 0; x < 8; x++) 141 | { 142 | int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1); 143 | int x2 = Math.Clamp(x + (srcX >> 1) + 1, 0, width - 1); 144 | int a = data[y1 * width + x1] >> 3 << 1; 145 | if (a != 0) 146 | a++; 147 | int b = data[y1 * width + x2] >> 3 << 1; 148 | if (b != 0) 149 | b++; 150 | result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3); 151 | } 152 | } 153 | } 154 | } 155 | else if ((srcX & 1) == 0) 156 | { 157 | if (srcX >> 1 >= 0 && (srcX >> 1) + 7 < width && 158 | srcY >> 1 >= 0 && (srcY >> 1) + 8 < height) 159 | { 160 | fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)]) 161 | { 162 | var bit0 = Vector256.Create((short)(1 << 2)); 163 | var ac = Avx2.ConvertToVector256Int16( 164 | Vector128.Create(*(ulong*)(src + 0 * width), *(ulong*)(src + 2 * width)).AsByte()); 165 | var isZero = Avx2.CompareEqual(ac, Vector256.Zero); 166 | ac = Avx2.Add(ac, bit0); 167 | ac = Avx2.AndNot(isZero, ac); 168 | 169 | var bd = Avx2.ConvertToVector256Int16( 170 | Vector128.Create(*(ulong*)(src + 1 * width), *(ulong*)(src + 3 * width)).AsByte()); 171 | isZero = Avx2.CompareEqual(bd, Vector256.Zero); 172 | bd = Avx2.Add(bd, bit0); 173 | bd = Avx2.AndNot(isZero, bd); 174 | 175 | 176 | var aBcD = Avx2.Add(ac, bd); 177 | aBcD = Avx2.ShiftRightLogical(aBcD, 4); 178 | aBcD = Avx2.ShiftLeftLogical(aBcD, 3); 179 | 180 | 181 | var eg = Avx2.ConvertToVector256Int16( 182 | Vector128.Create(*(ulong*)(src + 4 * width), *(ulong*)(src + 6 * width)).AsByte()); 183 | isZero = Avx2.CompareEqual(eg, Vector256.Zero); 184 | eg = Avx2.Add(eg, bit0); 185 | eg = Avx2.AndNot(isZero, eg); 186 | 187 | var ce = Vector256.Create(ac.GetUpper(), eg.GetLower()); 188 | var bCdE = Avx2.Add(bd, ce); 189 | bCdE = Avx2.ShiftRightLogical(bCdE, 4); 190 | bCdE = Avx2.ShiftLeftLogical(bCdE, 3); 191 | Avx.Store(dst, Avx2.PackUnsignedSaturate(aBcD, bCdE)); 192 | 193 | var fh = Avx2.ConvertToVector256Int16( 194 | Vector128.Create(*(ulong*)(src + 5 * width), *(ulong*)(src + 7 * width)).AsByte()); 195 | isZero = Avx2.CompareEqual(fh, Vector256.Zero); 196 | fh = Avx2.Add(fh, bit0); 197 | fh = Avx2.AndNot(isZero, fh); 198 | 199 | var eFgH = Avx2.Add(eg, fh); 200 | eFgH = Avx2.ShiftRightLogical(eFgH, 4); 201 | eFgH = Avx2.ShiftLeftLogical(eFgH, 3); 202 | 203 | var last = Sse41.ConvertToVector128Int16(src + 8 * width); 204 | var isZeroLast = Sse2.CompareEqual(last, Vector128.Zero); 205 | last = Sse2.Add(last, Vector128.Create((short)(1 << 2))); 206 | last = Sse2.AndNot(isZeroLast, last); 207 | 208 | var gi = Vector256.Create(eg.GetUpper(), last); 209 | var fGhI = Avx2.Add(fh, gi); 210 | fGhI = Avx2.ShiftRightLogical(fGhI, 4); 211 | fGhI = Avx2.ShiftLeftLogical(fGhI, 3); 212 | Avx.Store(dst + 4 * 8, Avx2.PackUnsignedSaturate(eFgH, fGhI)); 213 | } 214 | 215 | // for (int y = 0; y < 8; y++) 216 | // { 217 | // for (int x = 0; x < 8; x++) 218 | // { 219 | // int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1; 220 | // if (a != 0) 221 | // a++; 222 | // int b = data[(y + (srcY >> 1) + 1) * width + x + (srcX >> 1)] >> 3 << 1; 223 | // if (b != 0) 224 | // b++; 225 | // if(result[y * 8 + x] != (byte)((a * 16 + b * 16) >> 6 << 3)) 226 | // { 227 | // 228 | // } 229 | // result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 230 | // } 231 | // } 232 | } 233 | else 234 | { 235 | for (int y = 0; y < 8; y++) 236 | { 237 | int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1); 238 | int y2 = Math.Clamp(y + (srcY >> 1) + 1, 0, height - 1); 239 | for (int x = 0; x < 8; x++) 240 | { 241 | int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1); 242 | int a = data[y1 * width + x1] >> 3 << 1; 243 | if (a != 0) 244 | a++; 245 | int b = data[y2 * width + x1] >> 3 << 1; 246 | if (b != 0) 247 | b++; 248 | result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3); 249 | } 250 | } 251 | } 252 | } 253 | else 254 | { 255 | if (srcX >> 1 >= 0 && (srcX >> 1) + 8 < width && 256 | srcY >> 1 >= 0 && (srcY >> 1) + 8 < height) 257 | { 258 | fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)]) 259 | { 260 | var bit0 = Vector256.Create((short)(1 << 2)); 261 | for (int y = 0; y < 8; y++) 262 | { 263 | var a = Avx2.ConvertToVector256Int16( 264 | Vector128.Create(*(ulong*)(src + y * width), *(ulong*)(src + (y + 1) * width + 1)) 265 | .AsByte()); 266 | var isZero = Avx2.CompareEqual(a, Vector256.Zero); 267 | a = Avx2.Add(a, bit0); 268 | a = Avx2.AndNot(isZero, a); 269 | var b = Sse2.Add(a.GetLower(), a.GetUpper()); 270 | b = Sse2.ShiftRightLogical(b, 4); 271 | b = Sse2.ShiftLeftLogical(b, 3); 272 | *(ulong*)(dst + y * 8) = Sse2.PackUnsignedSaturate(b, Vector128.Zero).AsUInt64() 273 | .ToScalar(); 274 | } 275 | } 276 | 277 | // for (int y = 0; y < 8; y++) 278 | // { 279 | // for (int x = 0; x < 8; x++) 280 | // { 281 | // int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1; 282 | // if (a != 0) 283 | // a++; 284 | // int b = data[(y + (srcY >> 1) + 1) * width + x + (srcX >> 1) + 1] >> 3 << 1; 285 | // if (b != 0) 286 | // b++; 287 | // result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 288 | // } 289 | // } 290 | } 291 | else 292 | { 293 | for (int y = 0; y < 8; y++) 294 | { 295 | int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1); 296 | int y2 = Math.Clamp(y + (srcY >> 1) + 1, 0, height - 1); 297 | for (int x = 0; x < 8; x++) 298 | { 299 | int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1); 300 | int x2 = Math.Clamp(x + (srcX >> 1) + 1, 0, width - 1); 301 | int a = data[y1 * width + x1] >> 3 << 1; 302 | if (a != 0) 303 | a++; 304 | int b = data[y2 * width + x2] >> 3 << 1; 305 | if (b != 0) 306 | b++; 307 | result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3); 308 | } 309 | } 310 | } 311 | } 312 | } 313 | 314 | // public static unsafe byte[] GetTileHalf(byte[,] data, int srcX, int srcY, int width, int height) 315 | // { 316 | // var result = new byte[height * width]; 317 | // if (((srcX | srcY) & 1) == 0) 318 | // { 319 | // if (srcX >> 1 >= 0 && (srcX >> 1) + width - 1 < data.GetLength(1) && 320 | // srcY >> 1 >= 0 && (srcY >> 1) + height - 1 < data.GetLength(0)) 321 | // { 322 | // fixed (byte* dst = &result[0]) 323 | // { 324 | // for (int y = 0; y < height; y++) 325 | // { 326 | // fixed (byte* src = &data[(srcY >> 1) + y, srcX >> 1]) 327 | // { 328 | // Buffer.MemoryCopy(src, dst + y * width, width, width); 329 | // } 330 | // } 331 | // } 332 | // } 333 | // else 334 | // { 335 | // for (int y = 0; y < height; y++) 336 | // { 337 | // for (int x = 0; x < width; x++) 338 | // { 339 | // int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1); 340 | // int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1); 341 | // result[y * width + x] = data[y1, x1]; 342 | // } 343 | // } 344 | // } 345 | // } 346 | // else if ((srcY & 1) == 0) 347 | // { 348 | // for (int y = 0; y < height; y++) 349 | // { 350 | // for (int x = 0; x < width; x++) 351 | // { 352 | // int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1); 353 | // int x2 = MathUtil.Clamp(x + (srcX >> 1) + 1, 0, data.GetLength(1) - 1); 354 | // int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1); 355 | // int a = data[y1, x1] >> 3 << 1; 356 | // if (a != 0) 357 | // a++; 358 | // int b = data[y1, x2] >> 3 << 1; 359 | // if (b != 0) 360 | // b++; 361 | // result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 362 | // //(byte) (((data[y1, x1] + data[y1, x2] + 8) >> 1) & 0xF8); 363 | // } 364 | // } 365 | // } 366 | // else if ((srcX & 1) == 0) 367 | // { 368 | // for (int y = 0; y < height; y++) 369 | // { 370 | // for (int x = 0; x < width; x++) 371 | // { 372 | // int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1); 373 | // int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1); 374 | // int y2 = MathUtil.Clamp(y + (srcY >> 1) + 1, 0, data.GetLength(0) - 1); 375 | // int a = data[y1, x1] >> 3 << 1; 376 | // if (a != 0) 377 | // a++; 378 | // int b = data[y2, x1] >> 3 << 1; 379 | // if (b != 0) 380 | // b++; 381 | // result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 382 | // // result[y * width + x] = (byte) (((data[y1, x1] + data[y2, x1] + 8) >> 1) & 0xF8); 383 | // } 384 | // } 385 | // } 386 | // else 387 | // { 388 | // for (int y = 0; y < height; y++) 389 | // { 390 | // for (int x = 0; x < width; x++) 391 | // { 392 | // int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1); 393 | // int x2 = MathUtil.Clamp(x + (srcX >> 1) + 1, 0, data.GetLength(1) - 1); 394 | // int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1); 395 | // int y2 = MathUtil.Clamp(y + (srcY >> 1) + 1, 0, data.GetLength(0) - 1); 396 | // int a = data[y1, x1] >> 3 << 1; 397 | // if (a != 0) 398 | // a++; 399 | // int b = data[y2, x2] >> 3 << 1; 400 | // if (b != 0) 401 | // b++; 402 | // result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3); 403 | // // result[y * width + x] = (byte) (((data[y1, x1] + data[y2, x2] + 8) >> 1) & 0xF8); 404 | // } 405 | // } 406 | // } 407 | // 408 | // return result; 409 | // } 410 | 411 | public static void SetTile(byte[,] data, int dstX, int dstY, int width, int height, byte[] src) 412 | { 413 | for (int y = 0; y < height; y++) 414 | for (int x = 0; x < width; x++) 415 | data[y + dstY, x + dstX] = src[y * width + x]; 416 | } 417 | 418 | public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, int step, 419 | byte[] src) 420 | { 421 | for (int y = 0; y < height; y++) 422 | for (int x = 0; x < width; x++) 423 | data[(y * step + dstY) * stride + x * step + dstX] = src[y * width + x]; 424 | } 425 | 426 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 427 | public static void SetTile2x2Step2(byte[] data, int stride, int dstX, int dstY, byte[] src) 428 | { 429 | data[dstY * stride + dstX] = src[0]; 430 | data[dstY * stride + dstX + 2] = src[1]; 431 | data[(dstY + 2) * stride + dstX] = src[2]; 432 | data[(dstY + 2) * stride + dstX + 2] = src[3]; 433 | } 434 | 435 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 436 | public static unsafe void SetTile8(byte[] data, int stride, int dstX, int dstY, byte[] src) 437 | { 438 | fixed (byte* pSrc = &src[0], pDst = &data[dstY * stride + dstX]) 439 | { 440 | *(ulong*)(pDst) = ((ulong*)pSrc)[0]; 441 | *(ulong*)(pDst + 1 * stride) = ((ulong*)pSrc)[1]; 442 | *(ulong*)(pDst + 2 * stride) = ((ulong*)pSrc)[2]; 443 | *(ulong*)(pDst + 3 * stride) = ((ulong*)pSrc)[3]; 444 | *(ulong*)(pDst + 4 * stride) = ((ulong*)pSrc)[4]; 445 | *(ulong*)(pDst + 5 * stride) = ((ulong*)pSrc)[5]; 446 | *(ulong*)(pDst + 6 * stride) = ((ulong*)pSrc)[6]; 447 | *(ulong*)(pDst + 7 * stride) = ((ulong*)pSrc)[7]; 448 | } 449 | } 450 | 451 | // public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, byte[,] src) 452 | // { 453 | // for (int y = 0; y < height; y++) 454 | // for (int x = 0; x < width; x++) 455 | // data[(y + dstY) * stride + x + dstX] = src[y, x]; 456 | // } 457 | 458 | public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, int step, 459 | byte[,] src) 460 | { 461 | for (int y = 0; y < height; y++) 462 | for (int x = 0; x < width; x++) 463 | data[(y * step + dstY) * stride + x * step + dstX] = src[y, x]; 464 | } 465 | 466 | public static unsafe byte[] GetBlockPixels16x16(byte[] Data, int X, int Y, int Stride, int Offset) 467 | { 468 | byte[] values = new byte[256]; 469 | fixed (byte* pVals = &values[0]) 470 | { 471 | ulong* pLVals = (ulong*)pVals; 472 | for (int y3 = 0; y3 < 16; y3++) 473 | { 474 | fixed (byte* pData = &Data[(Y + y3) * Stride + X + Offset]) 475 | { 476 | *pLVals++ = *((ulong*)pData); 477 | *pLVals++ = *((ulong*)(pData + 8)); 478 | } 479 | } 480 | } 481 | 482 | return values; 483 | } 484 | 485 | public static unsafe byte[] GetBlockPixels8x8(byte[] Data, int X, int Y, int Stride, int Offset) 486 | { 487 | byte[] values = new byte[64]; 488 | fixed (byte* pVals = &values[0], pData = &Data[Y * Stride + X + Offset]) 489 | { 490 | ulong* pLVals = (ulong*)pVals; 491 | *pLVals++ = *((ulong*)pData); 492 | *pLVals++ = *((ulong*)(pData + Stride)); 493 | *pLVals++ = *((ulong*)(pData + Stride * 2)); 494 | *pLVals++ = *((ulong*)(pData + Stride * 3)); 495 | *pLVals++ = *((ulong*)(pData + Stride * 4)); 496 | *pLVals++ = *((ulong*)(pData + Stride * 5)); 497 | *pLVals++ = *((ulong*)(pData + Stride * 6)); 498 | *pLVals++ = *((ulong*)(pData + Stride * 7)); 499 | /*ulong* pLVals = (ulong*)pVals; 500 | for (int y3 = 0; y3 < 8; y3++) 501 | { 502 | fixed (byte* pData = &Data[(Y + y3) * Stride + X + Offset]) 503 | { 504 | *pLVals++ = *((ulong*)pData); 505 | } 506 | }*/ 507 | } 508 | 509 | return values; 510 | } 511 | 512 | public static unsafe byte[] GetBlockPixels4x4(byte[] Data, int X, int Y, int Stride, int Offset) 513 | { 514 | byte[] values = new byte[16]; 515 | fixed (byte* pVals = &values[0], pData = &Data[Y * Stride + X + Offset]) 516 | { 517 | uint* pLVals = (uint*)pVals; 518 | *pLVals++ = *((uint*)pData); 519 | *pLVals++ = *((uint*)(pData + Stride)); 520 | *pLVals++ = *((uint*)(pData + Stride * 2)); 521 | *pLVals++ = *((uint*)(pData + Stride * 3)); 522 | } 523 | 524 | return values; 525 | } 526 | 527 | public static unsafe void SetBlockPixels4x4(byte[] Data, int X, int Y, int Stride, int Offset, byte[] Values) 528 | { 529 | fixed (byte* pVals = &Values[0], pData = &Data[Y * Stride + X + Offset]) 530 | { 531 | uint* pLVals = (uint*)pVals; 532 | *((uint*)pData) = *pLVals++; 533 | *((uint*)(pData + Stride)) = *pLVals++; 534 | *((uint*)(pData + Stride * 2)) = *pLVals++; 535 | *((uint*)(pData + Stride * 3)) = *pLVals++; 536 | } 537 | } 538 | 539 | public static unsafe void SetBlockPixels8x8(byte[] Data, int X, int Y, int Stride, int Offset, byte[] Values) 540 | { 541 | fixed (byte* pVals = &Values[0], pData = &Data[Y * Stride + X + Offset]) 542 | { 543 | ulong* pLVals = (ulong*)pVals; 544 | *((ulong*)pData) = *pLVals++; 545 | *((ulong*)(pData + Stride)) = *pLVals++; 546 | *((ulong*)(pData + Stride * 2)) = *pLVals++; 547 | *((ulong*)(pData + Stride * 3)) = *pLVals++; 548 | *((ulong*)(pData + Stride * 4)) = *pLVals++; 549 | *((ulong*)(pData + Stride * 5)) = *pLVals++; 550 | *((ulong*)(pData + Stride * 6)) = *pLVals++; 551 | *((ulong*)(pData + Stride * 7)) = *pLVals++; 552 | } 553 | } 554 | 555 | 556 | public static unsafe int Sad64(ReadOnlySpan a, ReadOnlySpan b) 557 | { 558 | fixed (byte* pA = a, pB = b) 559 | { 560 | var a0 = Avx.LoadVector256(pA); 561 | var b0 = Avx.LoadVector256(pB); 562 | var sad0 = Avx2.SumAbsoluteDifferences(a0, b0); 563 | var a1 = Avx.LoadVector256(pA + 32); 564 | var b1 = Avx.LoadVector256(pB + 32); 565 | var sad1 = Avx2.SumAbsoluteDifferences(a1, b1); 566 | var diff = Avx2.Add(sad0.AsInt32(), sad1.AsInt32()); 567 | var diff2 = Sse2.Add(diff.GetLower(), diff.GetUpper()); 568 | return diff2.GetElement(0) + diff2.GetElement(2); 569 | } 570 | } 571 | 572 | public static unsafe ulong Sad(ReadOnlySpan a, ReadOnlySpan b) 573 | { 574 | var sad = Vector256.Zero; 575 | ulong result; 576 | fixed (byte* pA0 = a, pB0 = b) 577 | { 578 | int i; 579 | for (i = 0; i + 31 < a.Length; i += 32) 580 | { 581 | var a0 = Avx.LoadVector256(pA0 + i); 582 | var b0 = Avx.LoadVector256(pB0 + i); 583 | sad = Avx2.Add(sad, Avx2.SumAbsoluteDifferences(a0, b0).AsUInt64()); 584 | } 585 | 586 | var result2 = Sse2.Add(sad.GetLower(), sad.GetUpper()); 587 | result = result2.GetElement(0) + result2.GetElement(1); 588 | for (; i < a.Length; i++) 589 | result += (ulong)Math.Abs(pA0[i] - pB0[i]); 590 | } 591 | 592 | return result; 593 | } 594 | } 595 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/Vlc.cs: -------------------------------------------------------------------------------- 1 | using Gericom.FastVideoDS.Bitstream; 2 | 3 | namespace Gericom.FastVideoDS 4 | { 5 | public static class Vlc 6 | { 7 | public static readonly int[] BitLengthTable; 8 | 9 | static Vlc() 10 | { 11 | BitLengthTable = new int[2 * 64 * 128]; 12 | ushort[] tabA = VlcTables.TableA; 13 | byte[] tabB = VlcTables.TableB; 14 | for (int last = 0; last <= 1; last++) 15 | { 16 | for (int skip = 0; skip < 64; skip++) 17 | { 18 | for (int value = -64; value < 64; value++) 19 | { 20 | int val = value; 21 | if (val < 0) 22 | val = -val; 23 | if (val <= 31) 24 | { 25 | int idx = VlcTables.TableARefLinear[val * 64 * 2 + skip * 2 + last]; 26 | if (idx >= 0) 27 | { 28 | BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = tabA[idx] & 0xF; 29 | continue; 30 | } 31 | 32 | int newskip = skip - tabB[(val | (last << 6)) + 0x80]; 33 | if (newskip >= 0) 34 | { 35 | idx = VlcTables.TableARefLinear[val * 64 * 2 + newskip * 2 + last]; 36 | if (idx >= 0) 37 | { 38 | BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 9 + (tabA[idx] & 0xF); 39 | continue; 40 | } 41 | } 42 | } 43 | 44 | int newval = val - tabB[skip | (last << 6)]; 45 | if (newval >= 0 && newval <= 31) 46 | { 47 | int idx = VlcTables.TableARefLinear[newval * 64 * 2 + skip * 2 + last]; 48 | if (idx >= 0) 49 | { 50 | BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 8 + (tabA[idx] & 0xF); 51 | continue; 52 | } 53 | } 54 | 55 | BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 28; 56 | } 57 | } 58 | } 59 | } 60 | 61 | public static int CalcDctBitCount(int[] dct) 62 | { 63 | int lastNonZero = 0; 64 | for (int i = dct.Length - 1; i >= 0; i--) 65 | { 66 | if (dct[i] != 0) 67 | { 68 | lastNonZero = i; 69 | break; 70 | } 71 | } 72 | 73 | return CalcDctBitCount(dct, lastNonZero); 74 | } 75 | 76 | public static int CalcDctBitCount(int[] dct, int lastNonZero) 77 | { 78 | int bitCount = 0; 79 | 80 | int skip = 0; 81 | for (int i = 0; i < lastNonZero; i++) 82 | { 83 | if (dct[i] == 0) 84 | { 85 | skip++; 86 | continue; 87 | } 88 | 89 | int val = dct[i]; 90 | if (val + 64 < 128) 91 | bitCount += BitLengthTable[(skip * 128) + (val + 64)]; 92 | else 93 | bitCount += 28; 94 | skip = 0; 95 | } 96 | 97 | if (dct[lastNonZero] + 64 < 128) 98 | bitCount += BitLengthTable[128 * 64 + (skip * 128) + (dct[lastNonZero] + 64)]; 99 | else 100 | bitCount += 28; 101 | 102 | return bitCount; 103 | } 104 | 105 | public static void EncodeDct(int[] dct, BitWriter b) 106 | { 107 | ushort[] tabA = VlcTables.TableA; 108 | byte[] tabB = VlcTables.TableB; 109 | int lastNonZero = 0; 110 | for (int i = 0; i < dct.Length; i++) 111 | { 112 | if (dct[i] != 0) 113 | lastNonZero = i; 114 | } 115 | 116 | int skip = 0; 117 | for (int i = 0; i < dct.Length; i++) 118 | { 119 | if (dct[i] == 0 && lastNonZero != 0) 120 | { 121 | skip++; 122 | continue; 123 | } 124 | 125 | int val = dct[i]; 126 | 127 | if (val < 0) val = -val; 128 | if (val <= 31) 129 | { 130 | int idx = VlcTables.TableARefLinear[val * 64 * 2 + skip * 2 + ((i == lastNonZero) ? 1 : 0)]; 131 | if (idx >= 0) 132 | { 133 | int nrbits = (tabA[idx] & 0xF); 134 | uint tidx = (uint)idx; 135 | if (nrbits < 12) 136 | tidx >>= (12 - nrbits); 137 | else if (nrbits > 12) 138 | tidx <<= (nrbits - 12); 139 | if (dct[i] < 0) tidx |= 1; 140 | b.WriteBits((uint)tidx, nrbits); 141 | skip = 0; 142 | goto end; 143 | } 144 | 145 | int newskip = skip - tabB[(val | (((i == lastNonZero) ? 1 : 0) << 6)) + 0x80]; 146 | if (newskip >= 0) 147 | { 148 | idx = VlcTables.TableARefLinear[ 149 | val * 64 * 2 + newskip * 2 + 150 | ((i == lastNonZero) ? 1 : 0)]; 151 | if (idx >= 0) 152 | { 153 | b.WriteBits(3, 7); 154 | b.WriteBits(1, 1); 155 | b.WriteBits(0, 1); 156 | int nrbits = (tabA[idx] & 0xF); 157 | uint tidx = (uint)idx; 158 | if (nrbits < 12) 159 | tidx >>= (12 - nrbits); 160 | else if (nrbits > 12) 161 | tidx <<= (nrbits - 12); 162 | if (dct[i] < 0) tidx |= 1; 163 | b.WriteBits((uint)tidx, nrbits); 164 | skip = 0; 165 | goto end; 166 | } 167 | } 168 | } 169 | 170 | int newval = val - tabB[skip | (((i == lastNonZero) ? 1 : 0) << 6)]; 171 | if (newval >= 0 && newval <= 31) 172 | { 173 | int idx = VlcTables.TableARefLinear[newval * 64 * 2 + skip * 2 + ((i == lastNonZero) ? 1 : 0)]; 174 | if (idx >= 0) 175 | { 176 | b.WriteBits(3, 7); 177 | b.WriteBits(0, 1); 178 | int nrbits = (tabA[idx] & 0xF); 179 | uint tidx = (uint)idx; 180 | if (nrbits < 12) 181 | tidx >>= (12 - nrbits); 182 | else if (nrbits > 12) 183 | tidx <<= (nrbits - 12); 184 | if (dct[i] < 0) tidx |= 1; 185 | b.WriteBits((uint)tidx, nrbits); 186 | skip = 0; 187 | goto end; 188 | } 189 | } 190 | 191 | b.WriteBits(3, 7); 192 | b.WriteBits(1, 1); 193 | b.WriteBits(1, 1); 194 | if (i == lastNonZero) 195 | b.WriteBits(1, 1); 196 | else 197 | b.WriteBits(0, 1); 198 | b.WriteBits((uint)skip, 6); 199 | skip = 0; 200 | b.WriteBits((uint)dct[i], 12); 201 | end: 202 | if (i == lastNonZero) 203 | break; 204 | } 205 | } 206 | } 207 | } -------------------------------------------------------------------------------- /Gericom.FastVideoDS/VlcTables.cs: -------------------------------------------------------------------------------- 1 | namespace Gericom.FastVideoDS 2 | { 3 | public static class VlcTables 4 | { 5 | public static readonly ushort[] TableA = 6 | { 7 | 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x807C, 0x807C, 0x806C, 0x806C, 0x016C, 0x016C, 0x015C, 0x015C, 8 | 0x842B, 0x842B, 0x842B, 0x842B, 0x823B, 0x823B, 0x823B, 0x823B, 0x805B, 0x805B, 0x805B, 0x805B, 0x1A1B, 0x1A1B, 0x1A1B, 0x1A1B, 9 | 0x0A3B, 0x0A3B, 0x0A3B, 0x0A3B, 0x102B, 0x102B, 0x102B, 0x102B, 0x083B, 0x083B, 0x083B, 0x083B, 0x064B, 0x064B, 0x064B, 0x064B, 10 | 0x044B, 0x044B, 0x044B, 0x044B, 0x027B, 0x027B, 0x027B, 0x027B, 0x014B, 0x014B, 0x014B, 0x014B, 0x013B, 0x013B, 0x013B, 0x013B, 11 | 0x017C, 0x017C, 0x018C, 0x018C, 0x028C, 0x028C, 0x122C, 0x122C, 0x862C, 0x862C, 0x882C, 0x882C, 0x9E1C, 0x9E1C, 0xA01C, 0xA01C, 12 | 0x019D, 0x01AD, 0x01BD, 0x029D, 0x0C3D, 0x02AD, 0x045D, 0x0E3D, 0x1C1D, 0x808D, 0x8A2D, 0x8C2D, 0xA21D, 0xA41D, 0xA61D, 0xA81D, 13 | 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 14 | 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 15 | 0x012B, 0x012B, 0x012B, 0x012B, 0x011B, 0x011B, 0x011B, 0x011B, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 16 | 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 17 | 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 18 | 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 19 | 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 20 | 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 21 | 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 22 | 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 23 | 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 24 | 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 25 | 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 26 | 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 27 | 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 28 | 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 29 | 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 30 | 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 31 | 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 32 | 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 33 | 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 34 | 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 35 | 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 36 | 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 37 | 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 38 | 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 39 | 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 40 | 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 41 | 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 42 | 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 43 | 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 44 | 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 45 | 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 46 | 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 47 | 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 48 | 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 49 | 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 50 | 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 51 | 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 52 | 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 53 | 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 54 | 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 55 | 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 56 | 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 57 | 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 58 | 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 59 | 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 60 | 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 61 | 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 62 | 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 63 | 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 64 | 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 65 | 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 66 | 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 67 | 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 68 | 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 69 | 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 70 | 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 71 | 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 72 | 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 73 | 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 74 | 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 75 | 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 76 | 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 77 | 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 78 | 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 79 | 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 80 | 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 81 | 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 82 | 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 83 | 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 84 | 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 85 | 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 86 | 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 87 | 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 88 | 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 89 | 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 90 | 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 91 | 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 92 | 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 93 | 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 94 | 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 95 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 96 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 97 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 98 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 99 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 100 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 101 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 102 | 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 103 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 104 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 105 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 106 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 107 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 108 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 109 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 110 | 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 111 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 112 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 113 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 114 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 115 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 116 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 117 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 118 | 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 119 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 120 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 121 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 122 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 123 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 124 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 125 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 126 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 127 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 128 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 129 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 130 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 131 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 132 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 133 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 134 | 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 135 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 136 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 137 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 138 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 139 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 140 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 141 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 142 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 143 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 144 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 145 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 146 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 147 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 148 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 149 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 150 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 151 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 152 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 153 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 154 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 155 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 156 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 157 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 158 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 159 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 160 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 161 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 162 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 163 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 164 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 165 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 166 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 167 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 168 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 169 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 170 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 171 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 172 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 173 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 174 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 175 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 176 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 177 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 178 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 179 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 180 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 181 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 182 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 183 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 184 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 185 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 186 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 187 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 188 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 189 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 190 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 191 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 192 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 193 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 194 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 195 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 196 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 197 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 198 | 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 199 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 200 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 201 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 202 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 203 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 204 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 205 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 206 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 207 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 208 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 209 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 210 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 211 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 212 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 213 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 214 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 215 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 216 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 217 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 218 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 219 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 220 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 221 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 222 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 223 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 224 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 225 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 226 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 227 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 228 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 229 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 230 | 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 231 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 232 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 233 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 234 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 235 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 236 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 237 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 238 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 239 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 240 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 241 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 242 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 243 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 244 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 245 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 246 | 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 247 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 248 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 249 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 250 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 251 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 252 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 253 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 254 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 255 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 256 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 257 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 258 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 259 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 260 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 261 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 262 | 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035 263 | }; 264 | 265 | public static readonly byte[] TableB = 266 | { 267 | 0x1B, 0x0A, 0x05, 0x04, 268 | 0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 270 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 271 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 272 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 273 | 0x08, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 274 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 275 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 276 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 277 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 278 | 0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x0A, 0x08, 0x04, 0x03, 0x02, 0x02, 279 | 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 280 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 281 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 282 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 283 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x15, 0x07, 0x02, 284 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 285 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 286 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 287 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 288 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 289 | }; 290 | 291 | public static readonly int[] TableARefLinear = 292 | { 293 | 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 294 | 2048, 1792, 3584, 960, 1408, 896, 1088, 544, 1024, 512, 832, 608, 576, 336, 640, 320, 400, 304, 384, 416, 368, 168, 200, 160, 192, 152, 28, 144, 88, 136, -1, 76, -1, 78, -1, 92, -1, 93, -1, 94, -1, 95, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 295 | 3072, 768, 1280, 176, 672, 16, 432, 72, 272, 74, 224, 90, 216, 91, 208, -1, 36, -1, 70, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 296 | 3840, 352, 704, 20, 240, -1, 232, -1, 40, -1, 32, -1, 84, -1, 87, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 297 | 1664, 184, 448, -1, 48, -1, 44, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 298 | 1536, 24, 256, -1, 86, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 299 | 1344, 10, 248, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 300 | 1216, 8, 52, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 301 | 1152, 89, 68, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 302 | 736, -1, 83, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 303 | 496, -1, 85, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 304 | 480, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 305 | 464, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 306 | 296, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 307 | 288, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 308 | 280, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 309 | 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 310 | 132, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 311 | 128, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 312 | 60, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 313 | 56, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 314 | 14, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 315 | 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 316 | 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 317 | 66, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 318 | 80, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 319 | 81, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 320 | 82, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 321 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 322 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 323 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 324 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 325 | }; 326 | } 327 | } 328 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | FastVideoDS Encoder 2 | =================== 3 | Encoder for the FastVideoDS format. Use [FastVideoDS Player](https://github.com/Gericom/FastVideoDSPlayer) to play back the encoded videos. 4 | 5 | ## Usage 6 | FastVideoDSEncoder [-j jobs] input output.fv 7 | 8 | * **-j *jobs*** Number of concurrent jobs (optional, default: cpu threads / 1.5) 9 | * ***input*** The input video file. Most formats are supported through FFmpeg. 10 | * ***output.fv*** The output video file. 11 | 12 | ## Libraries Used 13 | * [CommandLineParser](https://github.com/commandlineparser/commandline) 14 | * [FFmpeg.AutoGen](https://github.com/Ruslan-B/FFmpeg.AutoGen) 15 | * [FFmpeg](https://ffmpeg.org/) --------------------------------------------------------------------------------