Log in

View Full Version : ConvertBackToYUY2() only works after ConvertToRGB()?


Aktan
15th January 2010, 01:34
I have a capture in RGB of game footage. My final output would to H.264 so the colorspace would change to YV12(). Since I don't want to lose the color information, I did a PointResize(last.width*2,last.height*2) on the source. I read from the Sampling (http://avisynth.org/mediawiki/Sampling) page of AviSynth that in order to avoid interpolating the chroma, I would need to use ConvertBackToYUY2(). I tried using it and after some testing, I found out that it does exactly the same as ConvertToYUY2()! Here is the two scripts I compared:

#RGB Clip
AVISource("test.avi")
PointResize(last.width*2,last.height*2)
ConvertBackToYUY2()

#RGB Clip
AVISource("test.avi")
PointResize(last.width*2,last.height*2)
ConvertToYUY2()

Now if I add the following two lines, ConvertBackToYUY2() seems to work:

ConvertToRGB()
ConvertBackToYUY2()

Here are the two scripts I compared:

#RGB Clip
AVISource("test.avi")
PointResize(last.width*2,last.height*2)
ConvertBackToYUY2()
ConvertToRGB()
ConvertBackToYUY2()

#RGB Clip
AVISource("test.avi")
PointResize(last.width*2,last.height*2)
ConvertToYUY2()
ConvertToRGB()
ConvertToYUY2()

It seems to me ConvertBackToYUY2() only works after ConvertToRGB(). Is this right? If this is true, is there any way I can convert to YUY2 without interpolating the chroma?

Blue_MiSfit
15th January 2010, 04:00
Why are you so worried about this?

You'll have to be in YV12 eventually, which means losing tons of chroma resolution.

Who cares though?

I'm not sure its possible to do what you want to do without interpolating any data.

~MiSfit

