scmccarthy
12th November 2002, 12:06
Q: How can you convert to YUY2 from YV12 without chroma interpolation?
A: By resizing the luma.
If x is luma and o is chroma, YV12 is like:
xxxxx
o o o
xxxxx
xxxxx
o o o
xxxxx
xxxxx etc.
So I wrote a filter that uses a (1/2,1/2) kernal to average the lines of luma above and below each chroma sample like this:
const int row_size = src->GetRowSize(PLANAR_U);
const int height = src->GetHeight(PLANAR_U);
for (int y = 0; y < height; y++) {
for (int x = 0; x < row_size; x++) {
yuv2p[x*4 + 0] = (srcpY[x*2] + srcpY[x*2+src_pitchY])>>1;
yuv2p[x*4 + 1] = srcpU[x];
yuv2p[x*4 + 2] = (srcpY[x*2+1] + srcpY[x*2+1+src_pitchY])>>1;
yuv2p[x*4 + 3] = srcpV[x];
}
srcpY += src_pitchY*2;
srcpU += src_pitchUV;
srcpV += src_pitchUV;
yuv2p += dst_pitch;
}
return dst;
This is the first filter I ever wrote. I think it might be useful as an example code since it is almost as simple as Invert with one important exception. It taught me what to put in the brackets after the GenericVideoFilter function:
ConvertYV12ToYUY2VRBy2(PClip _child) : GenericVideoFilter(_child) {
vi.height >>= 1;
vi.pixel_type = VideoInfo::CS_YUY2;
child->SetCacheHints(CACHE_NOTHING,0);
}
So if anyone is wondering, this is how you output a different size and pixel type than what you read as input. I had a lot of trouble finding this and even mentioned my trouble in another thread. I read the ConvertToYV12() function in the sources, but overlooked where the pixel type was being changed, since it is not near the main loop. Thanks ShOdan for not interpolating yet, it was much easier to follow that way. Hopefully, now people will always have the choice whether to interpolate or halve the frame.
The idea behind the filter is to see if the colors look better or sharper if I convert without interpolation, but with the chroma perfectly cited on the luma. Also I figured this could be used instead of VerticalReduceBy2(). It is very fast (for a filter that does not use mmx) and looks very good. This actually represents an idea I have that color space conversions and resizing can be optimized if done together. It might minimize the degradation due either to the conversion of resizing. I also noticed that there are many flavors of RGB:
RGB709, RGB601, RGB240M, RGBEDU, RGB255 for blackcode 0 on computers, and RGB219. Now I am on the quest for the perfect matrix to preserve gamma and color fidelity. The answer being that there is no perfect version because the absolute best is probubly different for interlaced, framebased, PAL, of NTSC sources. So my answer will be to try a couple and see.
I hope you like it.
Oh, and here's the attachment:
A: By resizing the luma.
If x is luma and o is chroma, YV12 is like:
xxxxx
o o o
xxxxx
xxxxx
o o o
xxxxx
xxxxx etc.
So I wrote a filter that uses a (1/2,1/2) kernal to average the lines of luma above and below each chroma sample like this:
const int row_size = src->GetRowSize(PLANAR_U);
const int height = src->GetHeight(PLANAR_U);
for (int y = 0; y < height; y++) {
for (int x = 0; x < row_size; x++) {
yuv2p[x*4 + 0] = (srcpY[x*2] + srcpY[x*2+src_pitchY])>>1;
yuv2p[x*4 + 1] = srcpU[x];
yuv2p[x*4 + 2] = (srcpY[x*2+1] + srcpY[x*2+1+src_pitchY])>>1;
yuv2p[x*4 + 3] = srcpV[x];
}
srcpY += src_pitchY*2;
srcpU += src_pitchUV;
srcpV += src_pitchUV;
yuv2p += dst_pitch;
}
return dst;
This is the first filter I ever wrote. I think it might be useful as an example code since it is almost as simple as Invert with one important exception. It taught me what to put in the brackets after the GenericVideoFilter function:
ConvertYV12ToYUY2VRBy2(PClip _child) : GenericVideoFilter(_child) {
vi.height >>= 1;
vi.pixel_type = VideoInfo::CS_YUY2;
child->SetCacheHints(CACHE_NOTHING,0);
}
So if anyone is wondering, this is how you output a different size and pixel type than what you read as input. I had a lot of trouble finding this and even mentioned my trouble in another thread. I read the ConvertToYV12() function in the sources, but overlooked where the pixel type was being changed, since it is not near the main loop. Thanks ShOdan for not interpolating yet, it was much easier to follow that way. Hopefully, now people will always have the choice whether to interpolate or halve the frame.
The idea behind the filter is to see if the colors look better or sharper if I convert without interpolation, but with the chroma perfectly cited on the luma. Also I figured this could be used instead of VerticalReduceBy2(). It is very fast (for a filter that does not use mmx) and looks very good. This actually represents an idea I have that color space conversions and resizing can be optimized if done together. It might minimize the degradation due either to the conversion of resizing. I also noticed that there are many flavors of RGB:
RGB709, RGB601, RGB240M, RGBEDU, RGB255 for blackcode 0 on computers, and RGB219. Now I am on the quest for the perfect matrix to preserve gamma and color fidelity. The answer being that there is no perfect version because the absolute best is probubly different for interlaced, framebased, PAL, of NTSC sources. So my answer will be to try a couple and see.
I hope you like it.
Oh, and here's the attachment: