Log in

View Full Version : r,g,b in YV12


slicktail
28th March 2010, 02:38
Work in YU12 colorspace.
plane=PLANAR_Y; pFrame1 = frame1->GetReadPtr(plane);
//prosessing
pOut_frame = out_frame->GetWritePtr(plane);

plane=PLANAR_U; pFrame1 = frame1->GetReadPtr(plane);
//prosessing
pOut_frame = out_frame->GetWritePtr(plane);

plane=PLANAR_V; pFrame1 = frame1->GetReadPtr(plane);
//prosessing
pOut_frame = out_frame->GetWritePtr(plane);

When prosessing with Y (plane=PLANAR_Y), i may recieve variable Y of each pixel (*pOut_frame=*pFrame1) .
When I may recieve variables V,U in this cycle?
http://en.wikipedia.org/wiki/YUV said, that

Y=*pFrame1;
pFrame1+=((height*width)+(height*width)/4);
V=*pFrame1;
pFrame1-=((height*width)+(height*width)/4);
R=(BYTE)(Y+(1.13983*V));
R=*pFrame1;
*pOut_frame=R;

But it isn't working. Why? How i assign *pOut_frame=R?

IanB
28th March 2010, 09:55
You cannot assume the in memory layout of PVideoFrames.

You must ask the API for pointers to the start of each plane and the line pitch for that plane in order to access the require pixel.

Install the FilterSDK when you install Avisynth, this will give you a lot of examples and documentation.

