Initial commit

This commit is contained in:
Gericom 2022-10-13 11:27:48 +02:00
commit 9aa251ee1d
34 changed files with 5607 additions and 0 deletions

63
.gitattributes vendored Normal file
View 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
View 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
View 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
View 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;
}
}
}

View 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);
}
}
}

View 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>

View 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}");
}
}
}
}

View 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);
});
}
}
}

View File

@ -0,0 +1,7 @@
{
"profiles": {
"FastVideoDSEncoder": {
"commandName": "Project"
}
}
}

View 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);
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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>

View 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++;
}
}
}
}

View File

@ -0,0 +1,7 @@
{
"profiles": {
"FastVideoDSInfo": {
"commandName": "Project"
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

View 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);
}
}
}

View 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();
}
}
}

View 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;
// }
}
}

View 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>

View 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;
}
}
}

View 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);
}
}

View 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
View 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;
}
}
}
}

View 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,
};
}
}