`Orum
15th January 2010, 04:44
I second Blue_MiSfit's comments. I don't know of a H.264 encoder that supports 4:4:4 (thought there are probably some, x264 doesn't). So just deal with the color loss or use a different codec...or wait til x264 gets 4:4:4 support (or write the patch yourself!).

This is a known annoyance in video that has high detail chroma planes, like video game captures.

Wilbert
15th January 2010, 12:27
AVISource("test.avi")
Info()

What colorspace does it state?

Aktan
16th January 2010, 17:15
Why are you so worried about this?

You'll have to be in YV12 eventually, which means losing tons of chroma resolution.

Who cares though?

I'm not sure its possible to do what you want to do without interpolating any data.

~MiSfit

The colorloss won't be there if I resize it to 4x the original resolution. This means if no interpolating was done, there would be no colorloss at all since each pixel would cover 4 pixels now.

Aktan
16th January 2010, 17:19
what colorspace does it state?

rgb32

Keiyakusha
17th January 2010, 21:43
If your source is RGB and target is YV12 you don't need ConvertBackToYUY2()
AFAIK ConvertBackToYUY2() used only if you source was YUY2 to begin with, then you converted it to something inside the script and as output you need also YUY2

Aktan
17th January 2010, 22:25
If your source is RGB and target is YV12 you don't need ConvertBackToYUY2()
AFAIK ConvertBackToYUY2() used only if you source was YUY2 to begin with, then you converted it to something inside the script and as output you need also YUY2

I use ConvertBackToYUY2() in order to avoid the interpolating of the chroma, as said in the first post. Looking at this URL: http://avisynth.org/mediawiki/Sampling will explain what I mean.

Keiyakusha
17th January 2010, 22:33
will explain what I mean.

Actually its not. Could you quote exact statement that shows how it helps in your case?
This function mentioned once under "RGB -> YUY2 conversion" This is not your case. And it doesn't helps to avoid interpolating, in makes it less noticeable.

use ConvertBackToYUY2() to convert back to YUY2, when you applied a YUY2->RGB conversion prior to that in your script. This will reduce color-blurring, but there are still some precision lost


YUY2 is NOT the same as YV12

Such construction:
ConvertBackToYUY2()
ConvertToRGB()
ConvertBackToYUY2()
Only makes loss of quality and the result will be converted internally in x264 if you feed this to it.

Aktan
18th January 2010, 03:50
here is all quoted from the same page:

"The other mode ConvertBackToYUY2 uses chroma from the left pixel, thus "

frame line
Y1C1 Y2 Y3C3 Y4 line 1
Y1C1 Y2 Y3C3 Y4 line 2
Y1C1 Y2 Y3C3 Y4 line 3
Y1C1 Y2 Y3C3 Y4 line 4



YUY2 -> YV12 progressive conversion :

frame lines weights
Y_Y_Y_Y line 1
C___C__ chroma of YUY2_lines (0.5)*1 + (0.5)*2
Y_Y_Y_Y line 2
Y_Y_Y_Y line 3
C___C__ chroma of YUY2_lines (0.5)*3 + (0.5)*4
Y_Y_Y_Y line 4

Thus if 1 pixel becomes 4 pixels, this is how it will look if using first ConvertBackToYUY2() then ConvertToYV12():

frame lines
Y1_Y1_Y2_Y2 line 1
C1___C2__
Y1_Y1_Y2_Y2 line 2
Y1_Y1_Y2_Y2 line 3
C1___C2__
Y1_Y1_Y2_Y2 line 4

Note: Formatting is terrible=/

Aktan
18th January 2010, 03:58
Here, I'll trying to explain from start.

4 pixels:

Y1C1 Y2C2
Y3C3 Y4C4

PointResize(last.width*2,last.height*2):

Y1C1Y1C1 Y2C2Y2C2
Y1C1Y1C1 Y2C2Y2C2
Y3C3Y3C3 Y4C4Y4C4
Y3C3Y3C3 Y4C4Y4C4

ConvertBackToYUY2() (at least if it worked):

Y1C1Y1 Y2C2Y2
Y1C1Y1 Y2C2Y2
Y3C3Y3 Y4C4Y4
Y3C3Y3 Y4C4Y4

ConvertToYV12():

Y1Y1 Y2Y2
C1 C2
Y1Y1 Y2Y2
Y3Y3 Y4Y4
C3 C4
Y3Y3 Y4Y4

As you can see, there is no color loss per pixel anymore.

IanB
18th January 2010, 06:47
ConvertBackToYUY2() is only for RGB to YUY2 conversions!

Anything else and you will get this error message "ConvertBackToYUY2: Use ConvertToYUY2 to convert non-RGB material to YUY2.".

It uses sampling of the left RGB pixel only to generate the chroma UV values and the left-hand Y value. The right RGB pixel is only used to calculate the right-hand Y value and has no influence on the resulting chroma values, i.e. the chroma is point resampled.


ConvertToYUY2() for RGB to YUY2 conversions uses the pure average of the left and right RGB pixels to generate the chroma UV values. This is technically wrong and results in a 0.5 pixel shift right of the chroma. This is original BenRG code and was used for performance reasons circa Pentium-MMX 166Mhz.


Conversions between YUY2 and YV12 for progressive are correct. There is a 50% additional loss in vertical chroma resolution going to YV12, both YV12 and YUY2 already have 50% horizontal chroma resolution implicit in the formats.


So yes pointresizing the RGB image by 2 first can maintain the original chroma resolution, but at some point before committing to H264 you will have to subsample the chroma as YV12.


Hint: Currently RGB to YV12 conversions are all via YUY2, so a performance gain can be obtained by deferring the vertical times 2 until the YUY2 to YV12 conversion, i.e.# RGB Source
PointResize(Width()*2, Height())
ConvertBackToYUY2() # Left and Right pixels are the same, so use Left only.
PointResize(Width(), Height()*2)
ConvertToYV12()
...

Note: from 2.6 there is YV24 format than offers full chroma resolution.

juGGaKNot
18th January 2010, 10:50
So pointresize by 2 to yuy2 will keep the full chroma and ConvertToYV12() from yuy2 will reduce it back to 50% ?

Same result if you just use ConvertToYV12() but faster ?

Avisynth 2.6 has ConvertToYV24() but x264 does not support it yet.

Right ?

IanB
18th January 2010, 11:03
I am not really sure why you think 2:1 subsampling the chroma is such a bad thing, all the popular domestic media formats do it. The ocular input for species Homo Sapien is far more restricted than 2:1 chroma subsampling. If you have an industrial application then perhaps you should be leaving the data in RGB format.

Aktan
18th January 2010, 12:52
ConvertBackToYUY2() is only for RGB to YUY2 conversions!

Anything else and you will get this error message "ConvertBackToYUY2: Use ConvertToYUY2 to convert non-RGB material to YUY2.".

It uses sampling of the left RGB pixel only to generate the chroma UV values and the left-hand Y value. The right RGB pixel is only used to calculate the right-hand Y value and has no influence on the resulting chroma values, i.e. the chroma is point resampled.


ConvertToYUY2() for RGB to YUY2 conversions uses the pure average of the left and right RGB pixels to generate the chroma UV values. This is technically wrong and results in a 0.5 pixel shift right of the chroma. This is original BenRG code and was used for performance reasons circa Pentium-MMX 166Mhz.


That's the thing, my source is RGB32 and it seems
ConvertBackToYUY2() still causes a 0.5 pixel shift, i.e. it looks exactly the same as ConvertToYUY2()!

I know there is interpolating when converting back to RGB32 for display, so maybe that's the shift I'm seeing, but I was expecting to see a difference between ConvertBackToYUY2() and ConvertToYUY2(). When I checked, there was no difference. The only time I saw a difference was when I went from RGB -> YUY2 -> RGB -> YUY2. Then I noticed that ConvertBackToYUY2() seem to keep more color.

This is why I'm wondering if ConvertToRGB() sets some flag that ConvertBackToYUY2() checks before doing the sampling via just taking the left pixel chroma. Something like:

if (flag) {
convert with taking left pixel chroma
}
else {
call ConvertToYUY2()
}

I guess I should mention I am using version 2.58 of AviSynth.

Hint: Currently RGB to YV12 conversions are all via YUY2, so a performance gain can be obtained by deferring the vertical times 2 until the YUY2 to YV12 conversion, i.e.

Thanks for the tip! It makes sense why that would be faster :)

2Bdecided
18th January 2010, 13:07
I am not really sure why you think 2:1 subsampling the chroma is such a bad thing, all the popular domestic media formats do it. The ocular input for species Homo Sapien is far more restricted than 2:1 chroma subsampling.If you think that taking RGB PC screen captures, and converting them to YV12, doesn't cause visible degradation because "ocular input for species Homo Sapien is far more restricted than 2:1 chroma subsampling", then can I respectfully suggest you go and look at the result - because to my eyes the degradation is clearly visible, and last time I checked I was "species Homo Sapien"! ;)

Aktan - as you've found at one stage, whether the output looks like you expect depend on the output decoding / chroma upconversion.

Can a point resize to 4x resolution, convert to yv12, and then point resize down to "only" 2x resolution get what you want? Or does point resize happen to grab the interpolated chroma pixels by default?

Cheers,
David.

Gavino
18th January 2010, 13:38
That's the thing, my source is RGB32 and it seems ConvertBackToYUY2() still causes a 0.5 pixel shift, i.e. it looks exactly the same as ConvertToYUY2()!
After a PointResize(width*2, height*2), ConvertBackToYUY2 will have the same result as ConvertToYUY2, since the two pixels in each relevant pair will be equal - hence taking the left pixel is the same as the average of the two.

Aktan
18th January 2010, 14:31
After a PointResize(width*2, height*2), ConvertBackToYUY2 will have the same result as ConvertToYUY2, since the two pixels in each relevant pair will be equal - hence taking the left pixel is the same as the average of the two.

Hmm, that's an interesting point. If indeed that's how it is done as IanB said, then the http://avisynth.org/mediawiki/Sampling page is wrong. According to that page:

More about RGB -> YUV color conversions can be found here: Color Conversions. Recall the layout of a 4:4:4 encoded image
frame line
Y1C1 Y2C2 Y3C3 Y4C4 line 1
Y1C1 Y2C2 Y3C3 Y4C4 line 2
Y1C1 Y2C2 Y3C3 Y4C4 line 3
Y1C1 Y2C2 Y3C3 Y4C4 line 4

In AviSynth, the default mode is using a 1-2-1 kernel to interpolate chroma, that is

C1x = (C1+C1+C1+C2)/4 (C1 is used three times, since this is the border)
C3x = (C2+C3+C3+C4)/4
C5x = (C4+C5+C5+C6)/4

The 4:2:2 encoded image becomes
frame line
Y1C1x Y2 Y3C3x Y4 line 1
Y1C1x Y2 Y3C3x Y4 line 2
Y1C1x Y2 Y3C3x Y4 line 3
Y1C1x Y2 Y3C3x Y4 line 4

which is not the same as averaging just the left and right pixel.

Maybe I'll just go dig around in the source and pray it isn't in ASM :p

Gavino
18th January 2010, 14:37
See this thread.

Aktan
18th January 2010, 14:39
Can a point resize to 4x resolution, convert to yv12, and then point resize down to "only" 2x resolution get what you want? Or does point resize happen to grab the interpolated chroma pixels by default?


I'm not sure what you mean. Just to clarify, the 4x resolution is 2x width and 2x height. If I were to resize down to 2x, which direction did you mean? I don't get a shift when I point resize to 4x resolution in RGB32. I only get a shift once I convert to YUY2, which is before the convert to YV12.

Aktan
18th January 2010, 14:45
See this thread.

Thanks, that clears things up. I guess that wiki page should really be updated, and maybe I should move to version 2.60 to allow a change in resize core.

Aktan
18th January 2010, 16:05
So I've installed version 2.60 alpha of AviSynth and tried to use the chromaresample parameter. I couldn't figure out what chromaresample options I had as even something like "hfaksjf" worked (probably went to default bicubic). I tried "point" but I don't think it worked. IanB, could you tell me the list of possible resamples?

Aktan
18th January 2010, 17:43
Well I found this in the code:

static ResamplingFunction* getResampler( const char* resampler, IScriptEnvironment* env) {
if (resampler) {
if (!lstrcmpi(resampler, "point"))
return new PointFilter();
else if (!lstrcmpi(resampler, "bilinear"))
return new TriangleFilter();
else if (!lstrcmpi(resampler, "bicubic"))
return new MitchellNetravaliFilter(1./3,1./3); // Parse out optional B= and C= from string
else if (!lstrcmpi(resampler, "lanczos"))
return new LanczosFilter(3); // Parse out optional Taps= from string
else if (!lstrcmpi(resampler, "lanczos4"))
return new LanczosFilter(4);
else if (!lstrcmpi(resampler, "blackman"))
return new BlackmanFilter(4);
else if (!lstrcmpi(resampler, "spline16"))
return new Spline16Filter();
else if (!lstrcmpi(resampler, "spline36"))
return new Spline36Filter();
else if (!lstrcmpi(resampler, "spline64"))
return new Spline64Filter();
else if (!lstrcmpi(resampler, "gauss"))
return new GaussianFilter(30.0); // Parse out optional P= from string
else if (!lstrcmpi(resampler, "sinc"))
return new SincFilter(4); // Parse out optional Taps= from string
else
env->ThrowError("Convert: Unknown chroma resampler, '%s'", resampler);
}
return new MitchellNetravaliFilter(1./3,1./3); // Default colorspace conversion for AviSynth
}


So I guess the compiled version of 2.60 Alpha I have doesn't use or have that yet. Guess I gotta wait since it is alpha after all :)

IanB
18th January 2010, 23:56
Yeah, there are some wrinkles in the new code.

The "chromaresample" option only applies to planar to planar conversions.

There are 2 YUV to RGB paths. One for YUY2, the original code, and a new one for all planar formats via YV24.

The code chooses the fastest path, so for YUY2 to RGB the old direct code is used.

For planar formats, it is first resampled to YV24 then converted to RGB.

Likewise for RGB to YUV, going to YUY2 uses the original code, and it seems YV12 without options also uses the original code.

Probably if options are specified for an original code path then an exception should be thrown. Additionally when options are specified then the new code path should be used (I have made a note of this).

In the mean time you should explicitly force each stage of the format conversions you need. i.e.

YUY2 -> (YV16 ->) YV24 -> RGB
YV12 -> YV24 -> RGB
RGB -> YV24 -> YV12
RGB -> YV24 -> (YV16 ->) YUY2

Note: YV16 and YUY2 represent the same video data, just with different internal memory layouts. YUY2 to any planar format will always go via YV16.

Aktan
19th January 2010, 01:32
Thanks for the info IanB! Will try it out.

Wilbert
19th January 2010, 14:59
See this thread.

Thanks, that clears things up. I guess that wiki page should really be updated, and maybe I should move to version 2.60 to allow a change in resize core.
Oops. I still need to correct this. Thanks for bringing it up again.

Aktan
19th January 2010, 17:44
Oops. I still need to correct this. Thanks for bringing it up again.

No problem :)

IanB: It works! Thanks :)

Gavino
19th January 2010, 18:52
Oops. I still need to correct this. Thanks for bringing it up again.
See also this thread regarding interlaced YV12 to YUY2 conversion.