Fizick, who does a lot of work on the SDK doco also maintains a Russian Avisynth site (http://www.avisynth.org.ru/) that you may find helpful.

For YV12 and RGB32 :-
pFrame1Y = frame1->GetReadPtr(PLANAR_Y);
pFrame1U = frame1->GetReadPtr(PLANAR_U);
pFrame1V = frame1->GetReadPtr(PLANAR_V);
pOut_frame = out_frame->GetWritePtr();

pitchY = frame1->GetPitch(PLANAR_Y);
pitchU = frame1->GetPitch(PLANAR_U);
pitchV = frame1->GetPitch(PLANAR_V);
outPitch = out_frame->GetPitch();

...
Y=pFrame1Y[x+y*pitchY];
V=pFrame1V[x/2+y/2*pitchV];

R=(BYTE)(Y+(1.13983*V));
...

// RGB32 is upside down.
pOut_frame[x*4+(height-y-1)*outPitch+3]=0; // Alpha
pOut_frame[x*4+(height-y-1)*outPitch+2]=R;
pOut_frame[x*4+(height-y-1)*outPitch+1]=G;
pOut_frame[x*4+(height-y-1)*outPitch+0]=B;

slicktail
30th March 2010, 06:49
Thank you!
Y=pFrame1Y[x+y*pitchY];
V=pFrame1V[x/2+y/2*pitchV];
How find U?

IanB
30th March 2010, 09:19
U=pFrame1U[x/2+y/2*pitchU];

x and y are column and row numbers (0 based, top left origin) respectively.

slicktail
30th March 2010, 13:55
pFrame2 = frame2->GetReadPtr(PLANAR_Y);
pFrame2U = frame2->GetReadPtr(PLANAR_U);
pFrame2V = frame2->GetReadPtr(PLANAR_V);
pOut_frame = out_frame->GetWritePtr();
frame_pitch = frame1->GetPitch(PLANAR_Y);
frame_pitchU = frame1->GetPitch(PLANAR_U);
.....
//Frame divide on blocks. Every Block read and write.
//pFrame2 - poiner on begin block (0,0), Y
//pFrame2U - poiner on begin block (0,0), U
//pFrame2V - poiner on begin block (0,0), V
....
for(int i=0;i<s_block;i++)
{ for(int j=0;j<s_block;j++)
{
if(j!=0)
{
pOut_frame+=1;
pFrame2+=1;
pFrame2U+=1;
pFrame2V+=1;
}
Y=*pFrame2;
U=*pFrame2U;
V=*pFrame2V;
G=(BYTE)(Y-(0.39465*U)-(0.58060*V));
*pOut_frame=G;
}
pFrame2+=(-(s_block-1)+frame_pitch);
pFrame2U+=(-(s_block-1)+frame_pitchU);
pFrame2V+=(-(s_block-1)+frame_pitchU);
pOut_frame+=(-(s_block-1)+frame_pitch);
}

But If I write Y - (*pOut_frame=Y), I recieve normal frame:
10930
If I write U - (*pOut_frame=U), I recieve bad frame:
10931
If I write V - (*pOut_frame=V), I recieve frame divided into 4 small frames of normal frame:
10932
Where is the error?

Gavino
30th March 2010, 20:12
Where is the error?
I don't fully understand what you're trying to do, but it seems to me you are not taking into account that the U and V planes have only half the width and height of the Y plane. So there are 4 Y pixels for each U and V pixel.

IanB
30th March 2010, 21:45
Yes 2x2 Y pixels for 1x1 U and V pixels, also every frame and every plane has its own pitch value.

You mention frame1, frame2 and out_frame in your code fragment yet you use frame1's pitch with frame2 and out_frame.

You will need to tell us about the code to get more specific help.

Look how SimpleSample in the SDK documentation changes as each improvement adds a new colour space or feature. See 1.1 and 1.6 for adding YV12.

slicktail
31st March 2010, 16:13
Each Frame divided on blocks size (s_block*s_block)
Then find move (SAD)
When I output frame, i want converted Y - R, etc

for(int i=0;i<s_block;i++)
{
for(int j=0;j<s_block;j++)
{
if(j!=0)
{
pOut_frame+=1;
pFrame2+=1;
pFrameX+=1;
}
//there must be converted to R
*pOut_frame=(BYTE)(*pFrameX+(*pFrame2-*pFrameX)*t);
}
pFrame2+=(-(s_block-1)+frame_pitch);
pFrameX+=(-(s_block-1)+frame_pitch);
pOut_frame+=(-(s_block-1)+frame_pitch);
}

how to get the RGB value in this place?
There is full code: 10936

IanB
1st April 2010, 00:10
As I keep saying, with Pitch you must use the value that goes with each PVideoFrame instance. As soon as someone does a SeparateFields(), a Crop() or a Splice() in the script then the values will be different for different frames. You only get frame1 pitch, yet you try to use it with frame2 and out_frame.


And you must account for the chroma planes being half height and half width. e.g.

Line 0
Y[0,0], U[0,0], V[0,0]
Y[1,0], U[0,0], V[0,0]
Y[2,0], U[1,0], V[1,0]
Y[3,0], U[1,0], V[1,0]
Y[4,0], U[2,0], V[2,0]
...
Line 1
Y[0,1], U[0,0], V[0,0]
Y[1,1], U[0,0], V[0,0]
Y[2,1], U[1,0], V[1,0]
Y[3,1], U[1,0], V[1,0]
Y[4,1], U[2,0], V[2,0]
...
Line 2
Y[0,2], U[0,1], V[0,1]
...

slicktail
1st April 2010, 09:40
Sorry,problem is described below

slicktail
6th April 2010, 05:46
PVideoFrame frame1 = child->GetFrame(n, env);
PVideoFrame out_frame = env->NewVideoFrame(vi);

pFrame1 = frame1->GetReadPtr(PLANAR_Y);
pFrame1U = frame1->GetReadPtr(PLANAR_U);
width = out_frame->GetRowSize();
height = out_frame->GetHeight();
pOut_frame = out_frame->GetWritePtr();

for (int h=0;h<height*width;h++)
{
Y=pFrame1[h];
//U=pFrame1U[h];
pOut_frame[h]=Y;
}

return out_frame;

How may i get Y,U,V in one cycle and write it in pOut_frame? Please, show me example

IanB
6th April 2010, 08:47
Assuming your input is YV12 and your output is to be RGB32, then here is a (slowish) YV12 to RGB32 template. // Rec601 coefficients
// ===================
#define Kr 0.299
#define Kg 0.587
#define Kb 0.114

// YUV to RGB conversion constants
// ===============================
const int crv = int(2*(1-Kr) * 255.0/224.0 * 65536+0.5);
const int cgv = int(2*(1-Kr)*Kr/Kg * 255.0/224.0 * 65536+0.5);
const int cgu = int(2*(1-Kb)*Kb/Kg * 255.0/224.0 * 65536+0.5);
const int cbu = int(2*(1-Kb) * 255.0/224.0 * 65536+0.5);

// Inline helper methods
static __inline BYTE ScaledPixelClip(int i) {
const int x = (i+32768) >> 16;

if (x <= 0) return 0;
if (x >= 255) return 255;

return (BYTE)x;
}

//===========================================

PVideoFrame frame1 = child->GetFrame(n, env); // Assumed to be YV12
BYTE *pFrame1Y = frame1->GetReadPtr(PLANAR_Y);
BYTE *pFrame1U = frame1->GetReadPtr(PLANAR_U);
BYTE *pFrame1V = frame1->GetReadPtr(PLANAR_V);
const int pitchY = frame1->GetPitch(PLANAR_Y);
const int pitchU = frame1->GetPitch(PLANAR_U);
const int pitchV = frame1->GetPitch(PLANAR_V);

PVideoFrame out_frame = env->NewVideoFrame(vi); // Assumed to be RGB32
BYTE *pOut_frame = out_frame->GetWritePtr();
const int outPitch = out_frame->GetPitch();

const int height = vi.height;
const int width = vi.width;

pOut_frame += outPitch*height; // RGB is upside down

for (int h=0; h<height; h++) {
pOut_frame -= outPitch;

for (int w=0; w<width; w++) {
const int Y = (pFrame1Y[w]-16) * int(255.0/219.0*65536+0.5);
const int U = pFrame1U[w/2]-128;
const int V = pFrame1V[w/2]-128;

pOut_frame[w*4+0] = ScaledPixelClip(Y + U * cbu ); // Blue
pOut_frame[w*4+1] = ScaledPixelClip(Y - U * cgu - V * cgv); // Green
pOut_frame[w*4+2] = ScaledPixelClip(Y + V * crv); // Red
pOut_frame[w*4+3] = 0; // Alpha
}

if (h & 1) { // Only every 2nd line
pFrame1U += pitchU;
pFrame1V += pitchV;
}
pFrame1Y += pitchY;
}

return out_frame;From your block.cpp sample I think you are trying to do a lot more, but without english comments I cannot begin to understand your intentions. I am guessing you are stuck with how to deal with the half height and half width chroma planes and/or the effect of pitch on processing each row. Hopefully the above example for passing a YV12 frame into a RGB32 frame will help you move forwards.

The above is by no means the fastest way, but I hope the steps are more clear as it is written. Possible improvements are to do 2 lines per outer loop and 2 pixels per inner loop, i.e. reference and calculate the U and V values once only for processing with 4 Y pixels.

slicktail
6th April 2010, 09:35
IanB, thank you. Your code is very useful!
But:
Input frame - YV12
If I use BYTE *pOut_frame = out_frame->GetWritePtr(),
output frame will be in YV12 or RGB?
Please, write, how may in one cycle use Y,U,V in YV12 output frame (such as SimpleSample 1.6,but in SimpleSample is three cycle). IanB, sorry for my nub.

Gavino
6th April 2010, 10:57
If I use BYTE *pOut_frame = out_frame->GetWritePtr(),
output frame will be in YV12 or RGB?
By default, it will be the same as the input (child) clip - in this case YV12.
If you want it to be different, you have to change the appropriate vi property in your constructor, eg
vi.pixel_type = CS_BGR32;
Please, write, how may in one cycle use Y,U,V in YV12 output frame (such as SimpleSample 1.6,but in SimpleSample is three cycle).
The logic of the loop is the same as IanB's example above, but instead of a single pOut_frame and outPitch, for YV12 output you would use a frame pointer and pitch for each plane, updating the output frame pointers within the loop in the same way as for the input frame pointers.

slicktail
6th April 2010, 16:11
By default, it will be the same as the input (child) clip - in this case YV12.
If you want it to be different, you have to change the appropriate vi property in your constructor, eg
vi.pixel_type = CS_BGR32;

The logic of the loop is the same as IanB's example above, but instead of a single pOut_frame and outPitch, for YV12 output you would use a frame pointer and pitch for each plane, updating the output frame pointers within the loop in the same way as for the input frame pointers.

Thank you, Gavino. Please write code, i am confused :(

Gavino
6th April 2010, 22:49
Please write code, i am confused :(
Basically, something like this:
PVideoFrame frame1 = child->GetFrame(n, env); // Assumed to be YV12
BYTE *pFrame1Y = frame1->GetReadPtr(PLANAR_Y);
BYTE *pFrame1U = frame1->GetReadPtr(PLANAR_U);
BYTE *pFrame1V = frame1->GetReadPtr(PLANAR_V);
const int pitchY = frame1->GetPitch(PLANAR_Y);
const int pitchU = frame1->GetPitch(PLANAR_U);
const int pitchV = frame1->GetPitch(PLANAR_V);

PVideoFrame out_frame = env->NewVideoFrame(vi); // Assumed to be YV12 also
BYTE *pOut_frameY = out_frame->GetWritePtr(PLANAR_Y);
BYTE *pOut_frameU = out_frame->GetWritePtr(PLANAR_U);
BYTE *pOut_frameV = out_frame->GetWritePtr(PLANAR_V);
const int outPitchY = out_frame->GetPitch(PLANAR_Y);
const int outPitchU = out_frame->GetPitch(PLANAR_U);
const int outPitchV = out_frame->GetPitch(PLANAR_V);

const int height = vi.height;
const int width = vi.width;

for (int h=0; h<height; h++) {
for (int w=0; w<width; w++) {
const int Y = pFrame1Y[w];
const int U = pFrame1U[w/2];
const int V = pFrame1V[w/2];

... // calculate output Y, U, V values

pOut_frameY[w] = ... ; // write output Y
pOut_frameU[w/2] = ... ; // U
pOut_frameV[w/2] = ... ; // V
}

if (h & 1) { // Only every 2nd line
pFrame1U += pitchU;
pFrame1V += pitchV;
pOut_frameU += outPitchU;
pOut_frameV += outPitchV;
}
pFrame1Y += pitchY;
pOut_frameY += outPitchY;
}

return out_frame;

It's not perfect - every U and V value gets written twice - but the logic of that part depends on how you derive the output values from the input values anyway. As Ian said, "Possible improvements are to do 2 lines per outer loop and 2 pixels per inner loop, i.e. reference and calculate the U and V values once only for processing with 4 Y pixels."

IanB
6th April 2010, 23:45
Snap Gavino :p

Of course when outputting YV12 you need accumulate the final U and V values over source 4 pixels, hence you need to process 4 pixels per iteration. Here is a template to apply an arbitrary per pixel transform. BYTE FunctionY(int Y, int U, int V);
int FunctionU(int Y, int U, int V);
int FunctionV(int Y, int U, int V);

// ==========================================

PVideoFrame frame1 = child->GetFrame(n, env); // Assumed to be YV12
BYTE *pFrame1Y = frame1->GetReadPtr(PLANAR_Y);
BYTE *pFrame1U = frame1->GetReadPtr(PLANAR_U);
BYTE *pFrame1V = frame1->GetReadPtr(PLANAR_V);
const int pitchY = frame1->GetPitch(PLANAR_Y);
const int pitchU = frame1->GetPitch(PLANAR_U);
const int pitchV = frame1->GetPitch(PLANAR_V);

PVideoFrame out_frame = env->NewVideoFrame(vi); // Assumed to be YV12
BYTE *pOut_frameY = out_frame->GetWritePtr(PLANAR_Y);
BYTE *pOut_frameU = out_frame->GetWritePtr(PLANAR_U);
BYTE *pOut_frameV = out_frame->GetWritePtr(PLANAR_V);
const int outPitchY = out_frame->GetPitch(PLANAR_Y);
const int outPitchU = out_frame->GetPitch(PLANAR_U);
const int outPitchV = out_frame->GetPitch(PLANAR_V);

const int height = vi.height;
const int width = vi.width;

BYTE *pFrame1Y1 = pFrame1Y + pitchY;
BYTE *pOut_frameY1 = pOut_frameY + outPitchY;

for (int h=0; h<height; h+=2) { // Only every 2nd line
for (int w=0; w<width; w+=2) { // Only every 2nd pixel
int Y, outU, outV;

const int U = (pFrame1U[w/2] - 128) * int(255.0/112.0*65536+0.5);
const int V = (pFrame1V[w/2] - 128) * int(255.0/112.0*65536+0.5);

// Pixel[00]
Y = (pFrame1Y[w]-16) * int(255.0/219.0*65536+0.5);

pOut_frameY[w] = FunctionY(Y, U, V);
outU = FunctionU(Y, U, V);
outV = FunctionV(Y, U, V);

// Pixel[01]
Y = (pFrame1Y[w+1]-16) * int(255.0/219.0*65536+0.5);

pOut_frameY[w+1] = FunctionY(Y, U, V);
outU += FunctionU(Y, U, V);
outV += FunctionV(Y, U, V);

// Pixel[10]
Y = (pFrame1Y1[w]-16) * int(255.0/219.0*65536+0.5);

pOut_frameY1[w] = FunctionY(Y, U, V);
outU += FunctionU(Y, U, V);
outV += FunctionV(Y, U, V);

// Pixel[11]
Y = (pFrame1Y1[w+1]-16) * int(255.0/219.0*65536+0.5);

pOut_frameY1[w+1] = FunctionY(Y, U, V);
outU += FunctionU(Y, U, V);
outV += FunctionV(Y, U, V);

// (Pixel[00]+Pixel[01]+Pixel[10]+Pixel[11]+2)/4
pOut_frameU[w/2] = BYTE((outU + 2 + 128*4) / 4);
pOut_frameV[w/2] = BYTE((outV + 2 + 128*4) / 4);
}

pFrame1Y += pitchY*2;
pFrame1Y1 += pitchY*2;
pFrame1U += pitchU;
pFrame1V += pitchV;

pOut_frameY += outPitchY*2;
pOut_frameY1 += outPitchY*2;
pOut_frameU += outPitchU;
pOut_frameV += outPitchV;
}

return out_frame;Of course the above code is not strictly right in that it assumes MPEG1 chroma positioning. This is often done because it is easy. Strictly correct code involves using the current chroma value for the left 2 pixels and calculating an average chroma for the right 2 pixels from the current and next chroma values.

slicktail
17th April 2010, 05:12
IanB, Gavino! Thank you for great code and example! It were very useful for me and my work! Thank you!