Log in

View Full Version : Question about source and destination in pluggin


jpsdr
28th August 2015, 12:44
I'm wondering something, because of VDub pluggin behavior.

In VDub pluggin, there is the FILTERPARAM_SWAP_BUFFERS parameter. If you use it, memory storage for source and destination will be differents.
If you don't, source and destination pointers will be the same.

How avisynth behave, when i'm doing something like this :

PVideoFrame __stdcall AutoYUY2::GetFrame(int n, IScriptEnvironment* env)
{
PVideoFrame src = child->GetFrame(n,env);
PVideoFrame dst = env->NewVideoFrame(vi);
uint8_t *dstp = dst->GetWritePtr(PLANAR_Y);
const uint8_t *srcYp = src->GetReadPtr(PLANAR_Y);

TurboPascal7
28th August 2015, 15:29
Surprisingly enough, NewVideoFrame returns a new video frame. With its own buffers and everything.

jpsdr
28th August 2015, 17:52
Surprisingly enough, NewVideoFrame returns a new video frame. With its own buffers and everything.

What a surprise indeed :eek:

:thanks:

StainlessS
29th August 2015, 12:41
With GetFrame() you need to use env->MakeWritable(&dst); before any writing (EDIT: Creates new frame and blits the contents of frame into the new writable one), best used where you are modifying just selected pixels or channels.
NewVideoFrame is already writable but you need to render all channels with valid data.

jpsdr
30th August 2015, 10:13
In my case, colorspace change, so using NewVideoFrame is obviously the correct way.
In case you eventualy don't need to create a new frame, i assume somthing like this would be the correct way :

PVideoFrame __stdcall AutoYUY2::GetFrame(int n, IScriptEnvironment* env)
{
PVideoFrame frame = child->GetFrame(n,env);
const uint8_t *src = frame->GetReadPtr(PLANAR_Y);
env->MakeWritable(&frame);
uint8_t *dst=frame->GetWritePtr(PLANAR_Y);


Is this the only way, and it always works the same way (creates a new memory and duplicate), or is there also a way to work the same than VDub pluggin, having finaly src and dst the same (avoiding the time and ressources to allocate new memory and transfer data) and somthing like the FILTERPARAM_SWAP_BUFFERS of VDub pluggin is also avaible on avisynth ?

foxyshadis
30th August 2015, 12:16
MakeWritable already works like vdub! The dest buffer is the same as source and you'd better keep track. It's NewVideoFrame that is the standard way that creates an entirely new canvas for you to write on.

But seriously, it's 2015. Memory is in vast supply and you can memory transfer one to two thousand frames a second at 1080p. Why would you ever need to use MakeWritable unless you're making a simple, small change to an existing image? Any full-frame processing would be better off writing to a new buffer to eliminate any possibility of bugs. (For instance, your idea of stride may not be the same as the buffer's.)

jpsdr
1st September 2015, 09:47
Don't want to open another thread, more or less related... :D

If i want to know the size of the whole frame, should be multiplanar or not, is vi.BMPSize() the size of the whole frame ?
If not, what is it ? I've not been able to see anything else that could provide this information in the avisynth.h.

StainlessS
1st September 2015, 14:50
From Wiki here: http://avisynth.nl/index.php/Filter_SDK/Cplusplus_API/VideoInfo

int BMPSize() const;

For interleaved formats it will return the size of the frame in bytes where the width is rounded up to a multiple of 4 bytes.
For planar formats it will do the same but only for the first plane. So, it's the number of bytes of a frame as it was a BMP frame.

examples:

640x480 RGB24: BMPSize() = 480 * 3*640 = 921600
643x480 RGB24: BMPSize() = 480 * 3*644 = 927360

640x480 YV24: BMPSize() = 480 * 640 = 307200
643x480 YV24: BMPSize() = 480 * 644 = 309120

Since v5 the behavior for planar formats is the same as for interleaved formats.


From Source v2.6 Final:

// struct VideoInfo
&VideoInfo::BMPSize, // int (VideoInfo::*BMPSize)() const;


Also baked as COMMENT (VERSION 3 header), from v2.6 Interface.cpp

/* Baked ********************
bool VideoInfo::IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this
int VideoInfo::BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); }
// Will not work on planar images, but will #return only luma planes

int VideoInfo::RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images
int VideoInfo::BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); }
__int64 VideoInfo::AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; }
Baked ********************/


Again from v2.6 Interface.cpp

int VideoInfo::BMPSize() const {
if (!IsY8() && IsPlanar()) {
// Y plane
const int Ybytes = ((RowSize(PLANAR_Y)+3) & ~3) * height;
const int UVbytes = Ybytes >> (GetPlaneWidthSubsampling(PLANAR_U)+GetPlaneHeightSubsampling(PLANAR_U));
return Ybytes + UVbytes*2;
}
return height * ((RowSize()+3) & ~3);
}


EDIT: A bit more from Interface.cpp

int VideoInfo::RowSize(int plane) const {
const int rowsize = BytesFromPixels(width);

switch (plane) {
case PLANAR_U: case PLANAR_V:
return (!IsY8() && IsPlanar()) ? rowsize>>GetPlaneWidthSubsampling(plane) : 0;

case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED:
return (!IsY8() && IsPlanar()) ? ((rowsize>>GetPlaneWidthSubsampling(plane))+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) : 0; // Aligned rowsize

case PLANAR_Y_ALIGNED:
return (rowsize+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize
}
return rowsize;
}

...

int VideoInfo::GetPlaneWidthSubsampling(int plane) const { // Subsampling in bitshifts!
if (plane == PLANAR_Y) // No subsampling
return 0;
if (IsY8())
throw AvisynthError("Filter error: GetPlaneWidthSubsampling not available on Y8 pixel type.");
if (plane == PLANAR_U || plane == PLANAR_V) {
if (IsYUY2())
return 1;
else if (IsPlanar())
return ((pixel_type>>CS_Shift_Sub_Width)+1) & 3;
else
throw AvisynthError("Filter error: GetPlaneWidthSubsampling called with unsupported pixel type.");
}
throw AvisynthError("Filter error: GetPlaneWidthSubsampling called with unsupported plane.");
}

...

int VideoInfo::GetPlaneHeightSubsampling(int plane) const { // Subsampling in bitshifts!
if (plane == PLANAR_Y) // No subsampling
return 0;
if (IsY8())
throw AvisynthError("Filter error: GetPlaneHeightSubsampling not available on Y8 pixel type.");
if (plane == PLANAR_U || plane == PLANAR_V) {
if (IsYUY2())
return 0;
else if (IsPlanar())
return ((pixel_type>>CS_Shift_Sub_Height)+1) & 3;
else
throw AvisynthError("Filter error: GetPlaneHeightSubsampling called with unsupported pixel type.");
}
throw AvisynthError("Filter error: GetPlaneHeightSubsampling called with supported plane.");
}


EDIT: Its not usually necessary to know the full size of frame, frame could be cropped in-situ.
Also note, pitch can change at every frame due to eg crop and interleave.

jpsdr
1st September 2015, 15:00
Ok, thanks.