View Full Version : AviSynth+ thread Vol.2
Dogway
29th October 2021, 09:35
A few things I observed, converting from RGB to YUV in float bitdepth.
ConvertToyuv420(matrix="PC.709")
Output is greyscale, not sure if this is intended.
I was also benchmarking my metrics function to see if it had a slowdown compared to vanilla and observed it was like 30% slower the culprit being propCopy(). I'm not sure it can be sped up, a simple (yet too verbose) Get+Set has no speed penalty. I think propCopy also wants identical clips (bitdepth, resolution, format)?
DTL
29th October 2021, 10:30
In my script I'm offering 3 upsampling methods: bicubic(0, .5), nnedi3 and ChromaFeconstructor_faster
In any case, built-in methods should allow configuring b and c parameters when upsampling.
I'm looking for numerically-accurate data for better processing in YUV444, and Bicubic(0, .5) is the most numerically accurate.
There are minimum 2 different types of subsampled to 4:4:4 convertors - for intermediate processing work (with packing back to subsampled at output) and for final result (for displaying without additional distortions). It is because of design of subsampled colour systems with conditioning of luma data at source side but conditioning of chroma data at receiver side. It is to decrease loss of chroma sharpness at the many generations of subsampled<->full_band conversions.
But 'final' result is when frame samples number is not changed. If resizing is performed - it may be better to use 'final' conversion before resize and may be other processing.
So 4:4:4 output of 'intermediate' type convertor will be 'distorted'.
The 'intermediate' type 'linear' convertto444 have 'flat' chroma channels frequency response (close to sinc-resize) and 'final' have 'slow rolloff' type like gauss-resize (or better). The worst news here is that the standard frequency response of the 'final/displaying' conditioning filter of convertto444 not exist. It either supposed to be known by designer (from common DSP) or still up to designer's of current conversion taste. It also mean the 'perfect convertto_subsampled' still can not be designed because it depends on the backward conversion.
The current defaults for convertto444 may be selected to be in-between of 'intermediate' and 'final' conversions so average user without many generations of conversion from and to subsampled will not got more chroma blurring but also if trying to use it as 'final' conversion - do not got more over/undershooting and/or ringing. So it may be sort of 'fail-safe' defaults for average low-experienced user.
MysteryX
29th October 2021, 14:59
DTL, I don't think ConvertToYUV444 is anywhere that sophisticated in terms of "balance". It does a plain resize, with whatever resizer you want, whether Spline36, Gauss or Bicubic. Although it allows changing the resizer, it just doesn't allow changing Bicubic values and keeps the defaults. I think that's all there is to it.
DTL
29th October 2021, 15:15
"ConvertToYUV444"
It not named ConvertToFin444() and ConvertToImm444(), so it have some hidden default inside. And the description allow to select any of available built-in resampler's kernel just to pick possibly better for current task. And typically the request to pass arguments to parametrical kernels looks like very rare (because it looks most of users possibly even not need different from default kernel).
I personally hope the awful shadows of the poor past with subsampled chroma compression will be deprecated at some day so we finally can forgot these conversions. It is already put to grave interlace-compression so I hope in some day the subsampled-compression and even transfer-function-compression will also be killed.
Also this conversion is sort of built-in macro for a sequence of separate-resample-combine planes operations. And possibly the user-defined function will have close performance and can use any required resampler. As I see programmers do not likes an idea to pack long macro into one function with tons of params for each used in macro simple function.
The sad truth of this function is hidden - correct name is not convert but DecompressColourTo(Final/Immediate)444(). So when you use modern (U)HDTV in 2021 not in 4:4:4 you still see ugly ancient colour-compressed system designed half+ century ago.
Nowdays as Avisynth progress it start to have many _clip properties to assist of auto-options selection to prevent gross-errors by low experienced users. So it is good to set property of colour-decompressed data in 4:4:4 format to be 'flat' or 'conditioned' (and band-limited to 1/2h and or 1/2v) colour-difference spectrum. So the hint-aware next processing software can use it. Like resize after decompressto444 with 'flat, (1/2v), 1/2h' chroma-diff spectrum properties need additional colour-difference conditioning inside 1/2 allowed frequency band operation before resampling.
MysteryX
29th October 2021, 15:33
Here:
https://github.com/realfinder/AVS-Stuff/blob/Community/avs%202.6%20and%20up/nnedi3_resize16.avsi
What parameter to change subsampling?
MysteryX
29th October 2021, 15:37
I personally hope the awful shadows of the poor past with subsampled chroma compression will be deprecated at some day so we finally can forgot these conversions.
Even if it got deprecated, you'd still have to deal with it in the majority of videos already produced.
And with 4K and 8K videos, we're heading towards more compression, not less compression. Bandwidth is becoming even more important than before. Reducing Chroma compression would mean losing Luma details. That's the reason subsampling was created to begin with. And for 8K footage, subsampling becomes so tiny that it has much less impact than it used to be; yet huge compressibility benefits.
Although. With the move from Pixel-based videos to Vector-based videos, subsampling might indeed become a thing of the past? I still doubt it.
DTL
29th October 2021, 16:11
"And with 4K and 8K videos, we're heading towards more compression, not less compression. Bandwidth is becoming even more important than before. Reducing Chroma compression would mean losing Luma details. That's the reason subsampling was created to begin with. And for 8K footage, subsampling becomes so tiny that it has much less impact than it used to be; yet huge compressibility benefits."
If current (progressing) civilization claims to make better quality video systems it is good to deprecate old poor and ugly compression systems. The progress is very slow - to 2021 only 2:1 compression of interlacing scan finally going to death.
Also it is good to exchange poor old compression methods to new higher quality. So 4:2:0/4:2:2 chroma-compression put distortions that can not be fixed by MPEG compression stage. But current MPEG put less distortions into 4:4:4 footage with same output bitrate as 4:2:0+MPEG. MPEG have much more advanced colour-treatment and compression methods in compare with poor old ugly '2:1 subsampling'. And MPEG have tons of updates at half of century interval (from MPEG-1 to current 265+). But poor ugly old chroma-subsampling compression still not completely documented and have zero updates.
I make tests with 4:4:4-version of x264 - it creates even less output bitrate if feeded with 4:4:4 version (same crf-value encoding) - not 2x larger as may be expected. But 4:4:4 x264 is not compatible with poor-people viewing hardware.
DTL
29th October 2021, 16:26
"move from Pixel-based"
It is one source why Avisynth is poor in many places for processing of professional samples-based motion pictures data. It is directly connected to the resampling and 4:2:x to 4:4:4 too.
It looks was started by computer pixel-based programmers. And lately more or less supplemented with sample-based methods of processing. But still far from complete.
kedautinh12
29th October 2021, 16:58
What parameter to change subsampling?
What do you mean?? It's right??
https://github.com/realfinder/AVS-Stuff/blob/cd4e6e41ba7c50be2e824a22d45935bb50986cb7/avs%202.6%20and%20up/nnedi3_resize16.avsi#L190
MysteryX
29th October 2021, 17:05
What do you mean?? It's right??
https://github.com/realfinder/AVS-Stuff/blob/cd4e6e41ba7c50be2e824a22d45935bb50986cb7/avs%202.6%20and%20up/nnedi3_resize16.avsi#L190
Chroma placement is something else. I need to say "upscale this clip from 420 to 444". Then it does need to know whether "420" has MPEG1 or MPEG2 chroma position before converting it to "444". NNEDI3 can work well for chroma upsampling because it's an exact double resolution.
FranceBB
29th October 2021, 19:13
Then it does need to know whether "420" has MPEG1 or MPEG2 chroma position before converting it to "444".
Or the new hellish top_left (i.e 4:2:0 type 2) and honestly we would have been living happily without it nowadays. I still don't understand why they decided to change it...
pinterf
30th October 2021, 07:39
A few things I observed, converting from RGB to YUV in float bitdepth.
ConvertToyuv420(matrix="PC.709")
Output is greyscale, not sure if this is intended.
I was also benchmarking my metrics function to see if it had a slowdown compared to vanilla and observed it was like 30% slower the culprit being propCopy(). I'm not sure it can be sped up, a simple (yet too verbose) Get+Set has no speed penalty. I think propCopy also wants identical clips (bitdepth, resolution, format)?
Greyscale is definitely not intended. Slowdown: don't know why, worth to understand its reason. Problem registered.
EDIT: greyscale problem is fixed on my test bench.
DTL
31st October 2021, 12:38
Also why ConvertTo444 is of not best quality: It is better to make scaling in 'linear domain'. But CbCr data typically (and by standard) obtained from R'G'B' non-linear data. So to make simple upscaling of chroma data for 4:4:4 it is required long quest (and still not perfect): Make Y' half size (it is typically not delivered to decompressor - but inside Avisynth environment it is possible in theory). Y' is not-linear so simple dowscaling to 1/2 is not perfect. To dematrix half size chroma with Y' half size to get R'G'B' half size - de-transfer to linear RGB - finally upscale half size RGB to half-band full-size RGB - transfer to R'G'B' and matrix to Y'CbCr full size for combine to output 4:4:4.
The simple upscale of CbCr in its delivering non-linear domain is only partially good idea.
DTL
1st November 2021, 14:03
I found one place of large enough memalloc in DeviceManager.cpp -> CPUDevice class and put simple enough patch:
class CPUDevice : public Device {
public:
CPUDevice(InternalEnvironment* env)
: Device(DEV_TYPE_CPU, 0, 0, env)
{
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tp;
// Enable this priveledge for the current process
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
{
env->ThrowError("LargePages: Can not open process token");
return;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &tp.Privileges[0].Luid))
{
env->ThrowError("LargePages: LookupPrivilegeValue failed.");
return;
}
BOOL result = AdjustTokenPrivileges(hToken, FALSE, &tp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
DWORD error = GetLastError();
if (!result || (error != ERROR_SUCCESS))
{
env->ThrowError("LargePages: AdjustTokenPrivileges failed.");
return;
}
// Cleanup
CloseHandle(hToken);
hToken = NULL;
}
virtual int SetMemoryMax(int mem)
{
// memory_max for CPU device is not implemented here.
env->ThrowError("Not implemented ...");
return 0;
}
virtual BYTE* Allocate(size_t size, int margin)
{
size += margin;
#ifdef _DEBUG
// large pages
SIZE_T stLPGranularity = GetLargePageMinimum();
size_t iNumLPUnits = size / stLPGranularity;
SIZE_T stSizeToAlloc = (iNumLPUnits + 1) * stLPGranularity;
BYTE* data = (BYTE*)VirtualAlloc(0, stSizeToAlloc, MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
DWORD error = GetLastError();
if (error != ERROR_SUCCESS)
env->ThrowError("LargePages alloc error. GetLastError returned: %d\n", error);
// BYTE* data = new BYTE[size + 16];
int *pInt = (int *)(data + size);
pInt[0] = 0xDEADBEEF;
pInt[1] = 0xDEADBEEF;
pInt[2] = 0xDEADBEEF;
pInt[3] = 0xDEADBEEF;
static const BYTE filler[] = { 0x0A, 0x11, 0x0C, 0xA7, 0xED };
BYTE* pByte = data;
BYTE* q = pByte + size / 5 * 5;
for (; pByte < q; pByte += 5)
{
pByte[0] = filler[0];
pByte[1] = filler[1];
pByte[2] = filler[2];
pByte[3] = filler[3];
pByte[4] = filler[4];
}
return data;
#else
// return new BYTE[size + 16];
// large pages
SIZE_T stLPGranularity = GetLargePageMinimum();
size_t iNumLPUnits = size / stLPGranularity;
SIZE_T stSizeToAlloc = (iNumLPUnits + 1) * stLPGranularity;
BYTE* data = (BYTE*)VirtualAlloc(0, stSizeToAlloc, MEM_LARGE_PAGES | MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
DWORD error = GetLastError();
if (error != ERROR_SUCCESS)
env->ThrowError("LargePages alloc error. GetLastError returned: %d\n", error);
return data;
#endif
}
virtual void Free(BYTE* ptr)
{
if (ptr != nullptr) {
// large pages here
VirtualFree(ptr, 0, MEM_RELEASE);
// delete[] ptr;
}
}
It works but not enough - somewhere still many 'standard' allocations:
Current stat at 4K MDegrainN with tr=6:
About 1 GB in large pages, about 300 Mb in standard pages, PageTable size of all AVSMeter process about 1.7 MB.
Standard AVS 3.6 (latest download from repository 3.7-master do not builds in Release at me with VS2019) - total standard pages about 1.6 GB and PageTable size about 3.7 MB. I use RAMMap tool to check - https://docs.microsoft.com/ru-ru/sysinternals/downloads/rammap .
For compare - xmrig with 2 GB total memory have PageTable 5 MB with standard pages and 300K with large pages.
Maybe someone with more knowlege in AVS core can point to other places of residual memory allocations (in avs core ?) ? I try to search 'new/delete' pairs now.
FranceBB
1st November 2021, 15:27
Is Prefetch() NUMA Node aware?
I can't seem to be able to make use of two CPUs at the same time, no matter how many threads I set :(
In a dual socket motherboard, it always uses either CPU0 or CPU1.
This way I can only use up to 28c/56th but I have 2 CPUs 28c/56th each, so I'd like to make use of 56c/112th :(
kedautinh12
1st November 2021, 15:57
Rich boy :D
FranceBB
1st November 2021, 16:12
Rich boy :D
When your company has the "kaching"
https://media2.giphy.com/media/hrQnFqUKTXwSSvH8AI/200.gif
DJATOM
1st November 2021, 17:06
Is Prefetch() NUMA Node aware?
I can't seem to be able to make use of two CPUs at the same time, no matter how many threads I set :(
In a dual socket motherboard, it always uses either CPU0 or CPU1.
This way I can only use up to 28c/56th but I have 2 CPUs 28c/56th each, so I'd like to make use of 56c/112th :(
I did observe that effect with x265. For dual CPU systems, it's loading all 16 threads on CPU0 and CPU1 is mostly idling. Maybe something is wrong in the Windows server OS, I don't know that.
DTL
1st November 2021, 17:41
Is Prefetch() NUMA Node aware?
I can't seem to be able to make use of two CPUs at the same time, no matter how many threads I set :(
In a dual socket motherboard, it always uses either CPU0 or CPU1.
This way I can only use up to 28c/56th but I have 2 CPUs 28c/56th each, so I'd like to make use of 56c/112th :(
As followed from https://gcc.gnu.org/bugzilla/attachment.cgi?id=44273 the new application wanting to run > 64threads at > 64 processors must check number of processors groups and number of processor threads (in each group) and expicitly assign > 64 threads to different processors groups. It is significant multithreading re-write of application. The 'free/auto' multuthreading by OS support is limited to 64 processors of 1 group. No more 'auto-sheduling' of the 1 easy to create threadpool between > 64 processors. Now application need to create different sets of threads with max 64 threads in each set and assign to different processors groups. The new multi-processor-groups AVS version is needed.
And it still not guaranteed any good performance scaling with > 64 threads because typical MT model assumes about equal access of different threads to units of data in memory and different processor group may have (and possibly will have) not equal. So it is required to re-design MultiThreaded data processign functions to be MultiGroup-MultiThreaded aware for best performance.
Dogway
1st November 2021, 22:18
Maybe ConvertBits() could write to frameprops, it might be useful for example for AvSpmod which doesn't know bitdepth of output clip, so it can show proper info.
Also chained comparisons are not supported in Expr() right? (3 <= x <= 5) Not sure if that would save any performance though.
Yesterday I was playing with Prefetch(), since it is well known that convolutions perform better with physical cores and long expressions better with logical I tested to run something like:
Convolution
Prefetch(4)
Expression
Prefetch(6) # normally better than 8 for my 4C/8T CPU
It happened to perform worse than just running everything with Prefetch(6). Not sure what to extract from it, just some insight.
pinterf
2nd November 2021, 08:38
VapourSynth developers were experimenting with large pages since 2018. Finally the idea was abandoned. Check commit history and search for 'page'.
'Add implementation', 'add hack to disable', 'disable if Windows is broken', 'disable in release build'. I think I trust them.
pinterf
2nd November 2021, 08:50
Maybe ConvertBits() could write to frameprops, it might be useful for example for AvSpmod which doesn't know bitdepth of output clip, so it can show proper info.
? AvsPMod knows everything about the clip format.
Also chained comparisons are not supported in Expr() right? (3 <= x <= 5) Not sure if that would save any performance though.
Not supported of course.
DTL
2nd November 2021, 10:27
Yes - large page option is not for everyday use of typical user. It is still server-class feature even in the win10 and most easy to use in system-startup services. With application it still may easy fail allocation with 'not enough resources' error after some time after system startup. So even win10 memory manager still not like to defragment memory. Also at different versions of win10 may not allowed even to have >1 processes with large page using. Need to close previous large page using application to start new. So it not comfortable for everyday use feature and only may be useful for external plugins with random enough use of large memory arrays. Most of AVS core functions like RGBAdjust() uses sequential scan and 1 access per sample for process so possibly will not any gain from large pages.
Unfortunately some external plugins like MVtools do not use internal memory management and were specially re-written for AVS memory management and caching so the only way to use large pages in MVtools is to have AVS core modified.
tormento
2nd November 2021, 12:25
Yes - large page option is not for everyday use of typical user. It is still server-class feature even in the win10 and most easy to use in system-startup services.
If my memory recalls it correctly, 7-Zip has a large page option since years and I am currently using it on Win 11 Enterprise with marginal differences.
Dogway
2nd November 2021, 13:14
? AvsPMod knows everything about the clip format.
Then I might have had the wrong impression from this post (https://forum.doom9.org/showthread.php?p=1942719#post1942719)
DTL
2nd November 2021, 14:34
large page option"
It can try but if allocation call fails - perform silent fallback to standard 4kB pages. I still not know if it possible to force windows to perform memory defragmentation and avoid reboot if it returns 'out of resources' return code. Avisynth looks like do not have log messages output for standard user so it may be not possible to display if it use large pages or not. The only indirect way is to check memory usage - the large page allocations typically not visible in most of memory using display software (AVSMeter also do not see it). So if it really used the displayed amount of memory in taskanager starts to become low (in most of available columns). Even RAMmap tool do not display number of largepages per process - only total number of largepages in the system.
It looks the application mostly benefits from large page when it uses small number of large size structures. Avisynth partially meet the requirement when uses small number of large video frame buffers of several MB in size. But it looks only part of total used memory (about 2/3). Other part looks like some structures of cache that may be uses copy of C++ objects made by even not AVS core but some external C++ library. I still do not found the place where it allocates lots of memory after parsing the script and walking through Manalyse and Mdegrain and finally after the Preftech(). It looks it somewhere at preparation lots of copies of objects for multithreading. To get full advantage of large pages the PageTable need to be small enough - the 2GB memory in 2 MB pages and 8byte per PageTable entry can be only 8 kByte in size. But now Avisynth uses about 1.7 MB PageTable for about 300 MB allocation outside the CPUDevice video buffers.
I need to found some memory display debug software to show each memory allocation by software and its size - to view how many total separated allocations and to pick largest first. But if Avisynth programmers were too lazy and uses lots of very small allocations - it will also overload PagesTable because it require at least one page per allocation and one entry in PT. And uses 2MB pages per very small allocations will overuse the memory. So to full benefit from large pages programmers need to be more smart to uses large structures up to 2MB page size in small amout of structures.
As i remember there exist some tools for detecting memory leaks and can display all allocations by current process. But may be something already exist in VisualStudio (I currently trying to set 2019 at home because it looks like have better CMake support for AVS compiling) ?
FranceBB
2nd November 2021, 15:54
Then I might have had the wrong impression from this post (https://forum.doom9.org/showthread.php?p=1942719#post1942719)
AVSPmod knows about high bit depth, however due to the python library implementation, the preview will always be 8bit, therefore, if you work in 16bit and you use a color picker on the AVSPmod preview, every value will be scaled down to its corresponding 8bit value. It's always been like this: it was like this with 16bit stacked and interleave and it's like this with 16bit planar. Unfortunately there isn't much we can do. It's actually also the reason why we can't have BT2020 displayed properly despite using Windows 10 or Windows 11 and a BT2020 capable display. :(
Dogway
2nd November 2021, 16:34
I'm fine with 8-bit preview but the color values in the status bar show 235 for white instead of 255 (ie. scaled from 16-bit). I mean if AvsPmod knows about frameprops and its values, then it knows about bitdepth and can scale those values according (by bitshift or full stretch) if one wants to show them in 16-bits or another bitdepth, no need for python support. We should also support bitdepth scale in frameprops to round it down so all clip information is within frame properties.
As for BT2020 I don't think there are capable monitors to show its gamut, it's mostly Display-P3 but that is enough for most non pure saturated real surface colors.
gispos
2nd November 2021, 17:28
Then I might have had the wrong impression from this post (https://forum.doom9.org/showthread.php?p=1942719#post1942719)
We've had that topic before.
I'm just not smart enough to implement that.
It is correct that python only returns 8bit from the display, but I am now totally overwhelmed how that would behave with a real 10bit display ... no idea.
However, the values of the pixels can also be calculated, but only for 8 bits.
And now to all the clever minds, below is the code for YUV and RGB calculations for 8bit.
POST me the code for other color depths, I'll be happy to implement that.
https://forum.doom9.org/showthread.php?p=1879721#post1879721
VoodooFX
2nd November 2021, 21:29
I'm writing one function using YPlaneMinMaxDifference() ect... it would help if those runtime functions could be masked.
Dogway
3rd November 2021, 00:30
And now to all the clever minds, below is the code for YUV and RGB calculations for 8bit.
POST me the code for other color depths, I'll be happy to implement that.
I have a 10bit monitor, but I keep all HDR stuff disabled as I see no point for working, unless it's a master monitor. Python has bitshift so as far as you know the clip bitdepth you can do:
32-bit float: 8-bit / 255 (then for UV planes shift to minus -0.5)
This will only show from 0 to 1 though, when 32-bit float in avs+ is capable of -+128.000000 (stored in 16-bit container)
10-16-bit int: Python can do bitshift. n << (bitdepth-8)
10-16-bit int: For full scale you don't have access to that information, unless pinterf says otherwise. But if you know I did it like so in ex_bs().
round(n << (bitdepth-8) + (n << (bitdepth-8)) / 256) (ie. ((16<<8)+(16<<8)/256))
You can also do
round((257/256) * (n << (bitdepth-8) ))
pinterf
3rd November 2021, 07:43
We've had that topic before.
I'm just not smart enough to implement that.
It is correct that python only returns 8bit from the display, but I am now totally overwhelmed how that would behave with a real 10bit display ... no idea.
However, the values of the pixels can also be calculated, but only for 8 bits.
And now to all the clever minds, below is the code for YUV and RGB calculations for 8bit.
POST me the code for other color depths, I'll be happy to implement that.
https://forum.doom9.org/showthread.php?p=1879721#post1879721
I think of something like this, see IsPlanar + Y-only case.
(may not work out-of-box but the idea is there)
def GetPixelYUV(self, x, y):
x = x * self.component_size
if self.IsPlanar:
indexY = x + y * self.pitch
if self.IsY:
if self.component_size == 1: #8 bit
return (self.ptrY[indexY], -1, -1)
elif self.component_size == 2: # up to 16 bits
buffer = [self.ptrY[indexY], self.ptrY[indexY + 1]]
return (int.from_bytes(buffer, byteorder='little'), -1, -1)
else: # 32 bit float
buffer = [self.ptrY[indexY], self.ptrY[indexY + 1], self.ptrY[indexY + 2], self.ptrY[indexY + 3]]
buf = bytearray(buffer)
return (struct.unpack('<f', buf) , -1, -1)
x = x >> self.WidthSubsampling
y = y >> self.HeightSubsampling
indexU = indexV = x + y * self.pitchUV
elif self.IsYUY2:
indexY = (x*2) + y * self.pitch
indexU = 4*(x/2) + 1 + y * self.pitch
indexV = 4*(x/2) + 3 + y * self.pitch
else:
return (-1,-1,-1)
return (self.ptrY[indexY], self.ptrU[indexU], self.ptrV[indexV])
gispos
3rd November 2021, 19:05
I think of something like this, see IsPlanar + Y-only case.
(may not work out-of-box but the idea is there)
def GetPixelYUV(self, x, y):
x = x * self.component_size
if self.IsPlanar:
indexY = x + y * self.pitch
if self.IsY:
if self.component_size == 1: #8 bit
return (self.ptrY[indexY], -1, -1)
elif self.component_size == 2: # up to 16 bits
buffer = [self.ptrY[indexY], self.ptrY[indexY + 1]]
return (int.from_bytes(buffer, byteorder='little'), -1, -1)
else: # 32 bit float
buffer = [self.ptrY[indexY], self.ptrY[indexY + 1], self.ptrY[indexY + 2], self.ptrY[indexY + 3]]
buf = bytearray(buffer)
return (struct.unpack('<f', buf) , -1, -1)
x = x >> self.WidthSubsampling
y = y >> self.HeightSubsampling
indexU = indexV = x + y * self.pitchUV
elif self.IsYUY2:
indexY = (x*2) + y * self.pitch
indexU = 4*(x/2) + 1 + y * self.pitch
indexV = 4*(x/2) + 3 + y * self.pitch
else:
return (-1,-1,-1)
return (self.ptrY[indexY], self.ptrU[indexU], self.ptrV[indexV])
Thank you Ferenc but unfortunately no success.
When looking at the code I thought that it could work with it, especially the non Y section seemed logical to me.
But very often 0,0,0 is returned, or values only within the byte range.
I looked at other relevant parts and didn't notice anything that could change the values to byte.
I had tried RGB before and thought that there shouldn't be any problems with it.
bytes = self.vi.bytes_from_pixels(1) should return the correct size to multiply regardless of the color depth (I thought)
and then just multiply, indexB = (x * bytes) + (self.Height - 1 - y) * self.pitch
Should be the right position for BGR and should return the right value, but unfortunately not either.
pinterf
3rd November 2021, 19:42
Meanwhile, powered up by the 3rd Covid vaccine :)
Avisynth+ 3.7.1 test build 23 (20211103) (https://drive.google.com/uc?export=download&id=1UfjtV3FMqzCjI8s-A864KzWUO_dAdaAR)
Well, this time the source suffered significant changes and additions. Let's hope the best. Anyway, the first Avisynth version which really sets _some_ common frame properties.
And a fix after Dogway's issue, thanks for reporting.
20211103 WIP
------------
- frame propery support: preliminary _Matrix and _ColorRange in various filters
Summary:
_Matrix constants - as seen in propShow() Constants will probably appear for developers in a header file. Not in Avisynth script.
AVS_MATRIX_RGB 0
AVS_MATRIX_BT709 1
AVS_MATRIX_UNSPECIFIED 2
AVS_MATRIX_FCC 4
AVS_MATRIX_BT470_BG 5 (BT601)
AVS_MATRIX_ST170_M 6 (practically same as 5)
AVS_MATRIX_ST240_M 7
AVS_MATRIX_YCGCO 8 (not supported by internal converters)
AVS_MATRIX_BT2020_NCL 9
AVS_MATRIX_BT2020_CL 10 (same as 9)
AVS_MATRIX_CHROMATICITY_DERIVED_NCL 12 (not supported by internal converters)
AVS_MATRIX_CHROMATICITY_DERIVED_CL 13 (not supported by internal converters)
AVS_MATRIX_ICTCP 14 (not supported by internal converters)
_ColorRange constants:
AVS_RANGE_FULL = 0
AVS_RANGE_LIMITED = 1
string "matrix" parameter possible values and their mapping (used in YUV-RGB converters)
"rgb" AVS_MATRIX_RGB
"709" AVS_MATRIX_BT709
"unspec" AVS_MATRIX_UNSPECIFIED
"170m" AVS_MATRIX_ST170_M
"240m" AVS_MATRIX_ST240_M
"470bg" AVS_MATRIX_BT470_BG
"fcc" AVS_MATRIX_FCC
"ycgco" AVS_MATRIX_YCGCO not supported
"2020ncl" AVS_MATRIX_BT2020_NCL
"2020cl" AVS_MATRIX_BT2020_CL same as 2020ncl
"chromacl" AVS_MATRIX_CHROMATICITY_DERIVED_CL not supported
"chromancl" AVS_MATRIX_CHROMATICITY_DERIVED_NCL not supported
"ictcp" AVS_MATRIX_ICTCP not supported
"601" AVS_MATRIX_BT470_BG compatibility alias
"2020" AVS_MATRIX_BT2020_NCL compatibility alias
the above "matrix" parameters can be followed by a "full" or "f" and "limited" or "l" or "auto" marker after a ":"
e.g. "709:f" means the same as the old "PC.709"
When there is no limited-ness marker, or is set to "auto" then value of _ColorRange frame property is used
old-style "matrix" parameters are kept, their name indicate the full/limited
For memo and the similar new string
"rec601" same as "170m:l"
"rec709" "709:l"
"pc.601" and "pc601" "170m:f"
"pc.709" and "pc709" "709:f"
"average" - kept for compatibility, really it has no standard _Matrix equivalent
"rec2020" "2020cl:l"
"pc.2020" and "pc2020" "2020cl:f"
- RGB<->YUV (YUY2) conversions: frame property support _Matrix and _ColorRange
Unlike smart external plugins, in Avisynth there is a single "matrix" parameter,
since the function names explicitely tell whether we are converting from RGB or to RGB.
New: additional "matrix" parameter values: see table above.
With a new syntax "170m", "240m", "fcc" are newly available matrixes.
New-style matrix name can be:
matrix name
or
matrix name : full_or_limited_marker
"auto" can appear on before and after the ":" character, e.g. "auto:full" will take matrix from frame property or default
When converting to RGB the _Matrix parameter is set to 0 ("rgb")
- ConvertBits: frame property support: _ColorRange
When parameter "fulls" is not specified, whether the source clip is full or limited is decided on _ColorRange frame property.
When no property available, then RGB clips are treated as fulls=true, while YUV are fulls=false.
If not specified, "fulld" parameter will inherit the value of the established fulls
- ColorBars: frame property support: writes _Matrix and _ColorRange.
RGB: _ColorRange = 1 ("limited") - ColorBars is using studio RGB values
_Matrix = 0 ("rgb")
- ColorBarsHD: frame property support:
_ColorRange = 1 ("limited"), _Matrix = 1 ("709")
- BlankClip: frame property support:
RGB: _ColorRange = 0 ("full"), _Matrix = 1 ("709")
YUV: _ColorRange = 1 ("limited"), _Matrix = 6 ("170m")
- Fix: Planar RGB 32 bit -> YUV matrix="PC.709"/"PC.601"/"PC.2020" resulted in greyscale image
FranceBB
3rd November 2021, 20:26
Awesome!
Well done, Ferenc! :D
https://c.tenor.com/ZWopsXeO7tQAAAAd/clapping-applause.gif
I look forward to test those, especially 'cause this makes the burden of setting frame properties less big for the user.
A very nice step in the right direction, bring it on! :D
gispos
3rd November 2021, 22:07
I have a 10bit monitor, but I keep all HDR stuff disabled as I see no point for working, unless it's a master monitor. Python has bitshift so as far as you know the clip bitdepth you can do:
32-bit float: 8-bit / 255 (then for UV planes shift to minus -0.5)
This will only show from 0 to 1 though, when 32-bit float in avs+ is capable of -+128.000000 (stored in 16-bit container)
10-16-bit int: Python can do bitshift. n << (bitdepth-8)
10-16-bit int: For full scale you don't have access to that information, unless pinterf says otherwise. But if you know I did it like so in ex_bs().
round(n << (bitdepth-8) + (n << (bitdepth-8)) / 256) (ie. ((16<<8)+(16<<8)/256))
You can also do
round((257/256) * (n << (bitdepth-8) ))
Hello Dogway, take a look at this and tell me if this can be so right
From left to right and top to bottom the first two lines (13 color fields)
ColorBarsHD(width=1280, height=720, pixel_type="YV24")
ConvertBits(bits=16, truerange=true, fulls=true, fulld=true)
*rgb=(26728,26471,26728) *yuv=(26925,32842,32862)
*rgb=(49601,49087,49601) *yuv=(46444,32917,32957)
*rgb=(49601,49087,257) *yuv=(41608,11255,36460)
*rgb=(257,49087,49344) *yuv=(33737,40107,11313)
*rgb=(257,49087,0) *yuv=(28901,18445,14816)
*rgb=(49601,0,49858) *yuv=(21729,47314,51002)
*rgb=(49601,0,514) *yuv=(16893,25652,54506)
*rgb=(257,0,49601) *yuv=(9022,54504,29359)
*rgb=(26728,26471,26728) *yuv=(26925,32842,32862)
*rgb=(0,65535,65535) *yuv=(43548,42467,3998)
*rgb=(27242,10794,257) *yuv=(16562,25707,40736)
*rgb=(49601,49087,49601) *yuv=(46444,32917,32957)
*rgb=(514,0,65535) *yuv=(10650,61461,28340)
ColorBarsHD(width=1280, height=720, pixel_type="YV24")
ConvertBits(bits=16, truerange=false, fulls=false, fulld=false)
*rgb=(26214,26214,26214) *yuv=(26613,32768,32768)
*rgb=(49087,49087,49087) *yuv=(46261,32768,32768)
*rgb=(49087,49087,0) *yuv=(41451,11218,36253)
*rgb=(0,49087,48830) *yuv=(33621,39920,11237)
*rgb=(0,49087,0) *yuv=(28835,18483,14703)
*rgb=(49087,0,49344) *yuv=(21547,47165,50813)
*rgb=(49087,0,257) *yuv=(16736,25615,54298)
*rgb=(0,0,49087) *yuv=(8906,54317,29282)
*rgb=(26214,26214,26214) *yuv=(26613,32768,32768)
*rgb=(0,65278,65535) *yuv=(43418,42541,4092)
*rgb=(26728,10794,0) *yuv=(16405,25671,40529)
*rgb=(49087,49087,49087) *yuv=(46261,32768,32768)
*rgb=(257,0,65535) *yuv=(10584,61499,28227)
Or this one (without averaging)
ColorBarsHD(width=1280, height=720, pixel_type="YV24")
ConvertBits(bits=16, truerange=false, fulls=false, fulld=false)
*rgb=(26112,26112,26112) *yuv=(26526,32768,32768)
*rgb=(48896,48896,48896) *yuv=(46097,32768,32768)
*rgb=(48896,48896,0) *yuv=(41305,11302,36239)
*rgb=(0,48896,48640) *yuv=(33506,39892,11320)
*rgb=(0,48896,0) *yuv=(28739,18539,14774)
*rgb=(48896,0,49152) *yuv=(21479,47109,50743)
*rgb=(48896,0,256) *yuv=(16687,25643,54215)
*rgb=(0,0,48896) *yuv=(8887,54233,29296)
*rgb=(26112,26112,26112) *yuv=(26526,32768,32768)
*rgb=(0,65024,65280) *yuv=(43265,42503,4204)
*rgb=(26624,10752,0) *yuv=(16357,25698,40499)
*rgb=(48896,48896,48896) *yuv=(46097,32768,32768)
*rgb=(256,0,65280) *yuv=(10559,61388,28245)
johnmeyer
4th November 2021, 02:35
I am unable to get AVISynth+ to open anything under Windows 7 64-bit SP1.
I downloaded and installed "AviSynthPlus_3.7.0_20210111_vcredist.exe" using the defaults, and running as Administroator. I then tried to open video frameserved from Vegas using this one-line script:
AVISource("C:\Users\User\Documents\fs.avi")
AVISynth throws the error "couldn't locate a decompressor"
I then tried:DirectShowSource("C:\Users\User\Documents\fs.avi")but that gave me all sorts of errors, including "could not open as video or audio," and "Pins cannot connect due to not supporting the same transport." AVISource still throws the same error.
I tried opening a dozen other video files, rather than the framerserver signpost. I uninstalled and re-installed. I spent over an hour searching both this forum and the Internet at large.
I did note that the installation installed TWO Microsoft Visual C++, redistributables, one for the 32-bit and one for the 64-bit.
I did try to install just the 64-bit, but the installation did not complete because it did not ask me to re-boot.
Sadly, this means I won't be able to work on the road the next five days.
Any suggestions, I'd sure appreciate it.
edit: I uninstalled everything and then installed just the 64-bit version. Using DirectShow I get an error message "cannot load a 32-bit DLL in 64-bit AVISynth ... AGC.DLL"
kedautinh12
4th November 2021, 03:23
Try L-SMASH source, can open .avi file
https://github.com/HomeOfAviSynthPlusEvolution/L-SMASH-Works/releases
johnmeyer
4th November 2021, 03:39
Try L-SMASH source, can open .avi file
https://github.com/HomeOfAviSynthPlusEvolution/L-SMASH-Works/releasesThanks for that. I've downloaded it, but I found out the problem: 64-bit AVISynth+ just doesn't work on my system. I removed everything, and installed only the 32-bit AVISynth+. It didn't work quite right until I also used the 32-bit version of VirtualDub.
So, as long as I stay with everything at 32-bit, everything works just like it has on my other computers. Since I could care less about 64-bit, I'll just proceed with what I have working now.
FranceBB
4th November 2021, 07:44
Even if you're not on XP, what about the XP build for x64? We don't know why it didn't run on your system, but the XP build uses v141_xp so it should be more compatible.
pinterf
4th November 2021, 08:02
Decompressor and avi opening problems swow that Avisynth works but a specific codec which knows your avi internal format is missing.
My test versions are still good for xp I think.
Install 3.7.0 then overwrite the files with the unzipped ones.
32 bit dll among the 64 bit ones is definitely user error, move that file away from your plugin folder. 64 bit Avisynth (or anything) is not able to consume 32 bit dlls.
Reel.Deel
4th November 2021, 08:32
@johnmeyer
I think you may be doing some things wrong. I have 64-bit AviSynth+ installed on my Windows 7 PC and also on a 11 year old MacBook Pro running Windows 7 and both work flawlessly. And if I'm not mistaken there are some users using 64-bit AVS+ even on Windows XP.
With that being said, based on the information you provided it seems you are trying to use some 32-bit plugins on a 64-bit environment. HDRAGC is one of the few plugins that is still used that's only in 32-bit because it's closed source. It will only work with 32-bit AVS+ and a 32-bit host. You can also use MP_Pipeline (http://avisynth.nl/index.php/MP_Pipeline) to load a 32-bit plugin in a 64-bit environment.
Some suggestions:
Install the AIO Repack for latest Microsoft Visual C++ Redistributable Runtimes (https://github.com/abbodi1406/vcredist/releases)
Install VirtualDub2 (https://sourceforge.net/projects/vdfiltermod/) - it includes both 32/64-bit versions. Not sure if you have this already or not, I did not see you mention it.
Start with a clean AviSynth+ install and only install plugins that you know are 64-bit into the appropriate install locations. An almost complete list of 64-bit plugins can be found here: http://avisynth.nl/index.php/Category:Plugins_x64 - (only shows 200 per page so you have to click next to view all)
Dogway
4th November 2021, 08:57
I get invalid arguments with the next call, still on test22:
a=last
b=propClearAll()
scriptclip(b, function [a,b] () {
propcopy(b,a,"_Matrix")
} )
"Invalid arguments to function 'propcopy'"
Maybe I missed something, sometimes it works for me others doesn't. 'a' has the attribute, also tested with custom properties.
@gispos: That's a totally different topic. I don't know why you use truerange=false, that will assume 16-bit regardless of int bitdepth. Also converting from RGB to YUV is not simple if we start to take into account range, bitdepth scale, etc. With the latest changes it's even more complicated since 'fulld' is broken. I'm about to upload a bunch of updates so maybe tomorrow I can have a deeper look.
pinterf
4th November 2021, 09:52
I get invalid arguments with the next call, still on test22:
a=last
b=propClearAll()
scriptclip(b, function [a,b] () {
propcopy(b,a,"_Matrix")
} )
"Invalid arguments to function 'propcopy'"
Maybe I missed something, sometimes it works for me others doesn't. 'a' has the attribute, also tested with custom properties.
@gispos: That's a totally different topic. I don't know why you use truerange=false, that will assume 16-bit regardless of int bitdepth. Also converting from RGB to YUV is not simple if we start to take into account range, bitdepth scale, etc. With the latest changes it's even more complicated since 'fulld' is broken. I'm about to upload a bunch of updates so maybe tomorrow I can have a deeper look.
There is no selective property copy.
You can copy (clone) all, or merge them.
pinterf
4th November 2021, 10:07
Thank you Ferenc but unfortunately no success.
When looking at the code I thought that it could work with it, especially the non Y section seemed logical to me.
But very often 0,0,0 is returned, or values only within the byte range.
I looked at other relevant parts and didn't notice anything that could change the values to byte.
Probably you made it right, seeing your last results.
Anyway, I refreshed my memories about AvsPMod development, reinstalled everything, so here is my working version. (I see the project is still on 2.7, Microsoft has silently removed their VcPython27 compiler, you can find only on some peoples' github repo.)
The code was try-except-pass guarded so it hid all internal errors e.g. using things which 2.7 did not know about.
import struct
def GetPixelYUV(self, x, y):
if self.bits_per_component > 8:
if self.bits_per_component == 32:
x = x * 4 # 32 bit float
else:
x = x * 2 # 10-16 bits
# if a resize filter used in the preview filter. CRASH if not check here
if self.DisplayWidth != self.Width or self.DisplayHeight != self.Height:
return (-1,-1,-1)
if self.IsPlanar:
indexY = x + y * self.pitch
if self.IsY8:
return (self.ptrY[indexY], -1, -1)
x = x >> self.WidthSubsampling
y = y >> self.HeightSubsampling
indexU = indexV = x + y * self.pitchUV
elif self.IsYUY2:
indexY = (x*2) + y * self.pitch
indexU = 4*(x/2) + 1 + y * self.pitch
indexV = 4*(x/2) + 3 + y * self.pitch
else:
return (-1,-1,-1)
if self.bits_per_component == 8:
return (self.ptrY[indexY], self.ptrU[indexU], self.ptrV[indexV])
if self.bits_per_component <= 16:
# struct.unpack needs import struct, and returns a single element tuple
# =H: unsigned short (2 bytes), native byte order
bufferY = [self.ptrY[indexY], self.ptrY[indexY + 1]]
valY = struct.unpack('=H', bytearray(bufferY))[0]
bufferU = [self.ptrU[indexU], self.ptrU[indexU + 1]]
valU = struct.unpack('=H', bytearray(bufferU))[0]
bufferV = [self.ptrV[indexV], self.ptrV[indexV + 1]]
valV = struct.unpack('=H', bytearray(bufferV))[0]
return (valY, valU, valV)
#float # =f: float (4 bytes), native byte order
bufferY = [self.ptrY[indexY], self.ptrY[indexY + 1], self.ptrY[indexY + 2], self.ptrY[indexY + 3]]
valY = struct.unpack('=f', bytearray(bufferY))[0]
bufferU = [self.ptrU[indexU], self.ptrU[indexU + 1], self.ptrU[indexU + 2], self.ptrU[indexU + 3]]
valU = struct.unpack('=f', bytearray(bufferU))[0]
bufferV = [self.ptrV[indexV], self.ptrV[indexV + 1], self.ptrV[indexV + 2], self.ptrV[indexV + 3]]
valV = struct.unpack('=f', bytearray(bufferV))[0]
return (valY, valU, valV)
And the calling/test part in avsp.py
avsYUV = script.AVI.GetPixelYUV(x, y)
if avsYUV != (-1,-1,-1):
Y,U,V = avsYUV
cY = ''
if script.AVI.bits_per_component == 8:
hexcolor = '$%02x%02x%02x' % (Y,U,V)
elif script.AVI.bits_per_component <= 16:
hexcolor = '$%04x,%04x,%04x' % (Y,U,V) # comma separated is more visible
else: # 32 bit
hexcolor = '%.5f,%.5f,%.5f' % (Y,U,V) # no reason for 32 bit float in hex
pinterf
4th November 2021, 10:19
@gispos: That's a totally different topic. I don't know why you use truerange=false, that will assume 16-bit regardless of int bitdepth. Also converting from RGB to YUV is not simple if we start to take into account range, bitdepth scale, etc. With the latest changes it's even more complicated since 'fulld' is broken. I'm about to upload a bunch of updates so maybe tomorrow I can have a deeper look.
Yes, please stop using truerange, I didn't even know what is still there (there was a huge ConvertBits refactor in the source last week) and someone is still using it. Probably it was a workaround in the very early HBD era, when some filters stored 10 bit data in a stacked-16-bit container and someone asked me to solve the problem (?) I was about to remove it, but at least I'm gonna give error when it is used other than the default value.
Q2:
How is 'fulld' broken?
Q3: Are you implementing another conversion engine besides z_convertformat, fmtconv?
DTL
4th November 2021, 10:55
" _ColorRange constants:"
The most strange why only color range. It typically data range including luma too and the luma errors may be most visible. Expected _Range or _DataRange.
Also at time of addition different metadata (moving pictures object properties) it is also good to add spectrum properties:
(for each plane separately or for luma and chroma separately in YUV, equal for planes of RGB formats) -
1. spectrum shape - rectangular (unconditioned), anti-gibbs conditioned.
2. target (preffered) scaling domain - linear, transfer-function converted.
3. type of chroma anti-gibbs filter for final conversion to 4:4:4 - (1,2,3,...).
For each property additional state 'undefined' if no information available.
pinterf
4th November 2021, 11:11
What is strange? This is only the beginning.
There are 'standardized' properties and values which are used since years in VapourSynth, zimg and lately in many Avisynth plugins.
I'm not gonna introduce or in-house-standardize brand new features or properties, I'm just trying to catch the train and would like to implement what exists presently before the end of this year.
Keeping conventions helps developers and plugin porting between vs and avs as well.
If there is no constant, then the "no information available" means that the given property does not exist.
Dogway
4th November 2021, 12:24
Q2:
How is 'fulld' broken?
Now I got your attention : P 'fulld' requires same value than 'fulls' so for example can't convert from 14-bit bitshift scale to 16-bit full scale. fmtc_bitdepth() allows different values, albeit linked to the color range (which I don't see the relation with, but don't want another argument).
Q3: Are you implementing another conversion engine besides z_convertformat, fmtconv?
I started TransformsPack (https://github.com/Dogway/Avisynth-Scripts/blob/master/TransformsPack.v1.0.RC22.avsi)(big update coming tomorrow) in May before ExTools, color is my area of interest but didn't like the current solutions for avisynth; terms, limitations, accesibility... It's also an expansion of my old LinearResize() so I integrated more resizers, scaling in different "spaces" like gamma, log or sigmoid, added different color models (reversible YUV, reversible YCoCg, OPP, YcCbcCrc, IPT, OkLab, HSV, Lab, Luv, Duv, etc) and plan to add a preset system, full ACES model (including the RRT) and gamut compression. Later (2.0 onwards) for HDR color models and transfer functions if I didn't lose my head already. I would like to see avisynth back being competent in a production environment. Watched a lecture a few months ago of Netflix' encoder David Ronca talking about how he used avisynth in the company's early days, things like that.
DTL
4th November 2021, 12:46
Standard naming in ITU-R BT.2100 table 9: https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.2100-2-201807-I!!PDF-E.pdf
Table 9 describes two different signal representations, “narrow” and “full”. The narrow range representation is in widespread use and is considered the default. (page 9)
Table 9:
Parameters: Quantization of R', G', B', Y', I (resulting values that exceed the video data range should be clipped to the video data range) - Narrow range , Full range .
Quantization of C'B, C'R, CT, CP (resulting values that exceed the video data range should be clipped to the video data range) - Narrow range , Full range .
So 'ITU-R standard' naming of essence is 'video data range' and its values 'narrow' and 'full'.
The word 'color' may cause error thinking it is only for colour data like C'B, C'R, CT, CP and for luma data separate property required.
It looks other programs like fmtc try to solve the issue using 'not-full' value. Do not call it 'limited' or 'narrow'. Just 'full' or 'not-full'.
In the 'broadcasting world' there was no need to name this essence before BT.2100 introducing 'full' for DolbyVision PQ. All 'pro broadcast' range was 'narrow' only.
vBulletin® v3.8.11, Copyright ©2000-2026, vBulletin Solutions Inc.