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 Usage

Reply
 
Thread Tools Search this Thread Display Modes
Old 23rd September 2002, 17:04   #21  |  Link
vlad59
Vlad, the Buffy slayer
 
vlad59's Avatar
 
Join Date: Oct 2001
Location: France
Posts: 445
@MarcFD

Of course as it's the first planar format in avisynth we'll have to change a little bit the architecture.

But I think we have to use a maximum current avisynth code when possible to use stable code a maximum.

I personnaly it's a good idea to keep only one VideoFrameBuffer* in VideoFrame so we don't have to change anything in cache specific code.

For now we just have to be talk about new functions of VideoFrame not the internal code (wich can evolve in the future).

So my proposition is :
Code:
class VideoFrame {
  int refcount;
  VideoFrameBuffer* const vfb;
  const int offset, pitch, row_size, height;

  friend class PVideoFrame;
  void AddRef() { ++refcount; }
  void Release() { if (refcount==1) --vfb->refcount; --refcount; }

  friend class ScriptEnvironment;
  friend class Cache;

  VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);

  void* operator new(unsigned size);

public:
  int GetPitch() const { return pitch; }
  int GetYPitch () const {return pitch;}
  int GetUPitch () const {return pitch>>1;}
  int GetVPitch () const {return pitch>>1;}
// we could have done a int GetUVPitch () const {return pitch>>1;}

  int GetRowSize() const { return row_size; }
  int GetHeight() const { return height; }

  // generally you shouldn't use these two 
  VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
  int GetOffset() const { return offset; }

  // in plugins use env->SubFrame()
  VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;

  const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
  const BYTE* GetReadPtr(BYTE p_channel) const { return vfb->GetReadPtr() + ???? (to be defined); }


  bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }

  BYTE* GetWritePtr() const {
    return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
  }

  ~VideoFrame() { --vfb->refcount; }
};
the code defined can be changed of course it's only my current sources.

The problem will be eventually with U or V pointer wich could be only 2bytes aligned depending of the cropping values.

EDIT : Sorry Sh0dan and MarcFd I've waited too long before send my answer, I haven't read your last posts.
I also forgot to check for pixel_type in specific Get_Pitch.
__________________
Vlad59
Convolution3D for avisynth 2.0X : http://www.hellninjacommando.com/con3d
Convolution3D for avisynth 2.5 : http://www.hellninjacommando.com/con3d/beta

Last edited by vlad59; 23rd September 2002 at 17:13.
vlad59 is offline   Reply With Quote
Old 23rd September 2002, 17:31   #22  |  Link
Marc FD
XviD fan
 
Marc FD's Avatar
 
Join Date: Jun 2002
Location: France
Posts: 907
the question is :
do you want YUV 4:2:0 (I420/YV12) planar support in avisynth (3 blocks),
or you just want block YV12 (1 block) ??

i'd prefer full planar support.

(XviD/ffdshow/MPEG2Dec/ect.. uses full YUV 4:2:0 _planar_ format)

i don't know how to use polymorphism in C++, but if it's like in Delphi, should be possible to implement a child of VideoFrame, like PlanarVideoFrame, and then use it if you have YV12 colorspace, no ??

maybe it's impossible

Last edited by Marc FD; 23rd September 2002 at 17:33.
Marc FD is offline   Reply With Quote
Old 23rd September 2002, 17:42   #23  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
Quote:
Originally posted by Marc FD

what is (stuff) ??
Offset (see next post)
Quote:
BTW, i absolutly knows nothing about avisynth internals, but if the 3 blocks aren't contiguous, how do you free/copy the data
You don't - as with the existing framework, you never allocate or deallocate a frame yourself. Allocation is done using NewVideoFrame(), and Avisynth does the deallocation.
As now, you cannot write to the pointers yourself, you can only request an empty frame and write to it. If you want 3 pointers, you have to request three pointers, my point is, that you could do this by only requesting one (as now), and easily calculate the rest yourself.

Therefore we can force data to be continuous, I can't see any real arguments for not having this, honestly.
__________________
Regards, sh0dan // VoxPod
sh0dan is offline   Reply With Quote
Old 23rd September 2002, 17:52   #24  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
Quote:
Originally posted by vlad59

So my proposition is :
[...]
With small changes:

