mirror of
https://github.com/Gericom/FastVideoDSEncoder.git
synced 2025-06-18 10:45:33 -04:00
Initial commit
This commit is contained in:
commit
9aa251ee1d
63
.gitattributes
vendored
Normal file
63
.gitattributes
vendored
Normal file
@ -0,0 +1,63 @@
|
||||
###############################################################################
|
||||
# Set default behavior to automatically normalize line endings.
|
||||
###############################################################################
|
||||
* text=auto
|
||||
|
||||
###############################################################################
|
||||
# Set default behavior for command prompt diff.
|
||||
#
|
||||
# This is need for earlier builds of msysgit that does not have it on by
|
||||
# default for csharp files.
|
||||
# Note: This is only used by command line
|
||||
###############################################################################
|
||||
#*.cs diff=csharp
|
||||
|
||||
###############################################################################
|
||||
# Set the merge driver for project and solution files
|
||||
#
|
||||
# Merging from the command prompt will add diff markers to the files if there
|
||||
# are conflicts (Merging from VS is not affected by the settings below, in VS
|
||||
# the diff markers are never inserted). Diff markers may cause the following
|
||||
# file extensions to fail to load in VS. An alternative would be to treat
|
||||
# these files as binary and thus will always conflict and require user
|
||||
# intervention with every merge. To do so, just uncomment the entries below
|
||||
###############################################################################
|
||||
#*.sln merge=binary
|
||||
#*.csproj merge=binary
|
||||
#*.vbproj merge=binary
|
||||
#*.vcxproj merge=binary
|
||||
#*.vcproj merge=binary
|
||||
#*.dbproj merge=binary
|
||||
#*.fsproj merge=binary
|
||||
#*.lsproj merge=binary
|
||||
#*.wixproj merge=binary
|
||||
#*.modelproj merge=binary
|
||||
#*.sqlproj merge=binary
|
||||
#*.wwaproj merge=binary
|
||||
|
||||
###############################################################################
|
||||
# behavior for image files
|
||||
#
|
||||
# image files are treated as binary by default.
|
||||
###############################################################################
|
||||
#*.jpg binary
|
||||
#*.png binary
|
||||
#*.gif binary
|
||||
|
||||
###############################################################################
|
||||
# diff behavior for common document formats
|
||||
#
|
||||
# Convert binary document formats to text before diffing them. This feature
|
||||
# is only available from the command line. Turn it on by uncommenting the
|
||||
# entries below.
|
||||
###############################################################################
|
||||
#*.doc diff=astextplain
|
||||
#*.DOC diff=astextplain
|
||||
#*.docx diff=astextplain
|
||||
#*.DOCX diff=astextplain
|
||||
#*.dot diff=astextplain
|
||||
#*.DOT diff=astextplain
|
||||
#*.pdf diff=astextplain
|
||||
#*.PDF diff=astextplain
|
||||
#*.rtf diff=astextplain
|
||||
#*.RTF diff=astextplain
|
365
.gitignore
vendored
Normal file
365
.gitignore
vendored
Normal file
@ -0,0 +1,365 @@
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Mono auto generated files
|
||||
mono_crash.*
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Ww][Ii][Nn]32/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Oo]ut/
|
||||
[Ll]og/
|
||||
[Ll]ogs/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUnit
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
nunit-*.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# ASP.NET Scaffolding
|
||||
ScaffoldingReadMe.txt
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Coverlet is a free, cross platform Code Coverage Tool
|
||||
coverage*.json
|
||||
coverage*.xml
|
||||
coverage*.info
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# NuGet Symbol Packages
|
||||
*.snupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
*.appxbundle
|
||||
*.appxupload
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- [Bb]ackup.rdl
|
||||
*- [Bb]ackup ([0-9]).rdl
|
||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
|
||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||
MigrationBackup/
|
||||
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
|
||||
!FastVideoDSEncoder/x64/
|
37
FastVideoDS.sln
Normal file
37
FastVideoDS.sln
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.2.32505.173
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gericom.FastVideoDS", "Gericom.FastVideoDS\Gericom.FastVideoDS.csproj", "{AC320DAA-A040-4654-A4F2-238224723834}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastVideoDSEncoder", "FastVideoDSEncoder\FastVideoDSEncoder.csproj", "{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FastVideoDSInfo", "FastVideoDSInfo\FastVideoDSInfo.csproj", "{BC08ACC4-8B61-4801-8532-D5D054795809}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{AC320DAA-A040-4654-A4F2-238224723834}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AC320DAA-A040-4654-A4F2-238224723834}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AC320DAA-A040-4654-A4F2-238224723834}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC320DAA-A040-4654-A4F2-238224723834}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6D06AE63-9EB8-4FFA-891C-455CB95A23BD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BC08ACC4-8B61-4801-8532-D5D054795809}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BC08ACC4-8B61-4801-8532-D5D054795809}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BC08ACC4-8B61-4801-8532-D5D054795809}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BC08ACC4-8B61-4801-8532-D5D054795809}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {35CAC4B4-A8ED-4DBA-941D-7E4438178987}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
188
FastVideoDSEncoder/Adpcm.cs
Normal file
188
FastVideoDSEncoder/Adpcm.cs
Normal file
@ -0,0 +1,188 @@
|
||||
using System;
|
||||
|
||||
namespace Gericom.FastVideoDSEncoder
|
||||
{
|
||||
public static class Adpcm
|
||||
{
|
||||
private static readonly int[] IndexTable =
|
||||
{
|
||||
-3, -3, -2, -1, 2, 4, 6, 8,
|
||||
-3, -3, -2, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
private static readonly short[] StepTable =
|
||||
{
|
||||
7, 8, 9, 10, 11, 12, 13, 14,
|
||||
16, 17, 19, 21, 23, 25, 28,
|
||||
31, 34, 37, 41, 45, 50, 55,
|
||||
60, 66, 73, 80, 88, 97, 107,
|
||||
118, 130, 143, 157, 173, 190, 209,
|
||||
230, 253, 279, 307, 337, 371, 408,
|
||||
449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552,
|
||||
1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026,
|
||||
4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
|
||||
9493, 10442, 11487, 12635, 13899, 15289, 16818,
|
||||
18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
public record AdpcmState(short LastSample, int LastIdx);
|
||||
|
||||
private static int GetBestTableIndex(int diff)
|
||||
{
|
||||
int lowestDiff = int.MaxValue;
|
||||
int lowestIdx = -1;
|
||||
for (int i = 0; i < StepTable.Length; i++)
|
||||
{
|
||||
int diff2 = Math.Abs(Math.Abs(diff) - StepTable[i]);
|
||||
if (diff2 < lowestDiff)
|
||||
{
|
||||
lowestDiff = diff2;
|
||||
lowestIdx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return lowestIdx;
|
||||
}
|
||||
|
||||
public static byte[] Encode(ReadOnlySpan<short> samples)
|
||||
=> Encode(samples, null, true).data;
|
||||
|
||||
public static (byte[] data, AdpcmState lastState) Encode(ReadOnlySpan<short> samples, AdpcmState state,
|
||||
bool emitHeader)
|
||||
{
|
||||
if ((samples.Length & 7) != 0)
|
||||
throw new Exception("Samples should be a multiple of 8");
|
||||
var result = new byte[4 + samples.Length / 2];
|
||||
var resultSpan = result.AsSpan();
|
||||
int idx;
|
||||
short last;
|
||||
if (state == null)
|
||||
{
|
||||
if (!emitHeader)
|
||||
throw new ArgumentException(nameof(emitHeader));
|
||||
idx = Math.Min(GetBestTableIndex(samples[1] - samples[0]) + 3, 88);
|
||||
last = (short)Math.Max(-0x7FFF, samples[0] - StepTable[idx] / 8);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = state.LastIdx;
|
||||
last = state.LastSample;
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
if (emitHeader)
|
||||
{
|
||||
resultSpan.WriteLe<short>(0, last);
|
||||
resultSpan.WriteLe<ushort>(2, (ushort)idx);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
int error = 0;
|
||||
for (int i = 0; i < samples.Length; i += 8)
|
||||
{
|
||||
uint nibbles = 0;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
int step = StepTable[idx];
|
||||
int sample = samples[i + j];
|
||||
|
||||
int best = -1;
|
||||
int bestScore = int.MaxValue;
|
||||
for (int k = 0; k < 16; k++)
|
||||
{
|
||||
int diff2 = (step * ((k & 7) * 2 + 1)) >> 3;
|
||||
int sample3 = last + diff2 * (((k >> 3) & 1) == 1 ? -1 : 1);
|
||||
if (sample3 < -0x7FFF)
|
||||
sample3 = -0x7FFF;
|
||||
if (sample3 > 0x7FFF)
|
||||
sample3 = 0x7FFF;
|
||||
int score = Math.Abs(sample3 - sample);
|
||||
if (i + j + 1 < samples.Length)
|
||||
{
|
||||
int step2 = StepTable[Math.Clamp(idx + IndexTable[k], 0, 88)];
|
||||
int bestScore2 = int.MaxValue;
|
||||
for (int l = 0; l < 16; l++)
|
||||
{
|
||||
int diff3 = (step2 * ((l & 7) * 2 + 1)) >> 3;
|
||||
int sample4 = sample3 + diff3 * (((l >> 3) & 1) == 1 ? -1 : 1);
|
||||
if (sample4 < -0x7FFF)
|
||||
sample4 = -0x7FFF;
|
||||
if (sample4 > 0x7FFF)
|
||||
sample4 = 0x7FFF;
|
||||
int score2 = Math.Abs(sample4 - samples[i + j + 1]);
|
||||
if (score2 < bestScore2)
|
||||
bestScore2 = score2;
|
||||
}
|
||||
|
||||
score += bestScore2;
|
||||
}
|
||||
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestScore = score;
|
||||
best = k;
|
||||
}
|
||||
}
|
||||
|
||||
nibbles |= (uint)best << (j * 4);
|
||||
|
||||
int diff = (step * ((best & 7) * 2 + 1)) >> 3;
|
||||
int sample2 = last + diff * (((best >> 3) & 1) == 1 ? -1 : 1);
|
||||
if (sample2 < -0x7FFF)
|
||||
sample2 = -0x7FFF;
|
||||
if (sample2 > 0x7FFF)
|
||||
sample2 = 0x7FFF;
|
||||
last = (short)sample2;
|
||||
idx += IndexTable[best];
|
||||
if (idx < 0)
|
||||
idx = 0;
|
||||
if (idx > 88)
|
||||
idx = 88;
|
||||
}
|
||||
|
||||
resultSpan.WriteLe<uint>(offset, nibbles);
|
||||
offset += 4;
|
||||
}
|
||||
|
||||
return (result, new(last, idx));
|
||||
}
|
||||
|
||||
public static short[] Decode(ReadOnlySpan<byte> samples)
|
||||
{
|
||||
if ((samples.Length & 3) != 0)
|
||||
throw new Exception("Samples should be a multiple of 4 bytes");
|
||||
var outSamples = new short[(samples.Length - 4) * 2];
|
||||
short last = samples.ReadLe<short>(0);
|
||||
int idx = samples.ReadLe<ushort>(2);
|
||||
int offset = 4;
|
||||
for (int i = 0; i < outSamples.Length; i += 8)
|
||||
{
|
||||
uint nibbles = samples.ReadLe<uint>(offset);
|
||||
offset += 4;
|
||||
for (int j = 0; j < 8; j++)
|
||||
{
|
||||
uint nibble = nibbles & 0xF;
|
||||
nibbles >>= 4;
|
||||
int diff = (int)((StepTable[idx] * ((nibble & 7) * 2 + 1)) >> 3);
|
||||
|
||||
int sample = last + diff * (((nibble >> 3) & 1) == 1 ? -1 : 1);
|
||||
|
||||
if (sample < -0x7FFF)
|
||||
sample = -0x7FFF;
|
||||
if (sample > 0x7FFF)
|
||||
sample = 0x7FFF;
|
||||
outSamples[i + j] = (short)sample;
|
||||
last = (short)sample;
|
||||
idx += IndexTable[nibble];
|
||||
if (idx < 0)
|
||||
idx = 0;
|
||||
if (idx > 88)
|
||||
idx = 88;
|
||||
}
|
||||
}
|
||||
|
||||
return outSamples;
|
||||
}
|
||||
}
|
||||
}
|
468
FastVideoDSEncoder/FFMpegDecoder.cs
Normal file
468
FastVideoDSEncoder/FFMpegDecoder.cs
Normal file
@ -0,0 +1,468 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using FFmpeg.AutoGen;
|
||||
using Gericom.FastVideoDS.Frames;
|
||||
using static FFmpeg.AutoGen.ffmpeg;
|
||||
|
||||
namespace Gericom.FastVideoDSEncoder
|
||||
{
|
||||
public unsafe class FFMpegDecoder : IDisposable
|
||||
{
|
||||
public const int StreamAuto = -1;
|
||||
public const int NoStream = -2;
|
||||
|
||||
private AVFormatContext* _formatContext;
|
||||
private AVCodecContext* _videoDecContext;
|
||||
private AVCodecContext* _audioDecContext;
|
||||
private SwsContext* _swsContext;
|
||||
private SwrContext* _swrContext;
|
||||
private AVPacket* _packet;
|
||||
private AVFrame* _frame;
|
||||
|
||||
private readonly byte* _rgbData;
|
||||
|
||||
private readonly Queue<RefFrame> _frameQueue = new();
|
||||
private readonly FramePool _framePool;
|
||||
private readonly short[] _leftBuffer = new short[2 * 48000];
|
||||
private readonly short[] _rightBuffer = new short[2 * 48000];
|
||||
private int _audioSampleCount;
|
||||
private int _audioReadOffset;
|
||||
private int _audioWriteOffset;
|
||||
|
||||
private long _curVideoPts = -1;
|
||||
private long _curAudioPts = -1;
|
||||
|
||||
public long FirstVideoPts { get; private set; } = -1;
|
||||
public long FirstAudioPktPos { get; private set; } = -1;
|
||||
|
||||
public long MaxAudioPktPos { get; set; } = -1;
|
||||
|
||||
public int VideoStreamId { get; }
|
||||
public int AudioStreamId { get; }
|
||||
|
||||
public int FrameHeight { get; private set; }
|
||||
|
||||
static FFMpegDecoder()
|
||||
{
|
||||
ffmpeg.RootPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "x64");
|
||||
}
|
||||
|
||||
public FFMpegDecoder(string srcPath, long startPts = 0, int videoStreamId = -1, int audioStreamId = -1)
|
||||
{
|
||||
AVFormatContext* formatContext = null;
|
||||
if (avformat_open_input(&formatContext, srcPath, null, null) < 0)
|
||||
throw new Exception("avformat_open_input error");
|
||||
|
||||
_formatContext = formatContext;
|
||||
|
||||
if (avformat_find_stream_info(_formatContext, null) < 0)
|
||||
throw new Exception("avformat_find_stream_info error");
|
||||
|
||||
if (videoStreamId >= 0 &&
|
||||
(videoStreamId >= formatContext->nb_streams ||
|
||||
formatContext->streams[videoStreamId]->codecpar->codec_type != AVMediaType.AVMEDIA_TYPE_VIDEO))
|
||||
throw new ArgumentException(nameof(videoStreamId));
|
||||
|
||||
if (audioStreamId >= 0 &&
|
||||
(audioStreamId >= formatContext->nb_streams ||
|
||||
formatContext->streams[audioStreamId]->codecpar->codec_type != AVMediaType.AVMEDIA_TYPE_AUDIO))
|
||||
throw new ArgumentException(nameof(audioStreamId));
|
||||
|
||||
for (int i = 0; i < formatContext->nb_streams; i++)
|
||||
{
|
||||
var codecType = formatContext->streams[i]->codecpar->codec_type;
|
||||
|
||||
if (videoStreamId != NoStream && videoStreamId < 0 && codecType == AVMediaType.AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
videoStreamId = i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (audioStreamId != NoStream && audioStreamId < 0 && codecType == AVMediaType.AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
audioStreamId = i;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (videoStreamId != NoStream && videoStreamId < 0)
|
||||
throw new Exception("No video stream found");
|
||||
|
||||
if (audioStreamId != NoStream && audioStreamId < 0)
|
||||
throw new Exception("No audio stream found");
|
||||
|
||||
VideoStreamId = videoStreamId;
|
||||
AudioStreamId = audioStreamId;
|
||||
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
AVCodec* videoDec = avcodec_find_decoder(_formatContext->streams[VideoStreamId]->codecpar->codec_id);
|
||||
_videoDecContext = avcodec_alloc_context3(videoDec);
|
||||
avcodec_parameters_to_context(_videoDecContext, _formatContext->streams[VideoStreamId]->codecpar);
|
||||
avcodec_open2(_videoDecContext, videoDec, null);
|
||||
}
|
||||
|
||||
if (AudioStreamId != NoStream)
|
||||
{
|
||||
AVCodec* audioDec = avcodec_find_decoder(_formatContext->streams[AudioStreamId]->codecpar->codec_id);
|
||||
_audioDecContext = avcodec_alloc_context3(audioDec);
|
||||
avcodec_parameters_to_context(_audioDecContext, _formatContext->streams[AudioStreamId]->codecpar);
|
||||
avcodec_open2(_audioDecContext, audioDec, null);
|
||||
}
|
||||
|
||||
if (startPts != 0 && VideoStreamId != NoStream)
|
||||
{
|
||||
if (av_seek_frame(_formatContext, VideoStreamId, startPts, 0) < 0)
|
||||
throw new Exception("av_seek_frame failed");
|
||||
avcodec_flush_buffers(_videoDecContext);
|
||||
|
||||
if (AudioStreamId != NoStream)
|
||||
avcodec_flush_buffers(_audioDecContext);
|
||||
}
|
||||
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
var aspect = _videoDecContext->sample_aspect_ratio;
|
||||
if (aspect.num == 0 && aspect.den == 1)
|
||||
aspect.num = 1;
|
||||
|
||||
FrameHeight = (int)Math.Round(_videoDecContext->height * 256.0 / _videoDecContext->width * aspect.den /
|
||||
aspect.num);
|
||||
|
||||
int mod8 = FrameHeight & 7;
|
||||
if (mod8 != 0)
|
||||
{
|
||||
FrameHeight &= ~7;
|
||||
if (mod8 >= 4)
|
||||
FrameHeight += 8;
|
||||
}
|
||||
|
||||
_framePool = new FramePool(256, FrameHeight);
|
||||
|
||||
_swsContext = sws_getContext(_videoDecContext->width, _videoDecContext->height,
|
||||
_videoDecContext->pix_fmt,
|
||||
256, FrameHeight, AVPixelFormat.AV_PIX_FMT_BGRA,
|
||||
SWS_LANCZOS | SWS_FULL_CHR_H_INT | SWS_FULL_CHR_H_INP | SWS_ACCURATE_RND, null, null, null);
|
||||
}
|
||||
|
||||
_packet = av_packet_alloc();
|
||||
_frame = av_frame_alloc();
|
||||
|
||||
_audioSampleCount = 0;
|
||||
_audioReadOffset = 0;
|
||||
_audioWriteOffset = 0;
|
||||
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
_rgbData = (byte*)NativeMemory.AlignedAlloc(256 * 192 * 4, 16);
|
||||
|
||||
while (FirstVideoPts == -1 && PumpData()) ;
|
||||
}
|
||||
|
||||
if (AudioStreamId != NoStream)
|
||||
{
|
||||
while (FirstAudioPktPos == -1 && PumpData()) ;
|
||||
}
|
||||
}
|
||||
|
||||
public AVRational GetFrameRate()
|
||||
{
|
||||
var rate = _formatContext->streams[VideoStreamId]->r_frame_rate;
|
||||
// if (rate.num == 50 && rate.den == 1 && _formatContext->streams[VideoStreamId]->codecpar->field_order !=
|
||||
// AVFieldOrder.AV_FIELD_PROGRESSIVE)
|
||||
// rate.num = 25;
|
||||
return rate;
|
||||
// return _formatContext->streams[VideoStreamId]->r_frame_rate;
|
||||
}
|
||||
|
||||
public AVRational GetVideoTimeBase()
|
||||
{
|
||||
return _formatContext->streams[VideoStreamId]->time_base;
|
||||
}
|
||||
|
||||
public long GetDuration()
|
||||
{
|
||||
if (_formatContext->streams[VideoStreamId]->duration <= 0)
|
||||
return _formatContext->duration * _formatContext->streams[VideoStreamId]->time_base.den /
|
||||
((long)AV_TIME_BASE * _formatContext->streams[VideoStreamId]->time_base.num);
|
||||
|
||||
return _formatContext->streams[VideoStreamId]->duration;
|
||||
}
|
||||
|
||||
public int GetAudioRate()
|
||||
{
|
||||
return 47605; //_formatContext->streams[AudioStreamId]->codecpar->sample_rate;
|
||||
}
|
||||
|
||||
private bool ReceiveVideoFrame()
|
||||
{
|
||||
if (avcodec_receive_frame(_videoDecContext, _frame) < 0)
|
||||
return false;
|
||||
|
||||
if (_frame->best_effort_timestamp <= _curVideoPts)
|
||||
{
|
||||
av_frame_unref(_frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FirstVideoPts == -1)
|
||||
FirstVideoPts = _frame->best_effort_timestamp;
|
||||
|
||||
_curVideoPts = _frame->best_effort_timestamp;
|
||||
|
||||
// fixed (byte* pRgb = _rgbData)
|
||||
// {
|
||||
sws_scale(_swsContext, _frame->data, _frame->linesize, 0,
|
||||
_videoDecContext->height, new[] { _rgbData }, new[] { 256 * 4 });
|
||||
|
||||
var refFrame = _framePool.AcquireFrame();
|
||||
|
||||
refFrame.Frame.FromRgba32(_rgbData, 256 * 4);
|
||||
_frameQueue.Enqueue(refFrame);
|
||||
// if(_frame->interlaced_frame != 0)
|
||||
// _frameQueue.Enqueue(RGB555Frame.FromRgba32(pRgb, 256, FrameHeight, 256 * 4));
|
||||
// }
|
||||
|
||||
av_frame_unref(_frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool ReceiveAudioFrame()
|
||||
{
|
||||
if (avcodec_receive_frame(_audioDecContext, _frame) < 0)
|
||||
return false;
|
||||
|
||||
if (_frame->best_effort_timestamp <= _curAudioPts)
|
||||
{
|
||||
av_frame_unref(_frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (MaxAudioPktPos != -1 && _frame->pkt_pos >= MaxAudioPktPos)
|
||||
{
|
||||
av_frame_unref(_frame);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FirstAudioPktPos == -1)
|
||||
FirstAudioPktPos = _frame->pkt_pos;
|
||||
|
||||
_curAudioPts = _frame->best_effort_timestamp;
|
||||
|
||||
if (_swrContext == null)
|
||||
{
|
||||
var inChLayout = &_frame->ch_layout;
|
||||
AVChannelLayout outChLayout;
|
||||
av_channel_layout_from_mask(&outChLayout, AV_CH_LAYOUT_STEREO);
|
||||
// if (chLayout == 0)
|
||||
// chLayout = av_get_default_channel_layout(_frame->channels);
|
||||
fixed (SwrContext** swr = &_swrContext)
|
||||
{
|
||||
int result = swr_alloc_set_opts2(swr,
|
||||
&outChLayout, AVSampleFormat.AV_SAMPLE_FMT_S16P, 47605,
|
||||
inChLayout, _audioDecContext->sample_fmt, _frame->sample_rate,
|
||||
0, null);
|
||||
if (result < 0)
|
||||
throw new Exception("swr_alloc_set_opts2 error");
|
||||
}
|
||||
|
||||
swr_init(_swrContext);
|
||||
}
|
||||
|
||||
byte** outBufs = stackalloc byte*[2];
|
||||
int outSamples = (int)av_rescale_rnd(
|
||||
swr_get_delay(_swrContext, _frame->sample_rate) + _frame->nb_samples, 47605,
|
||||
_frame->sample_rate, AVRounding.AV_ROUND_UP);
|
||||
|
||||
if (_audioWriteOffset + outSamples <= _leftBuffer.Length)
|
||||
{
|
||||
fixed (short* leftPtr = _leftBuffer, rightPtr = _rightBuffer)
|
||||
{
|
||||
outBufs[0] = (byte*)&leftPtr[_audioWriteOffset];
|
||||
outBufs[1] = (byte*)&rightPtr[_audioWriteOffset];
|
||||
outSamples = swr_convert(_swrContext, outBufs, outSamples, (byte**)&_frame->data,
|
||||
_frame->nb_samples);
|
||||
if (outSamples < 0)
|
||||
throw new Exception("swr_convert error");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var leftBuf = new short[outSamples];
|
||||
var rightBuf = new short[outSamples];
|
||||
fixed (short* leftPtr = leftBuf, rightPtr = rightBuf)
|
||||
{
|
||||
outBufs[0] = (byte*)leftPtr;
|
||||
outBufs[1] = (byte*)rightPtr;
|
||||
outSamples = swr_convert(_swrContext, outBufs, outSamples, (byte**)&_frame->data,
|
||||
_frame->nb_samples);
|
||||
if (outSamples < 0)
|
||||
throw new Exception("swr_convert error");
|
||||
}
|
||||
|
||||
int firstHalf = _leftBuffer.Length - _audioWriteOffset;
|
||||
if (firstHalf > outSamples)
|
||||
firstHalf = outSamples;
|
||||
Array.Copy(leftBuf, 0, _leftBuffer, _audioWriteOffset, firstHalf);
|
||||
Array.Copy(rightBuf, 0, _rightBuffer, _audioWriteOffset, firstHalf);
|
||||
if (firstHalf != outSamples)
|
||||
{
|
||||
int secondHalf = outSamples - firstHalf;
|
||||
Array.Copy(leftBuf, firstHalf, _leftBuffer, 0, secondHalf);
|
||||
Array.Copy(rightBuf, firstHalf, _rightBuffer, 0, secondHalf);
|
||||
}
|
||||
}
|
||||
|
||||
_audioWriteOffset += outSamples;
|
||||
if (_audioWriteOffset >= _leftBuffer.Length)
|
||||
_audioWriteOffset -= _leftBuffer.Length;
|
||||
|
||||
_audioSampleCount += outSamples;
|
||||
if (_audioSampleCount > _leftBuffer.Length)
|
||||
throw new Exception("Audio buffer overflow!");
|
||||
|
||||
av_frame_unref(_frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool PumpData()
|
||||
{
|
||||
int ret = av_read_frame(_formatContext, _packet);
|
||||
if (ret == AVERROR_EOF)
|
||||
{
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
while (ReceiveVideoFrame()) ;
|
||||
}
|
||||
|
||||
if (AudioStreamId != NoStream)
|
||||
{
|
||||
while (ReceiveAudioFrame()) ;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_packet->stream_index == VideoStreamId)
|
||||
{
|
||||
avcodec_send_packet(_videoDecContext, _packet);
|
||||
ReceiveVideoFrame();
|
||||
}
|
||||
else if (_packet->stream_index == AudioStreamId)
|
||||
{
|
||||
avcodec_send_packet(_audioDecContext, _packet);
|
||||
ReceiveAudioFrame();
|
||||
}
|
||||
|
||||
av_packet_unref(_packet);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public RefFrame GetNextFrame()
|
||||
{
|
||||
if (VideoStreamId == NoStream)
|
||||
return null;
|
||||
|
||||
while (_frameQueue.Count == 0)
|
||||
{
|
||||
if (!PumpData())
|
||||
{
|
||||
if (_frameQueue.Count == 0)
|
||||
return null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _frameQueue.Dequeue();
|
||||
}
|
||||
|
||||
public int GetAudioSamples(short[] leftDst, short[] rightDst, int count)
|
||||
{
|
||||
if (AudioStreamId == NoStream)
|
||||
return 0;
|
||||
|
||||
if (count > _leftBuffer.Length)
|
||||
throw new Exception("Requesting too much audio data");
|
||||
|
||||
while (_audioSampleCount < count)
|
||||
{
|
||||
if (!PumpData())
|
||||
{
|
||||
count = _audioSampleCount;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (_audioReadOffset + count <= _leftBuffer.Length)
|
||||
{
|
||||
Array.Copy(_leftBuffer, _audioReadOffset, leftDst, 0, count);
|
||||
Array.Copy(_rightBuffer, _audioReadOffset, rightDst, 0, count);
|
||||
}
|
||||
else
|
||||
{
|
||||
int firstHalf = _leftBuffer.Length - _audioReadOffset;
|
||||
Array.Copy(_leftBuffer, _audioReadOffset, leftDst, 0, firstHalf);
|
||||
Array.Copy(_rightBuffer, _audioReadOffset, rightDst, 0, firstHalf);
|
||||
int secondHalf = count - firstHalf;
|
||||
Array.Copy(_leftBuffer, 0, leftDst, firstHalf, secondHalf);
|
||||
Array.Copy(_rightBuffer, 0, rightDst, firstHalf, secondHalf);
|
||||
}
|
||||
|
||||
_audioReadOffset += count;
|
||||
if (_audioReadOffset >= _leftBuffer.Length)
|
||||
_audioReadOffset -= _leftBuffer.Length;
|
||||
_audioSampleCount -= count;
|
||||
return count;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
fixed (AVPacket** packet = &_packet)
|
||||
av_packet_free(packet);
|
||||
fixed (AVFrame** frame = &_frame)
|
||||
av_frame_free(frame);
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
sws_freeContext(_swsContext);
|
||||
_swsContext = null;
|
||||
}
|
||||
|
||||
if (AudioStreamId != NoStream && _swrContext != null)
|
||||
{
|
||||
fixed (SwrContext** swrContext = &_swrContext)
|
||||
swr_free(swrContext);
|
||||
}
|
||||
|
||||
if (AudioStreamId != NoStream)
|
||||
{
|
||||
avcodec_close(_audioDecContext);
|
||||
fixed (AVCodecContext** audioDecContext = &_audioDecContext)
|
||||
avcodec_free_context(audioDecContext);
|
||||
}
|
||||
|
||||
if (VideoStreamId != NoStream)
|
||||
{
|
||||
avcodec_close(_videoDecContext);
|
||||
fixed (AVCodecContext** videoDecContext = &_videoDecContext)
|
||||
avcodec_free_context(videoDecContext);
|
||||
}
|
||||
|
||||
fixed (AVFormatContext** formatContext = &_formatContext)
|
||||
avformat_close_input(formatContext);
|
||||
|
||||
if (_rgbData != null)
|
||||
NativeMemory.AlignedFree(_rgbData);
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
~FFMpegDecoder()
|
||||
{
|
||||
if (_rgbData != null)
|
||||
NativeMemory.AlignedFree(_rgbData);
|
||||
}
|
||||
}
|
||||
}
|
87
FastVideoDSEncoder/FastVideoDSEncoder.csproj
Normal file
87
FastVideoDSEncoder/FastVideoDSEncoder.csproj
Normal file
@ -0,0 +1,87 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<Authors>Gericom</Authors>
|
||||
<Product>FastVideoDS Encoder</Product>
|
||||
<Nullable>disable</Nullable>
|
||||
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
|
||||
<RootNamespace>Gericom.FastVideoDSEncoder</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageReference Include="FFmpeg.AutoGen" Version="5.1.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Gericom.FastVideoDS\Gericom.FastVideoDS.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="x64\" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="x64\avcodec-58.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avcodec-59.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avdevice-58.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avdevice-59.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avfilter-7.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avfilter-8.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avformat-58.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avformat-59.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avutil-56.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\avutil-57.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\postproc-55.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\postproc-56.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\swresample-3.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\swresample-4.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\swscale-5.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="x64\swscale-6.dll">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
323
FastVideoDSEncoder/FvEncoder.cs
Normal file
323
FastVideoDSEncoder/FvEncoder.cs
Normal file
@ -0,0 +1,323 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Gericom.FastVideoDSEncoder
|
||||
{
|
||||
public class FvEncoder
|
||||
{
|
||||
private const int AudioFrameSize = 256;
|
||||
|
||||
public volatile int[] JobProgess;
|
||||
|
||||
public List<(int frame, uint offset)>[] JobKeyFrames;
|
||||
|
||||
public uint[] JobFileSize;
|
||||
|
||||
public int MaxGopLength = 250;
|
||||
|
||||
private FvEncoder() { }
|
||||
|
||||
private record EncoderParams(int JobId, string DestinationPath, FFMpegDecoder Decoder, int StartFrame,
|
||||
int EndFrame);
|
||||
|
||||
private void EncoderThreadMain(object encParams)
|
||||
{
|
||||
var (jobId, dstPath, decoder, frame, endFrame) = (EncoderParams)encParams;
|
||||
|
||||
var dummyAudioBuf = new byte[4 + (AudioFrameSize / 2)];
|
||||
using (var outStream = File.Create(dstPath))
|
||||
{
|
||||
int audioRate = decoder.GetAudioRate();
|
||||
var videoRate = decoder.GetFrameRate();
|
||||
var encoder = new Gericom.FastVideoDS.FastVideoDSEncoder(256, decoder.FrameHeight, 30, 0, MaxGopLength);
|
||||
|
||||
int inFrame = frame;
|
||||
int outFrame = frame;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (inFrame < endFrame)
|
||||
{
|
||||
var frameData = decoder.GetNextFrame();
|
||||
if (frameData != null)
|
||||
{
|
||||
encoder.SendFrame(frameData);
|
||||
if (++inFrame == endFrame)
|
||||
encoder.Flush();
|
||||
}
|
||||
else
|
||||
{
|
||||
inFrame = endFrame;
|
||||
encoder.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
var encData = encoder.ReceiveFrame();
|
||||
if (encData != null)
|
||||
{
|
||||
long expectedSamples = (long)audioRate * (outFrame + 1) * videoRate.den / videoRate.num;
|
||||
long audioSamplesWritten = ((long)audioRate * outFrame * videoRate.den / videoRate.num) /
|
||||
AudioFrameSize * AudioFrameSize;
|
||||
int newSamples = (int)(expectedSamples - audioSamplesWritten);
|
||||
int audioFrames = newSamples > 0 ? newSamples / AudioFrameSize : 0;
|
||||
|
||||
long curPos = outStream.Position;
|
||||
|
||||
int frameLen = (encData.Data.Length + 3) & ~3;
|
||||
uint sizeField = ((uint)frameLen & 0x1FFFFu) | ((uint)audioFrames << 17);
|
||||
outStream.WriteByte((byte)(sizeField & 0xFF));
|
||||
outStream.WriteByte((byte)((sizeField >> 8) & 0xFF));
|
||||
outStream.WriteByte((byte)((sizeField >> 16) & 0xFF));
|
||||
outStream.WriteByte((byte)((sizeField >> 24) & 0xFF));
|
||||
outStream.Write(encData.Data);
|
||||
for (int i = encData.Data.Length; i < frameLen; i++)
|
||||
outStream.WriteByte(0);
|
||||
|
||||
for (int j = 0; j < audioFrames; j++)
|
||||
{
|
||||
outStream.Write(dummyAudioBuf);
|
||||
outStream.Write(dummyAudioBuf);
|
||||
}
|
||||
|
||||
if (encData.Type == Gericom.FastVideoDS.FastVideoDSEncoder.FvFrameType.IFrame)
|
||||
JobKeyFrames[jobId].Add((outFrame, (uint)curPos));
|
||||
|
||||
outFrame++;
|
||||
|
||||
JobProgess[jobId] = outFrame;
|
||||
}
|
||||
|
||||
if (inFrame == endFrame && encoder.FrameQueueEmpty)
|
||||
break;
|
||||
}
|
||||
|
||||
decoder.Dispose();
|
||||
|
||||
JobFileSize[jobId] = (uint)outStream.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Encode(string inFile, string outFile, int jobCount = 1)
|
||||
{
|
||||
if (!Avx2.IsSupported)
|
||||
throw new Exception("Avx2 instruction support not available");
|
||||
|
||||
if (jobCount < 1)
|
||||
throw new ArgumentException(nameof(jobCount));
|
||||
|
||||
var context = new FvEncoder();
|
||||
|
||||
var decoder = new FFMpegDecoder(inFile);
|
||||
|
||||
int audioStream = decoder.AudioStreamId;
|
||||
|
||||
long duration = decoder.GetDuration();
|
||||
|
||||
var timeBase = decoder.GetVideoTimeBase();
|
||||
var videoRate = decoder.GetFrameRate();
|
||||
int audioRate = decoder.GetAudioRate();
|
||||
int frameHeight = decoder.FrameHeight;
|
||||
|
||||
decoder.Dispose();
|
||||
|
||||
long partDuration = duration / jobCount;
|
||||
|
||||
var decoders = new FFMpegDecoder[jobCount];
|
||||
|
||||
for (int i = 0; i < jobCount; i++)
|
||||
{
|
||||
decoders[i] = new FFMpegDecoder(inFile, partDuration * i, decoder.VideoStreamId,
|
||||
FFMpegDecoder.NoStream); //decoder.AudioStreamId);
|
||||
// if (i != 0)
|
||||
// decoders[i - 1].MaxAudioPktPos = decoders[i].FirstAudioPktPos;
|
||||
}
|
||||
|
||||
int ptsToFrame(long pts) =>
|
||||
(int)(pts * timeBase.num * videoRate.num / ((long)timeBase.den * videoRate.den));
|
||||
|
||||
context.JobProgess = new int[jobCount];
|
||||
context.JobKeyFrames = new List<(int, uint)>[jobCount];
|
||||
context.JobFileSize = new uint[jobCount];
|
||||
// var jobProgess = new int[jobCount];
|
||||
var startFrames = new int[jobCount];
|
||||
var endFrames = new int[jobCount];
|
||||
|
||||
var tasks = new Task[jobCount];
|
||||
for (int i = 0; i < jobCount; i++)
|
||||
{
|
||||
int startFrame = i == 0 ? 0 : ptsToFrame(decoders[i].FirstVideoPts);
|
||||
int endFrame = i == jobCount - 1 ? ptsToFrame(duration) : ptsToFrame(decoders[i + 1].FirstVideoPts);
|
||||
|
||||
startFrames[i] = startFrame;
|
||||
endFrames[i] = endFrame;
|
||||
context.JobProgess[i] = startFrame;
|
||||
context.JobKeyFrames[i] = new();
|
||||
|
||||
tasks[i] = Task.Factory.StartNew(context.EncoderThreadMain,
|
||||
new EncoderParams(i, $"{outFile}.{i}", decoders[i], startFrame, endFrame));
|
||||
}
|
||||
|
||||
Console.WriteLine($"Encoding video with {jobCount} jobs ...");
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
while (true)
|
||||
{
|
||||
bool allDone = true;
|
||||
for (int i = 0; i < jobCount; i++)
|
||||
{
|
||||
if (!tasks[i].IsCompleted)
|
||||
{
|
||||
allDone = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int consoleWidth = Console.BufferWidth;
|
||||
int barWidth = consoleWidth - 3;
|
||||
Console.SetCursorPosition(0, Console.GetCursorPosition().Top);
|
||||
Console.Write('[');
|
||||
int totalFrames = endFrames[^1];
|
||||
for (int i = 0; i < barWidth; i++)
|
||||
{
|
||||
int barFrame = (i + 1) * totalFrames / barWidth;
|
||||
for (int j = 0; j < jobCount; j++)
|
||||
{
|
||||
if (barFrame >= startFrames[j] && barFrame <= endFrames[j])
|
||||
{
|
||||
if (context.JobProgess[j] >= barFrame)
|
||||
Console.Write('#');
|
||||
else
|
||||
Console.Write('.');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.Write(']');
|
||||
|
||||
if (allDone)
|
||||
{
|
||||
Console.WriteLine();
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
uint keyFrameCount = (uint)context.JobKeyFrames.Sum(j => (uint)j.Count);
|
||||
|
||||
var audioBlockL = new short[AudioFrameSize];
|
||||
var audioBlockR = new short[AudioFrameSize];
|
||||
|
||||
using (var outStream = File.Create(outFile))
|
||||
{
|
||||
var header = new byte[0x1C + keyFrameCount * 8];
|
||||
header[0] = (byte)'F';
|
||||
header[1] = (byte)'V';
|
||||
header[2] = (byte)'D';
|
||||
header[3] = (byte)'S';
|
||||
var headerSpan = header.AsSpan();
|
||||
headerSpan.WriteLe<ushort>(0x04, 256);
|
||||
headerSpan.WriteLe<ushort>(0x06, (ushort)frameHeight);
|
||||
headerSpan.WriteLe<uint>(0x08, (uint)videoRate.num);
|
||||
headerSpan.WriteLe<uint>(0x0C, (uint)videoRate.den);
|
||||
headerSpan.WriteLe<ushort>(0x10, (ushort)audioRate);
|
||||
headerSpan.WriteLe<ushort>(0x12, 2);
|
||||
headerSpan.WriteLe<uint>(0x14, (uint)endFrames[^1]);
|
||||
headerSpan.WriteLe<uint>(0x18, keyFrameCount);
|
||||
|
||||
uint jobOffset = (uint)header.Length;
|
||||
int headerOffset = 0x1C;
|
||||
for (int i = 0; i < jobCount; i++)
|
||||
{
|
||||
foreach (var (frame, offset) in context.JobKeyFrames[i])
|
||||
{
|
||||
headerSpan.WriteLe<uint>(headerOffset, (uint)frame);
|
||||
headerSpan.WriteLe<uint>(headerOffset + 4, jobOffset + offset);
|
||||
headerOffset += 8;
|
||||
}
|
||||
|
||||
jobOffset += context.JobFileSize[i];
|
||||
}
|
||||
|
||||
outStream.Write(header);
|
||||
|
||||
for (int i = 0; i < jobCount; i++)
|
||||
{
|
||||
using (var partStream = File.OpenRead($"{outFile}.{i}"))
|
||||
partStream.CopyTo(outStream);
|
||||
|
||||
File.Delete($"{outFile}.{i}");
|
||||
}
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"Video encoding done in {stopwatch.Elapsed}");
|
||||
|
||||
Console.WriteLine("Encoding audio...");
|
||||
|
||||
stopwatch = Stopwatch.StartNew();
|
||||
|
||||
var audioDec = new FFMpegDecoder(inFile, 0, FFMpegDecoder.NoStream, audioStream);
|
||||
|
||||
outStream.Position = header.Length;
|
||||
var sizeBuf = new byte[4];
|
||||
|
||||
int f = 0;
|
||||
var audioTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
Adpcm.AdpcmState lastLeft = null;
|
||||
Adpcm.AdpcmState lastRight = null;
|
||||
for (; f < endFrames[^1]; f++)
|
||||
{
|
||||
outStream.Read(sizeBuf);
|
||||
uint sizeField = BinaryPrimitives.ReadUInt32LittleEndian(sizeBuf);
|
||||
|
||||
uint frameLen = sizeField & 0x1FFFFu;
|
||||
uint audioFrames = sizeField >> 17;
|
||||
|
||||
outStream.Position += frameLen;
|
||||
|
||||
for (int j = 0; j < audioFrames; j++)
|
||||
{
|
||||
Array.Clear(audioBlockL, 0, audioBlockL.Length);
|
||||
Array.Clear(audioBlockR, 0, audioBlockR.Length);
|
||||
int samples = audioDec.GetAudioSamples(audioBlockL, audioBlockR, AudioFrameSize);
|
||||
(var data, lastLeft) = Adpcm.Encode(audioBlockL, lastLeft, true);
|
||||
outStream.Write(data);
|
||||
|
||||
(data, lastRight) = Adpcm.Encode(audioBlockR, lastRight, true);
|
||||
outStream.Write(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
while (!audioTask.IsCompleted)
|
||||
{
|
||||
int consoleWidth = Console.BufferWidth;
|
||||
int barWidth = consoleWidth - 3;
|
||||
Console.SetCursorPosition(0, Console.GetCursorPosition().Top);
|
||||
Console.Write('[');
|
||||
int totalFrames = endFrames[^1];
|
||||
int done = barWidth * f / totalFrames;
|
||||
Console.Write(Enumerable.Repeat('#', done).ToArray());
|
||||
Console.Write(Enumerable.Repeat('.', barWidth - done).ToArray());
|
||||
|
||||
Console.Write(']');
|
||||
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
stopwatch.Stop();
|
||||
Console.WriteLine($"Audio encoding done in {stopwatch.Elapsed}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
FastVideoDSEncoder/Program.cs
Normal file
66
FastVideoDSEncoder/Program.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using CommandLine;
|
||||
using CommandLine.Text;
|
||||
|
||||
namespace Gericom.FastVideoDSEncoder
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
private class Options
|
||||
{
|
||||
[Option('j', HelpText = "Number of concurrent jobs (default: cpu threads / 1.5)", MetaValue = "jobs")]
|
||||
public int? Jobs { get; set; }
|
||||
|
||||
[Value(0, Required = true, MetaName = "input", HelpText = "Input video file")]
|
||||
public string Input { get; set; }
|
||||
|
||||
[Value(1, Required = true, MetaName = "output", HelpText = "Output video file")]
|
||||
public string Output { get; set; }
|
||||
}
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("FastVideoDS Encoder by Gericom");
|
||||
|
||||
if (!Avx2.IsSupported)
|
||||
{
|
||||
Console.WriteLine();
|
||||
Console.WriteLine("This encoder requires a cpu with support for AVX2 instructions");
|
||||
return;
|
||||
}
|
||||
|
||||
var parser = new Parser(with =>
|
||||
{
|
||||
with.HelpWriter = null;
|
||||
with.AutoVersion = false;
|
||||
with.AutoHelp = true;
|
||||
});
|
||||
|
||||
var parserResult = parser.ParseArguments<Options>(args);
|
||||
|
||||
parserResult.WithParsed(opt =>
|
||||
{
|
||||
Console.WriteLine();
|
||||
FvEncoder.Encode(opt.Input, opt.Output, opt.Jobs ?? (int)Math.Round(Environment.ProcessorCount / 1.5));
|
||||
});
|
||||
|
||||
parserResult.WithNotParsed(errs =>
|
||||
{
|
||||
var helpText = HelpText.AutoBuild(parserResult, h =>
|
||||
{
|
||||
h.AdditionalNewLineAfterOption = false;
|
||||
h.Heading = "";
|
||||
h.Copyright = "";
|
||||
h.AutoVersion = false;
|
||||
h.AutoHelp = false;
|
||||
h.AddPreOptionsLine("Usage: FastVideoDSEncoder [-j jobs] input output.fv");
|
||||
|
||||
return h;
|
||||
});
|
||||
|
||||
Console.WriteLine(helpText);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
7
FastVideoDSEncoder/Properties/launchSettings.json
Normal file
7
FastVideoDSEncoder/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"FastVideoDSEncoder": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
140
FastVideoDSEncoder/SpanExtensions.cs
Normal file
140
FastVideoDSEncoder/SpanExtensions.cs
Normal file
@ -0,0 +1,140 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Gericom.FastVideoDSEncoder
|
||||
{
|
||||
public static class SpanExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static T ReverseEndianness<T>(T val) where T : unmanaged
|
||||
{
|
||||
switch (val)
|
||||
{
|
||||
case short value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
case ushort value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
case int value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
case uint value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
case long value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
case ulong value:
|
||||
return (T)(object)BinaryPrimitives.ReverseEndianness(value);
|
||||
default:
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static T ReadLe<T>(this Span<byte> span, nint offset) where T : unmanaged
|
||||
=> ReadLe<T>(ref MemoryMarshal.GetReference(span), offset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static T ReadLe<T>(this ReadOnlySpan<byte> span, nint offset) where T : unmanaged
|
||||
=> ReadLe<T>(ref MemoryMarshal.GetReference(span), offset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static T ReadLe<T>(ref byte refSpan, nint offset) where T : unmanaged
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
return (T)(object)BinaryPrimitives.ReadSingleLittleEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)));
|
||||
|
||||
if (typeof(T) == typeof(double))
|
||||
return (T)(object)BinaryPrimitives.ReadDoubleLittleEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)));
|
||||
|
||||
T result = Unsafe.ReadUnaligned<T>(ref Unsafe.Add(ref refSpan, offset));
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
return result;
|
||||
|
||||
return ReverseEndianness(result);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static T ReadBe<T>(this Span<byte> span, nint offset) where T : unmanaged
|
||||
=> ReadBe<T>(ref MemoryMarshal.GetReference(span), offset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static T ReadBe<T>(this ReadOnlySpan<byte> span, nint offset) where T : unmanaged
|
||||
=> ReadBe<T>(ref MemoryMarshal.GetReference(span), offset);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static T ReadBe<T>(ref byte refSpan, nint offset) where T : unmanaged
|
||||
{
|
||||
if (typeof(T) == typeof(float))
|
||||
return (T)(object)BinaryPrimitives.ReadSingleBigEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)));
|
||||
|
||||
if (typeof(T) == typeof(double))
|
||||
return (T)(object)BinaryPrimitives.ReadDoubleBigEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)));
|
||||
|
||||
T result = Unsafe.ReadUnaligned<T>(ref Unsafe.Add(ref refSpan, offset));
|
||||
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
return result;
|
||||
|
||||
return ReverseEndianness(result);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static void WriteLe<T>(ref byte refSpan, nint offset, T value) where T : unmanaged
|
||||
{
|
||||
if (value is float f)
|
||||
{
|
||||
BinaryPrimitives.WriteSingleLittleEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)), f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is double d)
|
||||
{
|
||||
BinaryPrimitives.WriteDoubleLittleEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)), d);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
value = ReverseEndianness(value);
|
||||
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref refSpan, offset), value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void WriteLe<T>(this Span<byte> span, int offset, T value) where T : unmanaged
|
||||
=> WriteLe(ref MemoryMarshal.GetReference(span), offset, value);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static void WriteBe<T>(ref byte refSpan, nint offset, T value) where T : unmanaged
|
||||
{
|
||||
if (value is float f)
|
||||
{
|
||||
BinaryPrimitives.WriteSingleBigEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(float)), f);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value is double d)
|
||||
{
|
||||
BinaryPrimitives.WriteDoubleBigEndian(
|
||||
MemoryMarshal.CreateSpan(ref Unsafe.Add(ref refSpan, offset), sizeof(double)), d);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BitConverter.IsLittleEndian)
|
||||
value = ReverseEndianness(value);
|
||||
|
||||
Unsafe.WriteUnaligned(ref Unsafe.Add(ref refSpan, offset), value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static void WriteBe<T>(this Span<byte> span, int offset, T value) where T : unmanaged
|
||||
=> WriteBe(ref MemoryMarshal.GetReference(span), offset, value);
|
||||
}
|
||||
}
|
BIN
FastVideoDSEncoder/x64/avcodec-59.dll
Normal file
BIN
FastVideoDSEncoder/x64/avcodec-59.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/avdevice-59.dll
Normal file
BIN
FastVideoDSEncoder/x64/avdevice-59.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/avfilter-8.dll
Normal file
BIN
FastVideoDSEncoder/x64/avfilter-8.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/avformat-59.dll
Normal file
BIN
FastVideoDSEncoder/x64/avformat-59.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/avutil-57.dll
Normal file
BIN
FastVideoDSEncoder/x64/avutil-57.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/postproc-56.dll
Normal file
BIN
FastVideoDSEncoder/x64/postproc-56.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/swresample-4.dll
Normal file
BIN
FastVideoDSEncoder/x64/swresample-4.dll
Normal file
Binary file not shown.
BIN
FastVideoDSEncoder/x64/swscale-6.dll
Normal file
BIN
FastVideoDSEncoder/x64/swscale-6.dll
Normal file
Binary file not shown.
11
FastVideoDSInfo/FastVideoDSInfo.csproj
Normal file
11
FastVideoDSInfo/FastVideoDSInfo.csproj
Normal file
@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
<Nullable>disable</Nullable>
|
||||
<RootNamespace>Gericom.FastVideoDSInfo</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
36
FastVideoDSInfo/Program.cs
Normal file
36
FastVideoDSInfo/Program.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
|
||||
namespace Gericom.FastVideoDSInfo
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
using var stream = File.OpenRead(args[0]);
|
||||
stream.Position += 0x20;
|
||||
var keyFrame0OffsBuf = new byte[4];
|
||||
stream.Read(keyFrame0OffsBuf);
|
||||
stream.Position = BinaryPrimitives.ReadUInt32LittleEndian(keyFrame0OffsBuf);
|
||||
using var csvStream = File.CreateText(args[1]);
|
||||
csvStream.WriteLine("frame;type;size;audioBlocks");
|
||||
var frameHeaderBuf = new byte[4];
|
||||
int frame = 0;
|
||||
while (true)
|
||||
{
|
||||
if (stream.Read(frameHeaderBuf) < 4)
|
||||
break;
|
||||
uint frameHeader = BinaryPrimitives.ReadUInt32LittleEndian(frameHeaderBuf);
|
||||
uint frameLen = frameHeader & 0x1FFFFu;
|
||||
uint audioFrames = frameHeader >> 17;
|
||||
stream.Read(frameHeaderBuf.AsSpan(0, 2));
|
||||
bool isPFrame = (BinaryPrimitives.ReadUInt16LittleEndian(frameHeaderBuf) >> 15) == 1;
|
||||
csvStream.WriteLine($"{frame};{(isPFrame ? "P" : "I")};{frameLen};{audioFrames}");
|
||||
stream.Position += frameLen - 2;
|
||||
stream.Position += audioFrames * 132 * 2;
|
||||
frame++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
FastVideoDSInfo/Properties/launchSettings.json
Normal file
7
FastVideoDSInfo/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"FastVideoDSInfo": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
69
Gericom.FastVideoDS/Bitstream/BitReader.cs
Normal file
69
Gericom.FastVideoDS/Bitstream/BitReader.cs
Normal file
@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Gericom.FastVideoDS.Bitstream
|
||||
{
|
||||
public class BitReader
|
||||
{
|
||||
private readonly byte[] _data;
|
||||
private int _offset;
|
||||
public int BitsRemaining;
|
||||
public uint Bits;
|
||||
|
||||
public BitReader(byte[] data)
|
||||
{
|
||||
_data = data;
|
||||
Bits = (uint)(BinaryPrimitives.ReadUInt16LittleEndian(data) << 16);
|
||||
BitsRemaining = 0;
|
||||
_offset = 2;
|
||||
}
|
||||
|
||||
public uint ReadUnsignedVarInt()
|
||||
{
|
||||
int clz = BitOperations.LeadingZeroCount(Bits); //nr zeros
|
||||
Bits <<= clz; //remove the zeros
|
||||
Bits += Bits; //remove the stop bit
|
||||
int r9 = 32 - clz; //shift amount
|
||||
uint r6 = r9 == 32 ? 0 : Bits >> r9;
|
||||
r9 = 1;
|
||||
r6 += (uint)(r9 << clz);
|
||||
r6--;
|
||||
Bits <<= clz;
|
||||
BitsRemaining -= clz << 1;
|
||||
if (--BitsRemaining < 0)
|
||||
FillBits();
|
||||
return r6;
|
||||
}
|
||||
|
||||
public void FillBits()
|
||||
{
|
||||
if (_offset >= _data.Length)
|
||||
return;
|
||||
uint r10 = BinaryPrimitives.ReadUInt16LittleEndian(_data.AsSpan(_offset));
|
||||
_offset += 2;
|
||||
BitsRemaining += 0x10;
|
||||
int r9 = 0x10 - BitsRemaining;
|
||||
Bits |= r10 << r9;
|
||||
}
|
||||
|
||||
private int ReadSignedVarInt()
|
||||
{
|
||||
int clz = BitOperations.LeadingZeroCount(Bits);
|
||||
Bits <<= clz;
|
||||
Bits += Bits;
|
||||
int r9 = 32 - clz;
|
||||
int r6 = r9 == 32 ? 0 : (int)(Bits >> r9);
|
||||
r9 = 1;
|
||||
r6 += r9 << clz;
|
||||
if ((r6 & 1) != 0)
|
||||
r6 = 1 - r6;
|
||||
r6 >>= 1;
|
||||
Bits <<= clz;
|
||||
BitsRemaining -= clz << 1;
|
||||
if (--BitsRemaining < 0)
|
||||
FillBits();
|
||||
return r6;
|
||||
}
|
||||
}
|
||||
}
|
99
Gericom.FastVideoDS/Bitstream/BitWriter.cs
Normal file
99
Gericom.FastVideoDS/Bitstream/BitWriter.cs
Normal file
@ -0,0 +1,99 @@
|
||||
using System.IO;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Gericom.FastVideoDS.Bitstream
|
||||
{
|
||||
public class BitWriter
|
||||
{
|
||||
private readonly MemoryStream _stream = new();
|
||||
|
||||
private uint _bits = 0;
|
||||
private int _bitCount = 0;
|
||||
|
||||
public void WriteBits(uint value, int nrBits)
|
||||
{
|
||||
if (nrBits <= 0)
|
||||
return;
|
||||
_bits |= (value & (1u << nrBits) - 1) << 32 - nrBits - _bitCount;
|
||||
_bitCount += nrBits;
|
||||
if (_bitCount >= 16)
|
||||
Flush();
|
||||
}
|
||||
|
||||
//Elias gamma coding
|
||||
public void WriteUnsignedVarInt(uint value)
|
||||
{
|
||||
int NrBits = 32 - BitOperations.LeadingZeroCount((value + 1) / 2);
|
||||
WriteBits(0, NrBits);
|
||||
WriteBits(1, 1); //stop bit
|
||||
value -= (1u << NrBits) - 1;
|
||||
WriteBits(value, NrBits);
|
||||
}
|
||||
|
||||
public void WriteSignedVarInt(int value)
|
||||
{
|
||||
uint val;
|
||||
if (value <= 0)
|
||||
val = (uint)(1 - value * 2);
|
||||
else
|
||||
val = (uint)(value * 2);
|
||||
int nrBits = 32 - BitOperations.LeadingZeroCount(val / 2);
|
||||
WriteBits(0, nrBits);
|
||||
WriteBits(1, 1); //stop bit
|
||||
val -= 1u << nrBits;
|
||||
WriteBits(val, nrBits);
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (_bitCount <= 0)
|
||||
return;
|
||||
_stream.WriteByte((byte)(_bits >> 16 & 0xFF));
|
||||
_stream.WriteByte((byte)(_bits >> 24 & 0xFF));
|
||||
_bitCount -= 16;
|
||||
_bits <<= 16;
|
||||
}
|
||||
|
||||
// public byte[] PeekStream()
|
||||
// {
|
||||
// if (BitCount <= 0)
|
||||
// return _stream.ToArray();
|
||||
// var res = new List<byte>();
|
||||
// res.AddRange(_stream.GetBuffer());
|
||||
// res.Add((byte)((Bits >> 16) & 0xFF));
|
||||
// res.Add((byte)((Bits >> 24) & 0xFF));
|
||||
// return res.ToArray();
|
||||
// }
|
||||
|
||||
public byte[] ToArray()
|
||||
{
|
||||
Flush();
|
||||
return _stream.ToArray();
|
||||
}
|
||||
|
||||
public static int GetUnsignedVarIntBitCount(uint value)
|
||||
{
|
||||
int result = 0;
|
||||
int nrBits = 32 - BitOperations.LeadingZeroCount((value + 1) / 2);
|
||||
result += nrBits;
|
||||
result++; //stop bit
|
||||
result += nrBits;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int GetSignedVarIntBitCount(int value)
|
||||
{
|
||||
int result = 0;
|
||||
uint val;
|
||||
if (value <= 0)
|
||||
val = (uint)(1 - value * 2);
|
||||
else
|
||||
val = (uint)(value * 2);
|
||||
int nrBits = 32 - BitOperations.LeadingZeroCount(val / 2);
|
||||
result += nrBits;
|
||||
result++; //stop bit
|
||||
result += nrBits;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
34
Gericom.FastVideoDS/Dct.cs
Normal file
34
Gericom.FastVideoDS/Dct.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace Gericom.FastVideoDS
|
||||
{
|
||||
public static class Dct
|
||||
{
|
||||
public static void Dct4NoDiv(int[] pixels, int[] dst)
|
||||
{
|
||||
int t0 = pixels[0] + pixels[1];
|
||||
int t1 = pixels[0] - pixels[1];
|
||||
int t2 = pixels[2] + pixels[3];
|
||||
int t3 = pixels[2] - pixels[3];
|
||||
|
||||
dst[0] = t0 + t2;
|
||||
dst[1] = t0 - t2;
|
||||
dst[2] = t1 + t3;
|
||||
dst[3] = t1 - t3;
|
||||
}
|
||||
|
||||
public static void IDct4(int[] dct, byte[] pixels, byte[] dst)
|
||||
{
|
||||
int r0 = dct[0] + 16;
|
||||
int t0 = r0 + dct[1];
|
||||
int t2 = r0 - dct[1];
|
||||
int t1 = dct[2] + dct[3];
|
||||
int t3 = dct[2] - dct[3];
|
||||
|
||||
dst[0] = (byte)(Math.Clamp((pixels[0] >> 3) + (t0 + t1 >> 5), 0, 31) << 3);
|
||||
dst[1] = (byte)(Math.Clamp((pixels[1] >> 3) + (t0 - t1 >> 5), 0, 31) << 3);
|
||||
dst[2] = (byte)(Math.Clamp((pixels[2] >> 3) + (t2 + t3 >> 5), 0, 31) << 3);
|
||||
dst[3] = (byte)(Math.Clamp((pixels[3] >> 3) + (t2 - t3 >> 5), 0, 31) << 3);
|
||||
}
|
||||
}
|
||||
}
|
1998
Gericom.FastVideoDS/FastVideoDSEncoder.cs
Normal file
1998
Gericom.FastVideoDS/FastVideoDSEncoder.cs
Normal file
File diff suppressed because it is too large
Load Diff
31
Gericom.FastVideoDS/Frames/FramePool.cs
Normal file
31
Gericom.FastVideoDS/Frames/FramePool.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Gericom.FastVideoDS.Frames
|
||||
{
|
||||
public class FramePool
|
||||
{
|
||||
private readonly Queue<Rgb555Frame> _pool = new();
|
||||
|
||||
public readonly int Width;
|
||||
public readonly int Height;
|
||||
|
||||
public FramePool(int width, int height)
|
||||
{
|
||||
Width = width;
|
||||
Height = height;
|
||||
}
|
||||
|
||||
public RefFrame AcquireFrame()
|
||||
{
|
||||
if (!_pool.TryDequeue(out var frame))
|
||||
frame = new Rgb555Frame(Width, Height);
|
||||
|
||||
return new RefFrame(this, frame);
|
||||
}
|
||||
|
||||
public void ReleaseFrame(RefFrame frame)
|
||||
{
|
||||
_pool.Enqueue(frame.Frame);
|
||||
}
|
||||
}
|
||||
}
|
47
Gericom.FastVideoDS/Frames/RefFrame.cs
Normal file
47
Gericom.FastVideoDS/Frames/RefFrame.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
|
||||
namespace Gericom.FastVideoDS.Frames
|
||||
{
|
||||
public sealed class RefFrame : IDisposable
|
||||
{
|
||||
private readonly FramePool _pool;
|
||||
|
||||
public int RefCount { get; private set; } = 1;
|
||||
|
||||
public readonly Rgb555Frame Frame;
|
||||
|
||||
public RefFrame(FramePool pool, Rgb555Frame frame)
|
||||
{
|
||||
_pool = pool;
|
||||
Frame = frame;
|
||||
}
|
||||
|
||||
public void Ref()
|
||||
{
|
||||
if (RefCount == 0)
|
||||
throw new Exception();
|
||||
|
||||
RefCount++;
|
||||
}
|
||||
|
||||
public void Unref()
|
||||
{
|
||||
if (RefCount == 0)
|
||||
throw new Exception();
|
||||
|
||||
if (--RefCount == 0)
|
||||
_pool.ReleaseFrame(this);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (RefCount == 0)
|
||||
return;
|
||||
|
||||
Unref();
|
||||
|
||||
if (RefCount != 0)
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
}
|
186
Gericom.FastVideoDS/Frames/Rgb555Frame.cs
Normal file
186
Gericom.FastVideoDS/Frames/Rgb555Frame.cs
Normal file
@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Gericom.FastVideoDS.Frames
|
||||
{
|
||||
public class Rgb555Frame
|
||||
{
|
||||
public readonly int Width;
|
||||
public readonly int Height;
|
||||
|
||||
public readonly byte[] R;
|
||||
public readonly byte[] G;
|
||||
public readonly byte[] B;
|
||||
|
||||
public Rgb555Frame(int width, int height)
|
||||
{
|
||||
if (width <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(width), width, "Width should be > 0");
|
||||
if (height <= 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(height), height, "Height should be > 0");
|
||||
Width = width;
|
||||
Height = height;
|
||||
R = new byte[height * width];
|
||||
G = new byte[height * width];
|
||||
B = new byte[height * width];
|
||||
}
|
||||
|
||||
// public unsafe Bitmap ToBitmap()
|
||||
// {
|
||||
// var b = new Bitmap(Width, Height, PixelFormat.Format32bppArgb);
|
||||
// var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.WriteOnly,
|
||||
// PixelFormat.Format32bppArgb);
|
||||
// for (int y = 0; y < b.Height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < b.Width; x++)
|
||||
// {
|
||||
// // int pr = R[y, x] << 3; // * 255 / 31;
|
||||
// // int pg = G[y, x] << 3; // * 255 / 31;
|
||||
// // int pb = B[y, x] << 3; // * 255 / 31;
|
||||
//
|
||||
// int pr = (R[y * Width + x] >> 3) * 255 / 31;
|
||||
// int pg = (G[y * Width + x] >> 3) * 255 / 31;
|
||||
// int pb = (B[y * Width + x] >> 3) * 255 / 31;
|
||||
//
|
||||
// if (pr < 0) pr = 0;
|
||||
// else if (pr > 255) pr = 255;
|
||||
// if (pg < 0) pg = 0;
|
||||
// else if (pg > 255) pg = 255;
|
||||
// if (pb < 0) pb = 0;
|
||||
// else if (pb > 255) pb = 255;
|
||||
//
|
||||
// *(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4) = Color.FromArgb(pr, pg, pb).ToArgb();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// b.UnlockBits(d);
|
||||
// return b;
|
||||
// }
|
||||
|
||||
private static readonly int[,] DitherMatrix =
|
||||
{
|
||||
{ 0, 12, 3, 15 },
|
||||
{ 8, 4, 11, 7 },
|
||||
{ 2, 14, 1, 13 },
|
||||
{ 10, 6, 9, 5 }
|
||||
};
|
||||
|
||||
// public static unsafe Rgb555Frame FromBitmap(Bitmap b)
|
||||
// {
|
||||
// var frame = new Rgb555Frame(b.Width, b.Height);
|
||||
// var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly,
|
||||
// PixelFormat.Format32bppArgb);
|
||||
//
|
||||
// for (int y = 0; y < b.Height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < b.Width; x++)
|
||||
// {
|
||||
// var c = Color.FromArgb(*(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4));
|
||||
// int bias = (DitherMatrix[y & 3, x & 3] >> 1) - 4;
|
||||
//
|
||||
// int pr = ((c.R + bias) >> 3); // * 255 / 31;
|
||||
// int pg = ((c.G + bias) >> 3); // * 255 / 31;
|
||||
// int pb = ((c.B + bias) >> 3); // * 255 / 31;
|
||||
//
|
||||
// if (pr < 0) pr = 0;
|
||||
// else if (pr > 31) pr = 31;
|
||||
// if (pg < 0) pg = 0;
|
||||
// else if (pg > 31) pg = 31;
|
||||
// if (pb < 0) pb = 0;
|
||||
// else if (pb > 31) pb = 31;
|
||||
//
|
||||
// frame.R[y * frame.Width + x] = (byte)(pr << 3); //((pr << 3) | (pr >> 2));
|
||||
// frame.G[y * frame.Width + x] = (byte)(pg << 3); //((pg << 3) | (pg >> 2));
|
||||
// frame.B[y * frame.Width + x] = (byte)(pb << 3); //((pb << 3) | (pb >> 2));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// b.UnlockBits(d);
|
||||
// return frame;
|
||||
// }
|
||||
|
||||
//Based on http://www.thetenthplanet.de/archives/5367
|
||||
private static double ToLinear(double value) => Math.Pow(value, 2.2);
|
||||
|
||||
private static readonly double[] ToLinear8 = new double[256];
|
||||
private static readonly double[] ToLinear5 = new double[32];
|
||||
|
||||
static Rgb555Frame()
|
||||
{
|
||||
for (int i = 0; i < 256; i++)
|
||||
ToLinear8[i] = ToLinear(i / 255.0);
|
||||
|
||||
for (int i = 0; i < 32; i++)
|
||||
ToLinear5[i] = ToLinear(i / 31.0);
|
||||
}
|
||||
|
||||
private static int Dither(int color, double noise)
|
||||
{
|
||||
int c0 = color * 31 / 255;
|
||||
int c1 = Math.Clamp(c0 + 1, 0, 31);
|
||||
double discr = ToLinear5[c0] * (1 - noise) + ToLinear5[c1] * noise;
|
||||
return discr < ToLinear8[color] ? c1 : c0;
|
||||
}
|
||||
|
||||
public static unsafe Rgb555Frame FromRgba32(byte* src, int width, int height, int stride)
|
||||
{
|
||||
var frame = new Rgb555Frame(width, height);
|
||||
frame.FromRgba32(src, stride);
|
||||
return frame;
|
||||
}
|
||||
|
||||
public unsafe void FromRgba32(byte* src, int stride)
|
||||
{
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
var c = Color.FromArgb(*(int*)(src + y * stride + x * 4));
|
||||
|
||||
int bias = DitherMatrix[y & 3, x & 3];
|
||||
|
||||
int pr = Dither(c.R, bias / 16.0);
|
||||
int pg = Dither(c.G, bias / 16.0);
|
||||
int pb = Dither(c.B, bias / 16.0);
|
||||
|
||||
R[y * Width + x] = (byte)(pr << 3);
|
||||
G[y * Width + x] = (byte)(pg << 3);
|
||||
B[y * Width + x] = (byte)(pb << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public static unsafe RGB555Frame FromBitmap555(Bitmap b)
|
||||
// {
|
||||
// var yuvFrame = new RGB555Frame(b.Width, b.Height);
|
||||
// var d = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly,
|
||||
// PixelFormat.Format32bppArgb);
|
||||
// for (int y = 0; y < b.Height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < b.Width; x++)
|
||||
// {
|
||||
// var c = Color.FromArgb(*(int*)(((byte*)d.Scan0) + y * d.Stride + x * 4));
|
||||
// int bias = (DitherMatrix[y & 3, x & 3] >> 1) - 4;
|
||||
//
|
||||
// int pr = ((c.R + bias) >> 3);// * 255 / 31;
|
||||
// int pg = ((c.G + bias) >> 3);// * 255 / 31;
|
||||
// int pb = ((c.B + bias) >> 3);// * 255 / 31;
|
||||
//
|
||||
// if (pr < 0) pr = 0;
|
||||
// else if (pr > 31) pr = 31;
|
||||
// if (pg < 0) pg = 0;
|
||||
// else if (pg > 31) pg = 31;
|
||||
// if (pb < 0) pb = 0;
|
||||
// else if (pb > 31) pb = 31;
|
||||
//
|
||||
// yuvFrame.R[y, x] = (byte) pr;//((pr << 3) | (pr >> 2));
|
||||
// yuvFrame.G[y, x] = (byte) pg;//((pg << 3) | (pg >> 2));
|
||||
// yuvFrame.B[y, x] = (byte) pb;//((pb << 3) | (pb >> 2));
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// b.UnlockBits(d);
|
||||
// return yuvFrame;
|
||||
// }
|
||||
}
|
||||
}
|
15
Gericom.FastVideoDS/Gericom.FastVideoDS.csproj
Normal file
15
Gericom.FastVideoDS/Gericom.FastVideoDS.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
157
Gericom.FastVideoDS/MotionEstimation.cs
Normal file
157
Gericom.FastVideoDS/MotionEstimation.cs
Normal file
@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Gericom.FastVideoDS.Bitstream;
|
||||
using Gericom.FastVideoDS.Frames;
|
||||
using Gericom.FastVideoDS.Utils;
|
||||
|
||||
namespace Gericom.FastVideoDS
|
||||
{
|
||||
public static class MotionEstimation
|
||||
{
|
||||
private static readonly MotionVector[] LdspDirections =
|
||||
{
|
||||
new(-2, 0),
|
||||
new(-1, -1),
|
||||
new(0, -2),
|
||||
new(1, -1),
|
||||
new(2, 0),
|
||||
new(1, 1),
|
||||
new(0, 2),
|
||||
new(-1, 1)
|
||||
};
|
||||
|
||||
private static readonly MotionVector[] SdspDirections =
|
||||
{
|
||||
new(-1, 0),
|
||||
new(0, -1),
|
||||
new(1, 0),
|
||||
new(0, 1),
|
||||
};
|
||||
|
||||
public static MotionVector FindMotionVector(byte[] targetR, byte[] targetG, byte[] targetB, Rgb555Frame src,
|
||||
MotionVector center, MotionVector cheap, out int bestScore)
|
||||
{
|
||||
const int lambda = 4;
|
||||
var block = new byte[64];
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
int getDistortion(MotionVector vec)
|
||||
{
|
||||
if (center.Y < (src.Height >> 1) * 2 && vec.Y > (src.Height - 8) * 2 ||
|
||||
center.Y >= (src.Height >> 1) * 2 && vec.Y < 0)
|
||||
return 999999;
|
||||
|
||||
FrameUtil.GetTileHalf8(src.R, src.Width, src.Height, vec.X, vec.Y, block);
|
||||
int score = FrameUtil.Sad64(targetR, block);
|
||||
FrameUtil.GetTileHalf8(src.G, src.Width, src.Height, vec.X, vec.Y, block);
|
||||
score += FrameUtil.Sad64(targetG, block);
|
||||
FrameUtil.GetTileHalf8(src.B, src.Width, src.Height, vec.X, vec.Y, block);
|
||||
score += FrameUtil.Sad64(targetB, block);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
int getBitCount(MotionVector vec)
|
||||
{
|
||||
return vec == cheap ? 1 :
|
||||
1 + BitWriter.GetSignedVarIntBitCount(vec.X - cheap.X)
|
||||
+ BitWriter.GetSignedVarIntBitCount(vec.Y - cheap.Y);
|
||||
}
|
||||
|
||||
// var vectors = new HashSet<MotionVector>();
|
||||
bestScore = getDistortion(center);
|
||||
int bestBitCount = getBitCount(center);
|
||||
int bestRdScore = bestBitCount * lambda + bestScore;
|
||||
var bestRdVec = center;
|
||||
var bestVec = center;
|
||||
|
||||
int score = getDistortion(cheap);
|
||||
int bitCount = getBitCount(cheap);
|
||||
int rdScore = bitCount * lambda + score;
|
||||
if (score < bestScore || score == bestScore && bitCount < bestBitCount)
|
||||
{
|
||||
bestScore = score;
|
||||
bestBitCount = bitCount;
|
||||
bestVec = cheap;
|
||||
}
|
||||
|
||||
if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore)
|
||||
{
|
||||
bestRdScore = rdScore;
|
||||
bestRdVec = cheap;
|
||||
}
|
||||
|
||||
var searchCenter = cheap;
|
||||
|
||||
int count = 0;
|
||||
int bestIdx;
|
||||
do
|
||||
{
|
||||
bestIdx = -1;
|
||||
for (int i = 0; i < LdspDirections.Length; i++)
|
||||
{
|
||||
var vec = searchCenter + LdspDirections[i];
|
||||
// if(vectors.Contains(vec))
|
||||
// continue;
|
||||
// vectors.Add(vec);
|
||||
score = getDistortion(vec);
|
||||
bitCount = getBitCount(vec);
|
||||
rdScore = bitCount * lambda + score;
|
||||
if (score < bestScore || score == bestScore && bitCount < bestBitCount)
|
||||
{
|
||||
bestScore = score;
|
||||
bestBitCount = bitCount;
|
||||
bestVec = vec;
|
||||
bestIdx = i;
|
||||
}
|
||||
|
||||
if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore)
|
||||
{
|
||||
bestRdScore = rdScore;
|
||||
bestRdVec = vec;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
searchCenter = bestVec;
|
||||
} while (bestIdx != -1 && count < 128); //32);
|
||||
|
||||
count = 0;
|
||||
do
|
||||
{
|
||||
bestIdx = -1;
|
||||
for (int i = 0; i < SdspDirections.Length; i++)
|
||||
{
|
||||
var vec = searchCenter + SdspDirections[i];
|
||||
// if (vectors.Contains(vec))
|
||||
// continue;
|
||||
// vectors.Add(vec);
|
||||
score = getDistortion(vec);
|
||||
bitCount = getBitCount(vec);
|
||||
rdScore = bitCount * lambda + score;
|
||||
if (score < bestScore || score == bestScore && bitCount < bestBitCount)
|
||||
{
|
||||
bestScore = score;
|
||||
bestBitCount = bitCount;
|
||||
bestVec = vec;
|
||||
bestIdx = i;
|
||||
}
|
||||
|
||||
if (rdScore < bestRdScore || Math.Abs(rdScore - bestRdScore) < 0.001f && score < bestScore)
|
||||
{
|
||||
bestRdScore = rdScore;
|
||||
bestRdVec = vec;
|
||||
}
|
||||
|
||||
count++;
|
||||
}
|
||||
|
||||
searchCenter = bestVec;
|
||||
} while (bestIdx != -1 && count < 128); //32);
|
||||
|
||||
return bestRdVec;
|
||||
}
|
||||
}
|
||||
}
|
44
Gericom.FastVideoDS/MotionVector.cs
Normal file
44
Gericom.FastVideoDS/MotionVector.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Gericom.FastVideoDS
|
||||
{
|
||||
public struct MotionVector
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public MotionVector(int x, int y)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static MotionVector operator +(MotionVector a, MotionVector b)
|
||||
=> new(a.X + b.X, a.Y + b.Y);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static MotionVector operator *(MotionVector a, int mul)
|
||||
=> new(a.X * mul, a.Y * mul);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator ==(MotionVector left, MotionVector right)
|
||||
=> left.Equals(right);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool operator !=(MotionVector left, MotionVector right)
|
||||
=> !left.Equals(right);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool Equals(MotionVector other)
|
||||
=> X == other.X && Y == other.Y;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override bool Equals(object obj)
|
||||
=> obj is MotionVector other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> unchecked(X * 397 ^ Y);
|
||||
}
|
||||
}
|
595
Gericom.FastVideoDS/Utils/FrameUtil.cs
Normal file
595
Gericom.FastVideoDS/Utils/FrameUtil.cs
Normal file
@ -0,0 +1,595 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
namespace Gericom.FastVideoDS.Utils
|
||||
{
|
||||
public static class FrameUtil
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void GetTile8(byte[] data, int stride, int srcX, int srcY, byte[] result)
|
||||
{
|
||||
fixed (byte* dst = &result[0], src = &data[srcY * stride + srcX])
|
||||
{
|
||||
((ulong*)dst)[0] = *(ulong*)(src);
|
||||
((ulong*)dst)[1] = *(ulong*)(src + 1 * stride);
|
||||
((ulong*)dst)[2] = *(ulong*)(src + 2 * stride);
|
||||
((ulong*)dst)[3] = *(ulong*)(src + 3 * stride);
|
||||
((ulong*)dst)[4] = *(ulong*)(src + 4 * stride);
|
||||
((ulong*)dst)[5] = *(ulong*)(src + 5 * stride);
|
||||
((ulong*)dst)[6] = *(ulong*)(src + 6 * stride);
|
||||
((ulong*)dst)[7] = *(ulong*)(src + 7 * stride);
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] GetTile(byte[] data, int stride, int srcX, int srcY, int width, int height)
|
||||
{
|
||||
var result = new byte[height * width];
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
result[y * width + x] = data[(y + srcY) * stride + (x + srcX)];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void GetTile2x2Step2(byte[] data, int stride, int srcX, int srcY, byte[] dst)
|
||||
{
|
||||
dst[0] = data[(srcY) * stride + srcX];
|
||||
dst[1] = data[(srcY) * stride + srcX + 2];
|
||||
dst[2] = data[(srcY + 2) * stride + srcX];
|
||||
dst[3] = data[(srcY + 2) * stride + srcX + 2];
|
||||
}
|
||||
|
||||
public static byte[] GetTile(byte[] data, int stride, int srcX, int srcY, int width, int height, int step)
|
||||
{
|
||||
var result = new byte[height * width];
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
result[y * width + x] = data[(y * step + srcY) * stride + x * step + srcX];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe void GetTileHalf8(byte[] data, int width, int height, int srcX, int srcY, byte[] result)
|
||||
{
|
||||
if (((srcX | srcY) & 1) == 0)
|
||||
{
|
||||
if (srcX >> 1 >= 0 && (srcX >> 1) + 7 < width &&
|
||||
srcY >> 1 >= 0 && (srcY >> 1) + 7 < height)
|
||||
{
|
||||
fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)])
|
||||
{
|
||||
((ulong*)dst)[0] = *(ulong*)(src);
|
||||
((ulong*)dst)[1] = *(ulong*)(src + 1 * width);
|
||||
((ulong*)dst)[2] = *(ulong*)(src + 2 * width);
|
||||
((ulong*)dst)[3] = *(ulong*)(src + 3 * width);
|
||||
((ulong*)dst)[4] = *(ulong*)(src + 4 * width);
|
||||
((ulong*)dst)[5] = *(ulong*)(src + 5 * width);
|
||||
((ulong*)dst)[6] = *(ulong*)(src + 6 * width);
|
||||
((ulong*)dst)[7] = *(ulong*)(src + 7 * width);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1);
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1);
|
||||
result[y * 8 + x] = data[y1 * width + x1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((srcY & 1) == 0)
|
||||
{
|
||||
if (srcX >> 1 >= 0 && (srcX >> 1) + 8 < width &&
|
||||
srcY >> 1 >= 0 && (srcY >> 1) + 7 < height)
|
||||
{
|
||||
fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)])
|
||||
{
|
||||
var bit0 = Vector256.Create((short)(1 << 2));
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
ulong row = *(ulong*)(src + y * width);
|
||||
ulong row2 = (row >> 8) | ((ulong)src[y * width + 8] << 56);
|
||||
|
||||
var a = Avx2.ConvertToVector256Int16(Vector128.Create(row, row2).AsByte());
|
||||
var isZero = Avx2.CompareEqual(a, Vector256<short>.Zero);
|
||||
a = Avx2.Add(a, bit0);
|
||||
a = Avx2.AndNot(isZero, a);
|
||||
var b = Sse2.Add(a.GetLower(), a.GetUpper());
|
||||
b = Sse2.ShiftRightLogical(b, 4);
|
||||
b = Sse2.ShiftLeftLogical(b, 3);
|
||||
*(ulong*)(dst + y * 8) = Sse2.PackUnsignedSaturate(b, Vector128<short>.Zero).AsUInt64()
|
||||
.ToScalar();
|
||||
}
|
||||
}
|
||||
|
||||
// for (int y = 0; y < 8; y++)
|
||||
// {
|
||||
// for (int x = 0; x < 8; x++)
|
||||
// {
|
||||
// int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[(y + (srcY >> 1)) * width + x + (srcX >> 1) + 1] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1);
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1);
|
||||
int x2 = Math.Clamp(x + (srcX >> 1) + 1, 0, width - 1);
|
||||
int a = data[y1 * width + x1] >> 3 << 1;
|
||||
if (a != 0)
|
||||
a++;
|
||||
int b = data[y1 * width + x2] >> 3 << 1;
|
||||
if (b != 0)
|
||||
b++;
|
||||
result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((srcX & 1) == 0)
|
||||
{
|
||||
if (srcX >> 1 >= 0 && (srcX >> 1) + 7 < width &&
|
||||
srcY >> 1 >= 0 && (srcY >> 1) + 8 < height)
|
||||
{
|
||||
fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)])
|
||||
{
|
||||
var bit0 = Vector256.Create((short)(1 << 2));
|
||||
var ac = Avx2.ConvertToVector256Int16(
|
||||
Vector128.Create(*(ulong*)(src + 0 * width), *(ulong*)(src + 2 * width)).AsByte());
|
||||
var isZero = Avx2.CompareEqual(ac, Vector256<short>.Zero);
|
||||
ac = Avx2.Add(ac, bit0);
|
||||
ac = Avx2.AndNot(isZero, ac);
|
||||
|
||||
var bd = Avx2.ConvertToVector256Int16(
|
||||
Vector128.Create(*(ulong*)(src + 1 * width), *(ulong*)(src + 3 * width)).AsByte());
|
||||
isZero = Avx2.CompareEqual(bd, Vector256<short>.Zero);
|
||||
bd = Avx2.Add(bd, bit0);
|
||||
bd = Avx2.AndNot(isZero, bd);
|
||||
|
||||
|
||||
var aBcD = Avx2.Add(ac, bd);
|
||||
aBcD = Avx2.ShiftRightLogical(aBcD, 4);
|
||||
aBcD = Avx2.ShiftLeftLogical(aBcD, 3);
|
||||
|
||||
|
||||
var eg = Avx2.ConvertToVector256Int16(
|
||||
Vector128.Create(*(ulong*)(src + 4 * width), *(ulong*)(src + 6 * width)).AsByte());
|
||||
isZero = Avx2.CompareEqual(eg, Vector256<short>.Zero);
|
||||
eg = Avx2.Add(eg, bit0);
|
||||
eg = Avx2.AndNot(isZero, eg);
|
||||
|
||||
var ce = Vector256.Create(ac.GetUpper(), eg.GetLower());
|
||||
var bCdE = Avx2.Add(bd, ce);
|
||||
bCdE = Avx2.ShiftRightLogical(bCdE, 4);
|
||||
bCdE = Avx2.ShiftLeftLogical(bCdE, 3);
|
||||
Avx.Store(dst, Avx2.PackUnsignedSaturate(aBcD, bCdE));
|
||||
|
||||
var fh = Avx2.ConvertToVector256Int16(
|
||||
Vector128.Create(*(ulong*)(src + 5 * width), *(ulong*)(src + 7 * width)).AsByte());
|
||||
isZero = Avx2.CompareEqual(fh, Vector256<short>.Zero);
|
||||
fh = Avx2.Add(fh, bit0);
|
||||
fh = Avx2.AndNot(isZero, fh);
|
||||
|
||||
var eFgH = Avx2.Add(eg, fh);
|
||||
eFgH = Avx2.ShiftRightLogical(eFgH, 4);
|
||||
eFgH = Avx2.ShiftLeftLogical(eFgH, 3);
|
||||
|
||||
var last = Sse41.ConvertToVector128Int16(src + 8 * width);
|
||||
var isZeroLast = Sse2.CompareEqual(last, Vector128<short>.Zero);
|
||||
last = Sse2.Add(last, Vector128.Create((short)(1 << 2)));
|
||||
last = Sse2.AndNot(isZeroLast, last);
|
||||
|
||||
var gi = Vector256.Create(eg.GetUpper(), last);
|
||||
var fGhI = Avx2.Add(fh, gi);
|
||||
fGhI = Avx2.ShiftRightLogical(fGhI, 4);
|
||||
fGhI = Avx2.ShiftLeftLogical(fGhI, 3);
|
||||
Avx.Store(dst + 4 * 8, Avx2.PackUnsignedSaturate(eFgH, fGhI));
|
||||
}
|
||||
|
||||
// for (int y = 0; y < 8; y++)
|
||||
// {
|
||||
// for (int x = 0; x < 8; x++)
|
||||
// {
|
||||
// int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[(y + (srcY >> 1) + 1) * width + x + (srcX >> 1)] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// if(result[y * 8 + x] != (byte)((a * 16 + b * 16) >> 6 << 3))
|
||||
// {
|
||||
//
|
||||
// }
|
||||
// result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1);
|
||||
int y2 = Math.Clamp(y + (srcY >> 1) + 1, 0, height - 1);
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1);
|
||||
int a = data[y1 * width + x1] >> 3 << 1;
|
||||
if (a != 0)
|
||||
a++;
|
||||
int b = data[y2 * width + x1] >> 3 << 1;
|
||||
if (b != 0)
|
||||
b++;
|
||||
result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (srcX >> 1 >= 0 && (srcX >> 1) + 8 < width &&
|
||||
srcY >> 1 >= 0 && (srcY >> 1) + 8 < height)
|
||||
{
|
||||
fixed (byte* dst = &result[0], src = &data[(srcY >> 1) * width + (srcX >> 1)])
|
||||
{
|
||||
var bit0 = Vector256.Create((short)(1 << 2));
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
var a = Avx2.ConvertToVector256Int16(
|
||||
Vector128.Create(*(ulong*)(src + y * width), *(ulong*)(src + (y + 1) * width + 1))
|
||||
.AsByte());
|
||||
var isZero = Avx2.CompareEqual(a, Vector256<short>.Zero);
|
||||
a = Avx2.Add(a, bit0);
|
||||
a = Avx2.AndNot(isZero, a);
|
||||
var b = Sse2.Add(a.GetLower(), a.GetUpper());
|
||||
b = Sse2.ShiftRightLogical(b, 4);
|
||||
b = Sse2.ShiftLeftLogical(b, 3);
|
||||
*(ulong*)(dst + y * 8) = Sse2.PackUnsignedSaturate(b, Vector128<short>.Zero).AsUInt64()
|
||||
.ToScalar();
|
||||
}
|
||||
}
|
||||
|
||||
// for (int y = 0; y < 8; y++)
|
||||
// {
|
||||
// for (int x = 0; x < 8; x++)
|
||||
// {
|
||||
// int a = data[(y + (srcY >> 1)) * width + x + (srcX >> 1)] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[(y + (srcY >> 1) + 1) * width + x + (srcX >> 1) + 1] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// result[y * 8 + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int y = 0; y < 8; y++)
|
||||
{
|
||||
int y1 = Math.Clamp(y + (srcY >> 1), 0, height - 1);
|
||||
int y2 = Math.Clamp(y + (srcY >> 1) + 1, 0, height - 1);
|
||||
for (int x = 0; x < 8; x++)
|
||||
{
|
||||
int x1 = Math.Clamp(x + (srcX >> 1), 0, width - 1);
|
||||
int x2 = Math.Clamp(x + (srcX >> 1) + 1, 0, width - 1);
|
||||
int a = data[y1 * width + x1] >> 3 << 1;
|
||||
if (a != 0)
|
||||
a++;
|
||||
int b = data[y2 * width + x2] >> 3 << 1;
|
||||
if (b != 0)
|
||||
b++;
|
||||
result[y * 8 + x] = (byte)((a * 16 + b * 16) >> 6 << 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// public static unsafe byte[] GetTileHalf(byte[,] data, int srcX, int srcY, int width, int height)
|
||||
// {
|
||||
// var result = new byte[height * width];
|
||||
// if (((srcX | srcY) & 1) == 0)
|
||||
// {
|
||||
// if (srcX >> 1 >= 0 && (srcX >> 1) + width - 1 < data.GetLength(1) &&
|
||||
// srcY >> 1 >= 0 && (srcY >> 1) + height - 1 < data.GetLength(0))
|
||||
// {
|
||||
// fixed (byte* dst = &result[0])
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// {
|
||||
// fixed (byte* src = &data[(srcY >> 1) + y, srcX >> 1])
|
||||
// {
|
||||
// Buffer.MemoryCopy(src, dst + y * width, width, width);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < width; x++)
|
||||
// {
|
||||
// int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1);
|
||||
// int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1);
|
||||
// result[y * width + x] = data[y1, x1];
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if ((srcY & 1) == 0)
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < width; x++)
|
||||
// {
|
||||
// int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1);
|
||||
// int x2 = MathUtil.Clamp(x + (srcX >> 1) + 1, 0, data.GetLength(1) - 1);
|
||||
// int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1);
|
||||
// int a = data[y1, x1] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[y1, x2] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// //(byte) (((data[y1, x1] + data[y1, x2] + 8) >> 1) & 0xF8);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else if ((srcX & 1) == 0)
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < width; x++)
|
||||
// {
|
||||
// int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1);
|
||||
// int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1);
|
||||
// int y2 = MathUtil.Clamp(y + (srcY >> 1) + 1, 0, data.GetLength(0) - 1);
|
||||
// int a = data[y1, x1] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[y2, x1] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// // result[y * width + x] = (byte) (((data[y1, x1] + data[y2, x1] + 8) >> 1) & 0xF8);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// {
|
||||
// for (int x = 0; x < width; x++)
|
||||
// {
|
||||
// int x1 = MathUtil.Clamp(x + (srcX >> 1), 0, data.GetLength(1) - 1);
|
||||
// int x2 = MathUtil.Clamp(x + (srcX >> 1) + 1, 0, data.GetLength(1) - 1);
|
||||
// int y1 = MathUtil.Clamp(y + (srcY >> 1), 0, data.GetLength(0) - 1);
|
||||
// int y2 = MathUtil.Clamp(y + (srcY >> 1) + 1, 0, data.GetLength(0) - 1);
|
||||
// int a = data[y1, x1] >> 3 << 1;
|
||||
// if (a != 0)
|
||||
// a++;
|
||||
// int b = data[y2, x2] >> 3 << 1;
|
||||
// if (b != 0)
|
||||
// b++;
|
||||
// result[y * width + x] = (byte) ((a * 16 + b * 16) >> 6 << 3);
|
||||
// // result[y * width + x] = (byte) (((data[y1, x1] + data[y2, x2] + 8) >> 1) & 0xF8);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return result;
|
||||
// }
|
||||
|
||||
public static void SetTile(byte[,] data, int dstX, int dstY, int width, int height, byte[] src)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
data[y + dstY, x + dstX] = src[y * width + x];
|
||||
}
|
||||
|
||||
public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, int step,
|
||||
byte[] src)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
data[(y * step + dstY) * stride + x * step + dstX] = src[y * width + x];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void SetTile2x2Step2(byte[] data, int stride, int dstX, int dstY, byte[] src)
|
||||
{
|
||||
data[dstY * stride + dstX] = src[0];
|
||||
data[dstY * stride + dstX + 2] = src[1];
|
||||
data[(dstY + 2) * stride + dstX] = src[2];
|
||||
data[(dstY + 2) * stride + dstX + 2] = src[3];
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void SetTile8(byte[] data, int stride, int dstX, int dstY, byte[] src)
|
||||
{
|
||||
fixed (byte* pSrc = &src[0], pDst = &data[dstY * stride + dstX])
|
||||
{
|
||||
*(ulong*)(pDst) = ((ulong*)pSrc)[0];
|
||||
*(ulong*)(pDst + 1 * stride) = ((ulong*)pSrc)[1];
|
||||
*(ulong*)(pDst + 2 * stride) = ((ulong*)pSrc)[2];
|
||||
*(ulong*)(pDst + 3 * stride) = ((ulong*)pSrc)[3];
|
||||
*(ulong*)(pDst + 4 * stride) = ((ulong*)pSrc)[4];
|
||||
*(ulong*)(pDst + 5 * stride) = ((ulong*)pSrc)[5];
|
||||
*(ulong*)(pDst + 6 * stride) = ((ulong*)pSrc)[6];
|
||||
*(ulong*)(pDst + 7 * stride) = ((ulong*)pSrc)[7];
|
||||
}
|
||||
}
|
||||
|
||||
// public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, byte[,] src)
|
||||
// {
|
||||
// for (int y = 0; y < height; y++)
|
||||
// for (int x = 0; x < width; x++)
|
||||
// data[(y + dstY) * stride + x + dstX] = src[y, x];
|
||||
// }
|
||||
|
||||
public static void SetTile(byte[] data, int stride, int dstX, int dstY, int width, int height, int step,
|
||||
byte[,] src)
|
||||
{
|
||||
for (int y = 0; y < height; y++)
|
||||
for (int x = 0; x < width; x++)
|
||||
data[(y * step + dstY) * stride + x * step + dstX] = src[y, x];
|
||||
}
|
||||
|
||||
public static unsafe byte[] GetBlockPixels16x16(byte[] Data, int X, int Y, int Stride, int Offset)
|
||||
{
|
||||
byte[] values = new byte[256];
|
||||
fixed (byte* pVals = &values[0])
|
||||
{
|
||||
ulong* pLVals = (ulong*)pVals;
|
||||
for (int y3 = 0; y3 < 16; y3++)
|
||||
{
|
||||
fixed (byte* pData = &Data[(Y + y3) * Stride + X + Offset])
|
||||
{
|
||||
*pLVals++ = *((ulong*)pData);
|
||||
*pLVals++ = *((ulong*)(pData + 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static unsafe byte[] GetBlockPixels8x8(byte[] Data, int X, int Y, int Stride, int Offset)
|
||||
{
|
||||
byte[] values = new byte[64];
|
||||
fixed (byte* pVals = &values[0], pData = &Data[Y * Stride + X + Offset])
|
||||
{
|
||||
ulong* pLVals = (ulong*)pVals;
|
||||
*pLVals++ = *((ulong*)pData);
|
||||
*pLVals++ = *((ulong*)(pData + Stride));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 2));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 3));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 4));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 5));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 6));
|
||||
*pLVals++ = *((ulong*)(pData + Stride * 7));
|
||||
/*ulong* pLVals = (ulong*)pVals;
|
||||
for (int y3 = 0; y3 < 8; y3++)
|
||||
{
|
||||
fixed (byte* pData = &Data[(Y + y3) * Stride + X + Offset])
|
||||
{
|
||||
*pLVals++ = *((ulong*)pData);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static unsafe byte[] GetBlockPixels4x4(byte[] Data, int X, int Y, int Stride, int Offset)
|
||||
{
|
||||
byte[] values = new byte[16];
|
||||
fixed (byte* pVals = &values[0], pData = &Data[Y * Stride + X + Offset])
|
||||
{
|
||||
uint* pLVals = (uint*)pVals;
|
||||
*pLVals++ = *((uint*)pData);
|
||||
*pLVals++ = *((uint*)(pData + Stride));
|
||||
*pLVals++ = *((uint*)(pData + Stride * 2));
|
||||
*pLVals++ = *((uint*)(pData + Stride * 3));
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static unsafe void SetBlockPixels4x4(byte[] Data, int X, int Y, int Stride, int Offset, byte[] Values)
|
||||
{
|
||||
fixed (byte* pVals = &Values[0], pData = &Data[Y * Stride + X + Offset])
|
||||
{
|
||||
uint* pLVals = (uint*)pVals;
|
||||
*((uint*)pData) = *pLVals++;
|
||||
*((uint*)(pData + Stride)) = *pLVals++;
|
||||
*((uint*)(pData + Stride * 2)) = *pLVals++;
|
||||
*((uint*)(pData + Stride * 3)) = *pLVals++;
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void SetBlockPixels8x8(byte[] Data, int X, int Y, int Stride, int Offset, byte[] Values)
|
||||
{
|
||||
fixed (byte* pVals = &Values[0], pData = &Data[Y * Stride + X + Offset])
|
||||
{
|
||||
ulong* pLVals = (ulong*)pVals;
|
||||
*((ulong*)pData) = *pLVals++;
|
||||
*((ulong*)(pData + Stride)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 2)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 3)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 4)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 5)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 6)) = *pLVals++;
|
||||
*((ulong*)(pData + Stride * 7)) = *pLVals++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static unsafe int Sad64(ReadOnlySpan<byte> a, ReadOnlySpan<byte> b)
|
||||
{
|
||||
fixed (byte* pA = a, pB = b)
|
||||
{
|
||||
var a0 = Avx.LoadVector256(pA);
|
||||
var b0 = Avx.LoadVector256(pB);
|
||||
var sad0 = Avx2.SumAbsoluteDifferences(a0, b0);
|
||||
var a1 = Avx.LoadVector256(pA + 32);
|
||||
var b1 = Avx.LoadVector256(pB + 32);
|
||||
var sad1 = Avx2.SumAbsoluteDifferences(a1, b1);
|
||||
var diff = Avx2.Add(sad0.AsInt32(), sad1.AsInt32());
|
||||
var diff2 = Sse2.Add(diff.GetLower(), diff.GetUpper());
|
||||
return diff2.GetElement(0) + diff2.GetElement(2);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe ulong Sad(ReadOnlySpan<byte> a, ReadOnlySpan<byte> b)
|
||||
{
|
||||
var sad = Vector256<ulong>.Zero;
|
||||
ulong result;
|
||||
fixed (byte* pA0 = a, pB0 = b)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i + 31 < a.Length; i += 32)
|
||||
{
|
||||
var a0 = Avx.LoadVector256(pA0 + i);
|
||||
var b0 = Avx.LoadVector256(pB0 + i);
|
||||
sad = Avx2.Add(sad, Avx2.SumAbsoluteDifferences(a0, b0).AsUInt64());
|
||||
}
|
||||
|
||||
var result2 = Sse2.Add(sad.GetLower(), sad.GetUpper());
|
||||
result = result2.GetElement(0) + result2.GetElement(1);
|
||||
for (; i < a.Length; i++)
|
||||
result += (ulong)Math.Abs(pA0[i] - pB0[i]);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
207
Gericom.FastVideoDS/Vlc.cs
Normal file
207
Gericom.FastVideoDS/Vlc.cs
Normal file
@ -0,0 +1,207 @@
|
||||
using Gericom.FastVideoDS.Bitstream;
|
||||
|
||||
namespace Gericom.FastVideoDS
|
||||
{
|
||||
public static class Vlc
|
||||
{
|
||||
public static readonly int[] BitLengthTable;
|
||||
|
||||
static Vlc()
|
||||
{
|
||||
BitLengthTable = new int[2 * 64 * 128];
|
||||
ushort[] tabA = VlcTables.TableA;
|
||||
byte[] tabB = VlcTables.TableB;
|
||||
for (int last = 0; last <= 1; last++)
|
||||
{
|
||||
for (int skip = 0; skip < 64; skip++)
|
||||
{
|
||||
for (int value = -64; value < 64; value++)
|
||||
{
|
||||
int val = value;
|
||||
if (val < 0)
|
||||
val = -val;
|
||||
if (val <= 31)
|
||||
{
|
||||
int idx = VlcTables.TableARefLinear[val * 64 * 2 + skip * 2 + last];
|
||||
if (idx >= 0)
|
||||
{
|
||||
BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = tabA[idx] & 0xF;
|
||||
continue;
|
||||
}
|
||||
|
||||
int newskip = skip - tabB[(val | (last << 6)) + 0x80];
|
||||
if (newskip >= 0)
|
||||
{
|
||||
idx = VlcTables.TableARefLinear[val * 64 * 2 + newskip * 2 + last];
|
||||
if (idx >= 0)
|
||||
{
|
||||
BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 9 + (tabA[idx] & 0xF);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int newval = val - tabB[skip | (last << 6)];
|
||||
if (newval >= 0 && newval <= 31)
|
||||
{
|
||||
int idx = VlcTables.TableARefLinear[newval * 64 * 2 + skip * 2 + last];
|
||||
if (idx >= 0)
|
||||
{
|
||||
BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 8 + (tabA[idx] & 0xF);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
BitLengthTable[last * 128 * 64 + skip * 128 + (value + 64)] = 28;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int CalcDctBitCount(int[] dct)
|
||||
{
|
||||
int lastNonZero = 0;
|
||||
for (int i = dct.Length - 1; i >= 0; i--)
|
||||
{
|
||||
if (dct[i] != 0)
|
||||
{
|
||||
lastNonZero = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return CalcDctBitCount(dct, lastNonZero);
|
||||
}
|
||||
|
||||
public static int CalcDctBitCount(int[] dct, int lastNonZero)
|
||||
{
|
||||
int bitCount = 0;
|
||||
|
||||
int skip = 0;
|
||||
for (int i = 0; i < lastNonZero; i++)
|
||||
{
|
||||
if (dct[i] == 0)
|
||||
{
|
||||
skip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int val = dct[i];
|
||||
if (val + 64 < 128)
|
||||
bitCount += BitLengthTable[(skip * 128) + (val + 64)];
|
||||
else
|
||||
bitCount += 28;
|
||||
skip = 0;
|
||||
}
|
||||
|
||||
if (dct[lastNonZero] + 64 < 128)
|
||||
bitCount += BitLengthTable[128 * 64 + (skip * 128) + (dct[lastNonZero] + 64)];
|
||||
else
|
||||
bitCount += 28;
|
||||
|
||||
return bitCount;
|
||||
}
|
||||
|
||||
public static void EncodeDct(int[] dct, BitWriter b)
|
||||
{
|
||||
ushort[] tabA = VlcTables.TableA;
|
||||
byte[] tabB = VlcTables.TableB;
|
||||
int lastNonZero = 0;
|
||||
for (int i = 0; i < dct.Length; i++)
|
||||
{
|
||||
if (dct[i] != 0)
|
||||
lastNonZero = i;
|
||||
}
|
||||
|
||||
int skip = 0;
|
||||
for (int i = 0; i < dct.Length; i++)
|
||||
{
|
||||
if (dct[i] == 0 && lastNonZero != 0)
|
||||
{
|
||||
skip++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int val = dct[i];
|
||||
|
||||
if (val < 0) val = -val;
|
||||
if (val <= 31)
|
||||
{
|
||||
int idx = VlcTables.TableARefLinear[val * 64 * 2 + skip * 2 + ((i == lastNonZero) ? 1 : 0)];
|
||||
if (idx >= 0)
|
||||
{
|
||||
int nrbits = (tabA[idx] & 0xF);
|
||||
uint tidx = (uint)idx;
|
||||
if (nrbits < 12)
|
||||
tidx >>= (12 - nrbits);
|
||||
else if (nrbits > 12)
|
||||
tidx <<= (nrbits - 12);
|
||||
if (dct[i] < 0) tidx |= 1;
|
||||
b.WriteBits((uint)tidx, nrbits);
|
||||
skip = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
int newskip = skip - tabB[(val | (((i == lastNonZero) ? 1 : 0) << 6)) + 0x80];
|
||||
if (newskip >= 0)
|
||||
{
|
||||
idx = VlcTables.TableARefLinear[
|
||||
val * 64 * 2 + newskip * 2 +
|
||||
((i == lastNonZero) ? 1 : 0)];
|
||||
if (idx >= 0)
|
||||
{
|
||||
b.WriteBits(3, 7);
|
||||
b.WriteBits(1, 1);
|
||||
b.WriteBits(0, 1);
|
||||
int nrbits = (tabA[idx] & 0xF);
|
||||
uint tidx = (uint)idx;
|
||||
if (nrbits < 12)
|
||||
tidx >>= (12 - nrbits);
|
||||
else if (nrbits > 12)
|
||||
tidx <<= (nrbits - 12);
|
||||
if (dct[i] < 0) tidx |= 1;
|
||||
b.WriteBits((uint)tidx, nrbits);
|
||||
skip = 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int newval = val - tabB[skip | (((i == lastNonZero) ? 1 : 0) << 6)];
|
||||
if (newval >= 0 && newval <= 31)
|
||||
{
|
||||
int idx = VlcTables.TableARefLinear[newval * 64 * 2 + skip * 2 + ((i == lastNonZero) ? 1 : 0)];
|
||||
if (idx >= 0)
|
||||
{
|
||||
b.WriteBits(3, 7);
|
||||
b.WriteBits(0, 1);
|
||||
int nrbits = (tabA[idx] & 0xF);
|
||||
uint tidx = (uint)idx;
|
||||
if (nrbits < 12)
|
||||
tidx >>= (12 - nrbits);
|
||||
else if (nrbits > 12)
|
||||
tidx <<= (nrbits - 12);
|
||||
if (dct[i] < 0) tidx |= 1;
|
||||
b.WriteBits((uint)tidx, nrbits);
|
||||
skip = 0;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
b.WriteBits(3, 7);
|
||||
b.WriteBits(1, 1);
|
||||
b.WriteBits(1, 1);
|
||||
if (i == lastNonZero)
|
||||
b.WriteBits(1, 1);
|
||||
else
|
||||
b.WriteBits(0, 1);
|
||||
b.WriteBits((uint)skip, 6);
|
||||
skip = 0;
|
||||
b.WriteBits((uint)dct[i], 12);
|
||||
end:
|
||||
if (i == lastNonZero)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
327
Gericom.FastVideoDS/VlcTables.cs
Normal file
327
Gericom.FastVideoDS/VlcTables.cs
Normal file
@ -0,0 +1,327 @@
|
||||
namespace Gericom.FastVideoDS
|
||||
{
|
||||
public static class VlcTables
|
||||
{
|
||||
public static readonly ushort[] TableA =
|
||||
{
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x807C, 0x807C, 0x806C, 0x806C, 0x016C, 0x016C, 0x015C, 0x015C,
|
||||
0x842B, 0x842B, 0x842B, 0x842B, 0x823B, 0x823B, 0x823B, 0x823B, 0x805B, 0x805B, 0x805B, 0x805B, 0x1A1B, 0x1A1B, 0x1A1B, 0x1A1B,
|
||||
0x0A3B, 0x0A3B, 0x0A3B, 0x0A3B, 0x102B, 0x102B, 0x102B, 0x102B, 0x083B, 0x083B, 0x083B, 0x083B, 0x064B, 0x064B, 0x064B, 0x064B,
|
||||
0x044B, 0x044B, 0x044B, 0x044B, 0x027B, 0x027B, 0x027B, 0x027B, 0x014B, 0x014B, 0x014B, 0x014B, 0x013B, 0x013B, 0x013B, 0x013B,
|
||||
0x017C, 0x017C, 0x018C, 0x018C, 0x028C, 0x028C, 0x122C, 0x122C, 0x862C, 0x862C, 0x882C, 0x882C, 0x9E1C, 0x9E1C, 0xA01C, 0xA01C,
|
||||
0x019D, 0x01AD, 0x01BD, 0x029D, 0x0C3D, 0x02AD, 0x045D, 0x0E3D, 0x1C1D, 0x808D, 0x8A2D, 0x8C2D, 0xA21D, 0xA41D, 0xA61D, 0xA81D,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001,
|
||||
0x012B, 0x012B, 0x012B, 0x012B, 0x011B, 0x011B, 0x011B, 0x011B, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A, 0x9C1A,
|
||||
0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x9A1A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A, 0x981A,
|
||||
0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x961A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A, 0x941A,
|
||||
0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x822A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A, 0x804A,
|
||||
0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x181A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A, 0x161A,
|
||||
0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0E2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A, 0x0C2A,
|
||||
0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x0A2A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A, 0x063A,
|
||||
0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x043A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A, 0x026A,
|
||||
0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x025A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A, 0x010A,
|
||||
0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x082A, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA, 0x00FA,
|
||||
0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00EA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA, 0x00DA,
|
||||
0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019, 0x9019,
|
||||
0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19, 0x8E19,
|
||||
0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19, 0x8C19,
|
||||
0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039, 0x8039,
|
||||
0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419, 0x1419,
|
||||
0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219, 0x1219,
|
||||
0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019, 0x1019,
|
||||
0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219, 0x9219,
|
||||
0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629, 0x0629,
|
||||
0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249, 0x0249,
|
||||
0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9, 0x00C9,
|
||||
0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9, 0x00B9,
|
||||
0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9, 0x00A9,
|
||||
0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818,
|
||||
0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818, 0x8818,
|
||||
0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618,
|
||||
0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618, 0x8618,
|
||||
0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18,
|
||||
0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18, 0x0C18,
|
||||
0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18,
|
||||
0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18, 0x8A18,
|
||||
0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18,
|
||||
0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18, 0x0E18,
|
||||
0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428,
|
||||
0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428, 0x0428,
|
||||
0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238,
|
||||
0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238, 0x0238,
|
||||
0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098,
|
||||
0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098, 0x0098,
|
||||
0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027,
|
||||
0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027,
|
||||
0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027,
|
||||
0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027, 0x8027,
|
||||
0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17,
|
||||
0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17,
|
||||
0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17,
|
||||
0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17, 0x0A17,
|
||||
0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417,
|
||||
0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417,
|
||||
0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417,
|
||||
0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417, 0x8417,
|
||||
0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217,
|
||||
0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217,
|
||||
0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217,
|
||||
0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217, 0x8217,
|
||||
0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817,
|
||||
0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817,
|
||||
0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817,
|
||||
0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817, 0x0817,
|
||||
0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617,
|
||||
0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617,
|
||||
0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617,
|
||||
0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617, 0x0617,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087, 0x0087,
|
||||
0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077,
|
||||
0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077,
|
||||
0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077,
|
||||
0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077, 0x0077,
|
||||
0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227,
|
||||
0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227,
|
||||
0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227,
|
||||
0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227,
|
||||
0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067,
|
||||
0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067,
|
||||
0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067,
|
||||
0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067, 0x0067,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416, 0x0416,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056, 0x0056,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046, 0x0046,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015, 0x8015,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013, 0x0013,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024, 0x0024,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215, 0x0215,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035,
|
||||
0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035, 0x0035
|
||||
};
|
||||
|
||||
public static readonly byte[] TableB =
|
||||
{
|
||||
0x1B, 0x0A, 0x05, 0x04,
|
||||
0x03, 0x03, 0x03, 0x03, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x08, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x01, 0x0F, 0x0A, 0x08, 0x04, 0x03, 0x02, 0x02,
|
||||
0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x15, 0x07, 0x02,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01
|
||||
};
|
||||
|
||||
public static readonly int[] TableARefLinear =
|
||||
{
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
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,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user