Welcome to Doom9's Forum, THE in-place to be for everyone interested in DVD conversion. Before you start posting please read the forum rules. By posting to this forum you agree to abide by the rules. |
13th January 2012, 06:18 | #26 | Link | |
VR, 3D & HDR UHD fan
Join Date: Mar 2006
Location: Sofia, Bulgaria
Posts: 53
|
Hello,
I recently found out about this colorspace and the possible compression gains so I decided to give it a try with x264. My source is fullrange RGB. Unfortunately, the resulting file doesn't look exactly right, the black level is off (should be 0/0/0 but it's 0/19/18) and the video is blue-ish. Pure white is OK though (255/255/255). I use the latest MadVR as both decoder and renderer (through MPC-HC), and also tried LAVF+MadVR with the same success. My encoding settings include: Code:
--colormatrix YCgCo --range pc --input-range pc --output-csp i444 I noticed that you said this: Quote:
Is there anything that I can do to correct the situation? Should any special --colorprim and --transfer parameters be set when encoding? Because MadVR says "primaries BT.709 (says bitstream)". Anyway, if I use any other renderer the black is OK (and all the grayscale as a whole), but naturally, the colors are messed up . Your BigBuckBunny samples look OK through MadVR (dec+rend) though... |
|
13th January 2012, 07:00 | #27 | Link | |
VR, 3D & HDR UHD fan
Join Date: Mar 2006
Location: Sofia, Bulgaria
Posts: 53
|
Nope, not exactly sure, just suspecting it does. There's nothing about YCgCo in madVR's changelog, so nothing official. I could only find this statement of the author:
Quote:
The samples I mentioned (probably the ones madshi talks about) look normal, as far as I can tell. Last edited by Zerofool; 13th January 2012 at 07:05. |
|
4th March 2012, 00:17 | #28 | Link |
Registered User
Join Date: Mar 2010
Posts: 98
|
It seems that the problem is somewhere in madVR. I made a few samples and noticed similar problems. But madVR is not open-source so I cannot analyze the problem, madshi has to do that.
To verify that your encoding is correct open the file in avisynth and add the following command (you need the ManualColorMatrix plug-in): Code:
ManualColorMatrix(2, 1.0, -1.0, 1.0, 1.0, 1.0, 0.0, 1.0, -1.0, -1.0, 0.0, -128.0, 256.0) |
11th March 2012, 23:15 | #29 | Link |
Registered User
Join Date: Mar 2010
Posts: 98
|
Madshi has fixed YCgCo matrix in madVR 0.82.5!
Now correctly encoded videos should look perfect. |
12th March 2012, 19:17 | #30 | Link |
Registered User
Join Date: Feb 2012
Posts: 36
|
Hi, XV. I am posting this on behalf of natt, a proficient video encoder from tasvideos.org. He wrote the following in response to your colorspace conversion code.
--- (Note: I'm working off the 2011 h.264 spec) The h.264 spec is very explicit about how RGB->YCgCo should be rounded. Looking over your source code (the C++ version), it doesn't appear to follow those conventions. In particular, rounding should be done towards the nearest integer (not towards zero). As a part of a little educational study, I wrote an RGB->YCgCo converter a while back, and I believe it fully implements the conversion with rounding exactly as the specification requires. (Of course, if there's any disagreement, I'd love to see test vectors). It's in C, and also implements the case of different bitdepths between RGB and YCgCo (which is not needed here) by changing BITDEPTHR and BITDEPTHY. Code:
typedef struct { int y; int cg; // "Cb" int co; // "Cr" } ycc_t; typedef struct { int r; int g; int b; } rgb_t; // R,G,B have bitdepth BITDEPTHR // Y,Cg,Co have bitdepth BITDEPTHY #define BITDEPTHR 8 #define BITDEPTHY 8 #define SRCRNG ((1 << BITDEPTHR) - 1) // rgb values are from [0, SRCRNG] #define SFC (1 << (BITDEPTHY - 1)) // used in some calculations, the "center point" of Cg, Co #define RNG ((1 << BITDEPTHY) - 1) // ycc values are from [0, RNG] void rgb_to_ycgco_int (ycc_t *dst, const rgb_t *src) { // E-19 through E-21 int r = src->r * RNG; int g = src->g * RNG; int b = src->b * RNG; int y = 2 * g + r + b; int cb = 2 * g - r - b; int cr = 2 * r - 2 * b; // round away from 0 y += 2 * SRCRNG; if (cb < 0) cb -= 2 * SRCRNG; else cb += 2 * SRCRNG; if (cr < 0) cr -= 2 * SRCRNG; else cr += 2 * SRCRNG; y /= 4 * SRCRNG; cb /= 4 * SRCRNG; cr /= 4 * SRCRNG; cb += SFC; cr += SFC; // clip if (cb > RNG) cb--; if (cr > RNG) cr--; dst->y = y; dst->cg = cb; dst->co = cr; } |
12th March 2012, 23:15 | #31 | Link |
Registered User
Join Date: Mar 2010
Posts: 98
|
You are right. How rounding is done in C++ version is defined by compiler, which is not good. SSE2 version was wrong (rounding towards zero). Fixing is really simple, I just added 0.5 and then use floor() to ensure itīs rounded towards zero (this is also what H.264 spec says). In SSE2 I just changed cvttps2dq to cvtps2dq.
Could you verify itīs correct? Only using integers for conversion is interesting and is most likely also a lot faster. When I find some time Iīll rewrite my assembly integer-only and see how it compares in speed. Results should be the same. |
15th March 2012, 01:04 | #32 | Link |
Registered User
Join Date: Mar 2010
Posts: 98
|
ConvertToYCgCo v0.4 released
I converted all code to int-only. Output of C and SSE version is bit-identical (as it should be) and should conform to H.264 spec. Using ints instead of float also gives a speed increase (especially for the C version).
I used binary operations instead of arithmetic to increase performance, thatīs the way Iīve done it: Code:
g<<=1; // the same as g*=2; y = g+r+b; cg = g-r-b+512; co = r-b+256; if (y&0x2) { y>>=2; y++; } // same as if(y%4>1) { y/=4; y++; } else y>>=2; if (cg&0x2) { cg>>=2; cg++; if(cg>255) cg--; } else cg>>=2; if (co&0x1) { co>>=1; co++; if(co>255) co--; } else co>>=1; |
19th March 2012, 01:11 | #33 | Link | |
Registered User
Join Date: Mar 2012
Posts: 10
|
Sorry for the slow response time. I had to wait for the board-imposed 5 day timeout, and didn't want to make Lex carry around messages for me.
The idea looks basically right, except for one hitch: the rounding for Cg, Co. The h264 spec says that you're supposed to round before you add 128: Quote:
Round ( (-75) / 2) As in the h264 spec: Round (-37.5) Sign(-37.5)*Floor(Abs(-37.5) + 0.5) (-1)*Floor(38) -38 Truncate and then add 1 because the original was odd: (-75) / 2 + 1 (-37) + 1 -36 |
|
19th March 2012, 20:20 | #34 | Link |
Registered User
Join Date: Mar 2010
Posts: 98
|
Also your example is wrong you are right:
The problem is Iīve not seen the 0.5 problem. My code rounds up, but spec says in this case round away from zero, and that of course makes a difference for negative numbers. For .25 and .75 rounding is correct: Code:
Round((-75)/2) + 128 = Sign(-37.5)*Floor(Abs(-37.5)+0.5) + 128 = (-1)*Floor(38) + 128 = -38 + 128 = 90 (-75 + 256) / 2 = 181/2 = 90 + 1 = 91 => NOT OK Round((-149)/4) + 128 = Sign(-37.25)*Floor(Abs(-37.25)+0.5) + 128 = (-1)*Floor(37.75) + 128 = -37 + 128 = 91 (-149 + 512) / 4 = 363/4 = 90 + 1 = 91 => OK Round((-151)/4) + 128 = Sign(-37.75)*Floor(Abs(-37.75)+0.5) + 128 = (-1)*Floor(38.25) + 128 = -38 + 128 = 90 (-151 + 512) / 4 = 361/4 = 90 + 0 = 90 => OK |
24th March 2012, 15:24 | #35 | Link |
Registered User
Join Date: Dec 2011
Posts: 1,812
|
When you have fixed it, converting RGB to I444 YCgCo should be totally lossless, right?
That would be really very cool, makes RGB redundant. Edit: Is there any way to losslessly convert back to RGB? Last edited by aufkrawall; 24th March 2012 at 20:10. |
25th March 2012, 19:25 | #38 | Link | |||
VR, 3D & HDR UHD fan
Join Date: Mar 2006
Location: Sofia, Bulgaria
Posts: 53
|
Quote:
Unfortunately, I didn't see the expected compression efficiency improvement, only few tens of kilobytes with the little testing I did, but there are possibly cases where the difference will be bigger. Quote:
That's what I wondered and asked Dark Shikari, but received no answer, most likely meaning it won't work, or it's too much trouble to implement: Quote:
Last edited by Zerofool; 25th March 2012 at 19:40. |
|||
25th March 2012, 22:22 | #39 | Link |
Registered User
Join Date: Mar 2012
Posts: 10
|
When you tell x264 "--colormatrix YCgCo", all it does set the VUI flag. It otherwise completely ignores it.
That means that if you send x264 supposed "YUV" data that is in fact YCgCo, it will pass it through unmolested, compress it appropriately, and set the VUI flag for YCgCo. How you do that depends on your workflow. This plugin will allow it with 8 bit, and will work if x264 reads the script directly or you use something like avs2pipemod. For 10 bit, I don't personally know much about how high bitdepth inside avisynth works. What I did for a few test clips is have my script output the original BGR, and then use a simple command line application of my own creation to do BGR 8 8 8->YCgCo 10 10 10. Seemed to work fine (but was affected by the madvr "teal bug" at the time). |
26th March 2012, 02:33 | #40 | Link | ||
Registered User
Join Date: Dec 2011
Posts: 1,812
|
Quote:
Quote:
When I tell Avisynth or x264 to simply convert to RGB, the result is a mess of colors. Edit: The plug in would need to convert back to RGB, I suppose. Last edited by aufkrawall; 27th March 2012 at 18:34. |
||
Thread Tools | Search this Thread |
Display Modes | |
|
|