Code:
class VideoFrame {
  int refcount;
  VideoFrameBuffer* const vfb;
  const int offset, pitch, row_size, height, int UV_pitch;

  friend class PVideoFrame;
  void AddRef() { ++refcount; }
  void Release() { if (refcount==1) --vfb->refcount; --refcount; }

  friend class ScriptEnvironment;
  friend class Cache;

  VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);

  void* operator new(unsigned size);
  enum {YV12_CHANNEL_Y=0;YV12_CHANNEL_U=1;YV12_CHANNEL_V=2}; // for planar modes only.
public:
  int GetPitch() const { return pitch; }
  int GetYPitch () const {return pitch;}
  int GetUVPitch () const {return uv_pitch;}

  int GetRowSize() const { return row_size; }
  int GetHeight() const { return height; }

  // generally you shouldn't use these two 
  VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
  int GetOffset() const { return offset; }

  // in plugins use env->SubFrame()
  VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;

  const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
  const BYTE* GetReadPtr(BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return vfb->GetReadPtr();
      case YV12_CHANNEL_U:
        return vfb->GetReadPtr()+(height*pitch);
      case YV12_CHANNEL_V:
        return vfb->GetReadPtr()+(height*pitch)+((height>>1)*uv_pitch);
      default:
      _ASSERT(FALSE);
   }
   return vfb->GetReadPtr(); 
 }


  bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }

  BYTE* GetWritePtr() const {
    return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
  }

  ~VideoFrame() { --vfb->refcount; }
};
Would it make more sense to overload GetPitch, and make different types, so it could return even more types of pitches?

[EDIT]"Full planar" is still possible, since the enums just could be expanded - perhaps the GetPitch should also be like this:
Code:
  int GetPitch (BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return pitch;
      case YV12_CHANNEL_U:
        return uv_pitch;
      case YV12_CHANNEL_V:
        return uv_pitch;
      default:
      _ASSERT(FALSE);
   }
   return uv_pitch;
  }
__________________
Regards, sh0dan // VoxPod

Last edited by sh0dan; 23rd September 2002 at 17:57.
sh0dan is offline   Reply With Quote
Old 23rd September 2002, 17:55   #25  |  Link
-h
Kilted Yaksman
 
-h's Avatar
 
Join Date: Oct 2001
Location: South Carolina
Posts: 1,303
do you want YUV 4:2:0 (I420/YV12) planar support in avisynth (3 blocks), or you just want block YV12 (1 block) ??

Remember, the only reason that programs like DVD2AVI/MPEG2DEC/XviD/libavcodec use separate planes is because of the image edging that the MPEG standards necessitate. Any program that desires YV12 input is going to want it in a single block, and will output it as a similar block, since that's what the standard requires (see hardware overlay support for why this is important). If you want SSE2-compatible alignment, you could do that with a single block by aligning it on 32 bytes, giving the UV planes 16-byte alignment.

I guess my biggest qualm with separate blocks is that you will have to blit the input into separate buffers at the start, then blit it back into a single block at the end, when you could avoid both. Though you could resolve this by making sure any yv12 input source is block-aware, and fills the pointers for you (i.e. a special build of mpeg2dec or something).

-h
-h is offline   Reply With Quote
Old 23rd September 2002, 18:04   #26  |  Link
Marc FD
XviD fan
 
Marc FD's Avatar
 
Join Date: Jun 2002
Location: France
Posts: 907
Quote:
Originally posted by sh0dan

Therefore we can force data to be continuous, I can't see any real arguments for not having this, honestly.
you are right.

i've taken a look in the avisynth internals (the first time i do this ) and i see know what you think. it make sense for me now

sorry if i didn't understood you immediatly

Okay, so when we use I420 colorspace with a bit alignement.
you need a new pitch,row_size and height.

my suggestion

Code:
class VideoFrame {
  int refcount;
  VideoFrameBuffer* const vfb;
  const int offset, pitch, row_size, height;
  const int pitch2, row_size2, height2; // needed for I420 alignement

  friend class PVideoFrame;
  void AddRef() { ++refcount; }
  void Release() { if (refcount==1) --vfb->refcount; --refcount; }

  friend class ScriptEnvironment;
  friend class Cache;

  VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height);

  void* operator new(unsigned size);

