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.

 

Go Back   Doom9's Forum > Capturing and Editing Video > Avisynth Development

Reply
 
Thread Tools Search this Thread Display Modes
Old 28th March 2010, 02:38   #1  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
r,g,b in YV12

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?
slicktail is offline   Reply With Quote
Old 28th March 2010, 09:55   #2  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
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 that you may find helpful.

For YV12 and RGB32 :-
Code:
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;
IanB is offline   Reply With Quote
Old 30th March 2010, 06:49   #3  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Thank you!
Y=pFrame1Y[x+y*pitchY];
V=pFrame1V[x/2+y/2*pitchV];
How find U?

Last edited by slicktail; 30th March 2010 at 07:33.
slicktail is offline   Reply With Quote
Old 30th March 2010, 09:19   #4  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
U=pFrame1U[x/2+y/2*pitchU];

x and y are column and row numbers (0 based, top left origin) respectively.
IanB is offline   Reply With Quote
Old 30th March 2010, 13:55   #5  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Code:
 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:
Name:  UntitledY.jpg
Views: 439
Size:  145.2 KB
If I write U - (*pOut_frame=U), I recieve bad frame:
Name:  UntitledU.jpg
Views: 477
Size:  144.5 KB
If I write V - (*pOut_frame=V), I recieve frame divided into 4 small frames of normal frame:
Name:  UntitledV.jpg
Views: 440
Size:  47.4 KB
Where is the error?

Last edited by slicktail; 30th March 2010 at 17:27.
slicktail is offline   Reply With Quote
Old 30th March 2010, 20:12   #6  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by slicktail View Post
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.
Gavino is offline   Reply With Quote
Old 30th March 2010, 21:45   #7  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
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.
IanB is offline   Reply With Quote
Old 31st March 2010, 16:13   #8  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Each Frame divided on blocks size (s_block*s_block)
Then find move (SAD)
When I output frame, i want converted Y - R, etc
Code:
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: Block.rar
slicktail is offline   Reply With Quote
Old 1st April 2010, 00:10   #9  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
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]
...
IanB is offline   Reply With Quote
Old 1st April 2010, 09:40   #10  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Sorry,problem is described below

Last edited by slicktail; 6th April 2010 at 05:44.
slicktail is offline   Reply With Quote
Old 6th April 2010, 05:46   #11  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Code:
    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
slicktail is offline   Reply With Quote
Old 6th April 2010, 08:47   #12  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Assuming your input is YV12 and your output is to be RGB32, then here is a (slowish) YV12 to RGB32 template.
Code:
  // 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.
IanB is offline   Reply With Quote
Old 6th April 2010, 09:35   #13  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
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.
slicktail is offline   Reply With Quote
Old 6th April 2010, 10:57   #14  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by slicktail View Post
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;
Quote:
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.
Gavino is offline   Reply With Quote
Old 6th April 2010, 16:11   #15  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
Quote:
Originally Posted by Gavino View Post
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
slicktail is offline   Reply With Quote
Old 6th April 2010, 22:49   #16  |  Link
Gavino
Avisynth language lover
 
Join Date: Dec 2007
Location: Spain
Posts: 3,431
Quote:
Originally Posted by slicktail View Post
Please write code, i am confused
Basically, something like this:
Code:
  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."
Gavino is offline   Reply With Quote
Old 6th April 2010, 23:45   #17  |  Link
IanB
Avisynth Developer
 
Join Date: Jan 2003
Location: Melbourne, Australia
Posts: 3,167
Snap Gavino

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.
Code:
  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.

Last edited by IanB; 17th April 2010 at 08:08. Reason: Ah Damn! Snap Gavino + GetWritePtr :o
IanB is offline   Reply With Quote
Old 17th April 2010, 05:12   #18  |  Link
slicktail
Registered User
 
Join Date: Feb 2010
Location: Russia
Posts: 21
IanB, Gavino! Thank you for great code and example! It were very useful for me and my work! Thank you!
slicktail is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +1. The time now is 21:59.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.