public:
  int GetPitch() const { return pitch; }
  int GetPitch2() const {return pitch2;}

  int GetRowSize() const { return row_size; }
  int GetRowSize2() const { return row_size2; }
  int GetHeight() const { return height; }
  int GetHeight2() const { return height2; }

  // generally you shouldn't use these two 
  VideoFrameBuffer* GetFrameBuffer() const { return vfb; }
  int GetOffset() const { return offset; }

  // in plugins use env->SubFrame()
  VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const;

  const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; }
  const BYTE* GetReadPtr(BYTE plane) const {
    if (plane==Y_PLANE) { 
      return vfb->GetReadPtr() + offset;
    } else if  (plane==U_PLANE) { 
      return vfp->GetReadPtr() + offset + pitch*height(+alignement trick)
    } else if (plane==V_PLANE) {
      return vfp->GetReadPtr() + offset + pitch*height(+alignement trick) + pitch2*height2(+alignement trick)
    } else {
      return vfb->GetReadPtr() + offset; // default
    }
}

vfp->GetReadPtr() + offset + pitch*height + pitch2*height2 + 


  bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); }

  BYTE* GetWritePtr() const {
    return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
  }

  ~VideoFrame() { --vfb->refcount; }
};
seems logical, no ?

EDIT : sorry didn't see yours

Last edited by Marc FD; 23rd September 2002 at 18:07.
Marc FD is offline   Reply With Quote
Old 23rd September 2002, 18:14   #27  |  Link
vlad59
Vlad, the Buffy slayer
 
vlad59's Avatar
 
Join Date: Oct 2001
Location: France
Posts: 445
Quote:
Originally posted by sh0dan
Would it make more sense to overload GetPitch, and make different types, so it could return even more types of pitches?

[EDIT]"Full planar" is still possible, since the enums just could be expanded - perhaps the GetPitch should also be like this:
Code:
  int GetPitch (BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return pitch;
      case YV12_CHANNEL_U:
        return uv_pitch;
      case YV12_CHANNEL_V:
        return uv_pitch;
      default:
      _ASSERT(FALSE);
   }
   return uv_pitch;
  }
[/B]
Yes I think we must use the same trick on GetReadPtr, GetPitch and even GetRowSize and GetHeight.

And it must also be the same with GetWritePtr. About GetWritePtr I think we will be obliged to provide standard function to copy one plane as Bitblt will copy the three planes.

@MarcFD
I globally agree with your code example (althought I prefer uv_pitch than pitch2 ).
But IMHO height2 and rowsize2 are not usefull as
height2 = height/2 and
rowsize2 = rowsize/2

Instead we need specific offset for U and V plane (to crop and keep correct alignment).

I'll have to think more about it.
__________________
Vlad59
Convolution3D for avisynth 2.0X : http://www.hellninjacommando.com/con3d
Convolution3D for avisynth 2.5 : http://www.hellninjacommando.com/con3d/beta

Last edited by vlad59; 23rd September 2002 at 18:33.
vlad59 is offline   Reply With Quote
Old 23rd September 2002, 18:17   #28  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
@marcfd:

- Pitches are already aligned - no need to adjust them. Consider pitches aligned widths.

- No need for seperate height and row-size - they are always half of the Y-original.

- We should use existing naming convensions. In half a year, people will wonder what the difference is between GetPitch() and GetPitch2() - avisynth.h should be as meaningful as possible.
__________________
Regards, sh0dan // VoxPod
sh0dan is offline   Reply With Quote
Old 23rd September 2002, 18:19   #29  |  Link
Marc FD
XviD fan
 
Marc FD's Avatar
 
Join Date: Jun 2002
Location: France
Posts: 907
Quote:
Originally posted by vlad59

But IMHO height2 and rowsize2 and not usefull as
height2 = height/2 and
rowsize2 = rowsize/2
oups i forgot we have mod2 restricition
yes of course you don't need them.
uv_pitch is not bad but then y_pitch is logical.
it's why i prefer the pitch/pitch2 pair or (compromise) a pitch/pitchUV
Marc FD is offline   Reply With Quote
Old 23rd September 2002, 18:35   #30  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
Quote:
Originally posted by vlad59

Instead we need specific offset for U and V plane (to crop and keep correct alignment).
You're right!! I had completely forgotten about crop!

Wouldn't this hold up? Or is my math bad?
Code:
 const BYTE* GetReadPtr(BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return vfb->GetReadPtr();
      case YV12_CHANNEL_U:
        return vfb->GetReadPtr()+(height*pitch)+(offset>>2);
      case YV12_CHANNEL_V:
        return vfb->GetReadPtr()+(height*pitch)+(offset>>1)+((height>>1)*uv_pitch);
      default:
      _ASSERT(FALSE);
   }
__________________
Regards, sh0dan // VoxPod
sh0dan is offline   Reply With Quote
Old 23rd September 2002, 19:09   #31  |  Link
vlad59
Vlad, the Buffy slayer
 
vlad59's Avatar
 
Join Date: Oct 2001
Location: France
Posts: 445
Quote:
Originally posted by sh0dan


You're right!! I had completely forgotten about crop!

Wouldn't this hold up? Or is my math bad?
Code:
 const BYTE* GetReadPtr(BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return vfb->GetReadPtr();
      case YV12_CHANNEL_U:
        return vfb->GetReadPtr()+(height*pitch)+(offset>>2);
      case YV12_CHANNEL_V:
        return vfb->GetReadPtr()+(height*pitch)+(offset>>1)+((height>>1)*uv_pitch);
      default:
      _ASSERT(FALSE);
   }
No I think it should be :
Code:
 const BYTE* GetReadPtr(BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return vfb->GetReadPtr() + offset; // at least I'm sure of that
      case YV12_CHANNEL_U:
        return vfb->GetReadPtr+(height*(pitch + offset))+(offset>>1);
      case YV12_CHANNEL_V:
        return vfb->GetReadPtr()+(height*(pitch + offset))+((height>>1)*(uv_pitch + offset>>1))+ offset>>1;
      default:
      _ASSERT(FALSE);
   }

I'm not 100% sure. But I think it's correct (I'm often wrong ).

We must also add some check to allow the use of this function only with YV12.
So I have many questions :
in
Code:
  enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22, YV12=0x?? };
what values should we use :
0x2? to make isYUV answer true
or
0x3? to make a future isPlanar answer true

With we should have :
Code:
 const BYTE* GetReadPtr(BYTE p_channel) const {
    if (!(pixel_type&0x30))
        Throw error
or
    if (pixel_type != YV12)
        Throw error

Lots of things to think about

EDIT : @Sh0dan forget about my correction, it's wrong I have misunderstood the use of offset, sorry
__________________
Vlad59
Convolution3D for avisynth 2.0X : http://www.hellninjacommando.com/con3d
Convolution3D for avisynth 2.5 : http://www.hellninjacommando.com/con3d/beta

Last edited by vlad59; 23rd September 2002 at 19:11.
vlad59 is offline   Reply With Quote
Old 23rd September 2002, 19:43   #32  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
Quote:
Originally posted by vlad59
No I think it should be :
Code:
 const BYTE* GetReadPtr(BYTE p_channel) const {
   switch (p_channel) {
      case YV12_CHANNEL_Y:
        return vfb->GetReadPtr() + offset; // at least I'm sure of that
      case YV12_CHANNEL_U:
        return vfb->GetReadPtr+(height*(pitch + offset))+(offset>>1);
      case YV12_CHANNEL_V:
        return vfb->GetReadPtr()+(height*(pitch + offset))+((height>>1)*(uv_pitch + offset>>1))+ offset>>1;
      default:
      _ASSERT(FALSE);
   }
ok - I'll do the math (just as exited as you are)

YPitch = 100
UVPitch = 50
We crop: top = 4 pixels, left= 6 pixels.

Y offset = (4 * 1 byte * Ypitch) + 6 * 1 byte = 406 bytes (not mod4 <shivers>)
U offset = (4 pixels * 1 byte * UVpitch)/2 + (6 pixels * 1 byte) /2 = 103

Surprise! None of us was right. Conclusion - we need to store one offset for Y and one for each U and V.
Quote:
I'm not 100% sure. But I think it's correct (I'm often wrong ).
Well - that goes for both of us
Quote:
We must also add some check to allow the use of this function only with YV12.
So I have many questions :
in
Code:
  enum { UNKNOWN=0, BGR24=0x13, BGR32=0x14, YUY2=0x22, YV12=0x?? };
what values should we use :
0x2? to make isYUV answer true
or
0x3? to make a future isPlanar answer true
Bens raionale seems to be 0x"RGB=1, YUV=2""how many bytes per pixel" - this just doesn't make sense when dealing with YV12. A way of dealing with it, could be to redefine them as masks - not the best way, but better.
So:
Code:
  enum { ISBGR=1<<1, ISYUV=1<<2, ISPLANAR=1<<3 };
But then, how do we know if it is RGB24 or RGB32, and how do we handle BytesFromPixels? Should we add a "byte bitsperpixel" to the struct, and derive BytesFromPixels from that?
Quote:
Lots of things to think about
Yeah - too many things are still unclear!

I hope you all see why we can't rush into doing YV12 - there are many considerations we have to do before implementing it.
__________________
Regards, sh0dan // VoxPod
sh0dan is offline   Reply With Quote
Old 23rd September 2002, 19:55   #33  |  Link
Marc FD
XviD fan
 
Marc FD's Avatar
 
Join Date: Jun 2002
Location: France
Posts: 907
Quote:
Originally posted by sh0dan

Code:
  enum { ISBGR=1<<1, ISYUV=1<<2, ISPLANAR=1<<3 };
what do you think of 0x4xx for planar colorspace ?

4:2:0 -> 0x420 / 4:2:2 -> 0x422 / 4:4:4 -> 0x444

it makes sense ??

Quote:

Yeah - too many things are still unclear!

I hope you all see why we can't rush into doing YV12 - there are many considerations we have to do before implementing it.
sure.

let's discuss of everything we need
Marc FD is offline   Reply With Quote
Old 23rd September 2002, 21:35   #34  |  Link
vlad59
Vlad, the Buffy slayer
 
vlad59's Avatar
 
Join Date: Oct 2001
Location: France
Posts: 445
Quote:
Originally posted by sh0dan

Surprise! None of us was right. Conclusion - we need to store one offset for Y and one for each U and V.
Yes I went to the same conclusion before going out for lunch. We must think quickly of how to crop and resize to test our ideas.

Quote:

Bens raionale seems to be 0x"RGB=1, YUV=2""how many bytes per pixel" - this just doesn't make sense when dealing with YV12. A way of dealing with it, could be to redefine them as masks - not the best way, but better.
So:
Code:
  enum { ISBGR=1<<1, ISYUV=1<<2, ISPLANAR=1<<3 };
But then, how do we know if it is RGB24 or RGB32, and how do we handle BytesFromPixels? Should we add a "byte bitsperpixel" to the struct, and derive BytesFromPixels from that?
No we could keep the same structure and add the planar information
So we could have
Code:
  enum { UNKNOWN=0, BGR24=0x013, BGR32=0x014, YUY2=0x022, YV12=0x122 };
Here we loose space as we consider that YV12 use 2 byte per pixel instead of 1.5 (wich is not so bad as a beginning.

But MarcFD's idea is a good one too. we really need to share our ideas

Quote:

Yeah - too many things are still unclear!

I hope you all see why we can't rush into doing YV12 - there are many considerations we have to do before implementing it.
I agree we really need to take enought time to have clear specs.

I need some sleep after that
__________________
Vlad59
Convolution3D for avisynth 2.0X : http://www.hellninjacommando.com/con3d
Convolution3D for avisynth 2.5 : http://www.hellninjacommando.com/con3d/beta
vlad59 is offline   Reply With Quote
Old 23rd September 2002, 21:59   #35  |  Link
sh0dan
Retired AviSynth Dev ;)
 
sh0dan's Avatar
 
Join Date: Nov 2001
Location: Dark Side of the Moon
Posts: 3,480
A little OT. Took some time, and finished first proposal for new sample support in 2.1, with float samples and multiple channels. It compiles, and has AVI in/out working. Some audio filters have been converted, but not tested. Plugins seems to be a problem - we'll have to see about that - they seem to break sound(?)

Most interesting changes are in avisynth.h

You can see the branch at: http://cvs.sourceforge.net/cgi-bin/v...g=avisynth_2_1
__________________
Regards, sh0dan // VoxPod
sh0dan 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 11:21.


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