Log in

View Full Version : InvertComponentsPlanar


MysteryX
31st January 2017, 17:05
I want to write a function that inverts the components of a clip: RGBA to ABGR.

With planar data, there's nothing easier. I can simply copy A into R, B into G, G into B and R into A.

Or...

Can I simply change the plane references without copying any data? How would that be done in C++?

TheFluff
31st January 2017, 18:57
uuuh

If the planes are the same size you literally just swap the pointers. You do understand what a pointer is, do you? Or are you asking for help on how to use the assignment operator?

MysteryX
31st January 2017, 20:42
Of course I know what a pointer is. I'm writing the code right now... I basically want to convert planar YUV data into planar RGB format without modifying the data itself; only changing the VideoInfo.

I must call env->NewVideoFrame to apply the new VideoInfo, so I don't think there's any way to avoid copying the data. NewVideoFrame gives me GetWritePtr. There is no such thing as SetWritePtr.

So, BitBlt each plane it is.

MysteryX
31st January 2017, 21:42
Damn this is not my day. I'm trying a simple BitBlt on planar data and can't get it to work. Also I'm mixing 2 things. One is I want to change pixel type info without changing the data, then I want to reverse components order in another simple filter.

Why is this not working to copy planar data? It works for a bunch of frames until it crashes with Access Violation. Must be something terribly simple because I can't see.

PVideoFrame __stdcall CopyYuvToRgbPlanar::GetFrame(int n, IScriptEnvironment* env) {
PVideoFrame src = child->GetFrame(n, env);
PVideoFrame dst = env->NewVideoFrame(vi, 32);
env->BitBlt(dst->GetWritePtr(PLANAR_Y), dst->GetPitch(PLANAR_Y), src->GetWritePtr(PLANAR_Y), src->GetPitch(PLANAR_Y), dst->GetRowSize(PLANAR_Y), dst->GetHeight(PLANAR_Y));
// env->BitBlt(dst->GetWritePtr(PLANAR_U), dst->GetPitch(PLANAR_U), src->GetWritePtr(PLANAR_U), src->GetPitch(PLANAR_U), dst->GetRowSize(PLANAR_U), dst->GetHeight(PLANAR_U));
// env->BitBlt(dst->GetWritePtr(PLANAR_V), dst->GetPitch(PLANAR_V), src->GetWritePtr(PLANAR_V), src->GetPitch(PLANAR_V), dst->GetRowSize(PLANAR_V), dst->GetHeight(PLANAR_V));
return dst;
}


This code works on RGB24 or RGB32 data, but crashes with YV12 or YV24 data.

pinterf
31st January 2017, 22:12
Damn this is not my day. I'm trying a simple BitBlt on planar data and can't get it to work. Also I'm mixing 2 things. One is I want to change pixel type info without changing the data, then I want to reverse components order in another simple filter.

Why is this not working to copy planar data? It works for a bunch of frames until it crashes with Access Violation. Must be something terribly simple because I can't see.

PVideoFrame __stdcall CopyYuvToRgbPlanar::GetFrame(int n, IScriptEnvironment* env) {
PVideoFrame src = child->GetFrame(n, env);
PVideoFrame dst = env->NewVideoFrame(vi, 32);
env->BitBlt(dst->GetWritePtr(PLANAR_Y), dst->GetPitch(PLANAR_Y), src->GetWritePtr(PLANAR_Y), src->GetPitch(PLANAR_Y), dst->GetRowSize(PLANAR_Y), dst->GetHeight(PLANAR_Y));
// env->BitBlt(dst->GetWritePtr(PLANAR_U), dst->GetPitch(PLANAR_U), src->GetWritePtr(PLANAR_U), src->GetPitch(PLANAR_U), dst->GetRowSize(PLANAR_U), dst->GetHeight(PLANAR_U));
// env->BitBlt(dst->GetWritePtr(PLANAR_V), dst->GetPitch(PLANAR_V), src->GetWritePtr(PLANAR_V), src->GetPitch(PLANAR_V), dst->GetRowSize(PLANAR_V), dst->GetHeight(PLANAR_V));
return dst;
}


This code works on RGB24 or RGB32 data, but crashes with YV12 or YV24 data.
src->GetWritePtr? Try GetReadPtr instead.

MysteryX
31st January 2017, 22:29
src->GetWritePtr? Try GetReadPtr instead.
That helps :D

pinterf
31st January 2017, 22:35
[QUOTE=MysteryX;1795420]Of course I know what a pointer is. I'm writing the code right now... I basically want to convert planar YUV data into planar RGB format without modifying the data itself; only changing the VideoInfo.

I must call env->NewVideoFrame to apply the new VideoInfo, so I don't think there's any way to avoid copying the data. NewVideoFrame gives me GetWritePtr. There is no such thing as SetWritePtr.

So, BitBlt each plane it is. [\QUOTE]
In AVS+ planar RGB uses the same plane variables internally as YUV. Usually the order is Y,U,V,A and G,B,R,A, but you don't need to bother with it.

For reading and writing, and getting plane properties, the filter authors are kindly asked to use PLANAR_G, PLANAR_B, PLANAR_R constants for getting plane data, these constants can appear anywhere where PLANAR_Y/U/V was used before.
And now you have PLANAR_A for alpha plane.

Subframe hacking:
SwapUV for example simply changes the plane pointers with a SubFrame call. No BitBlt.
The comment says in the source: "very naughty - don't do this at home!!".
Look at the source of SwapUVToY::GetFrame in planeswap.cpp to learn easy plane swapping.

SubframePlanar is a regular interface method, unfortunately I could not put SubframePlanarA (alpha aware SubframePlanar) to the regular IScriptEnvironment interface (compatibility again!), but now it appears in IScriptEnvironment2. (I have put it there lately).

For more hacking with subframes, check code in Avisynth+ source, field.cpp:
SeparateRows::GetFrame

TheFluff
31st January 2017, 22:40
While I'm completely baffled as to why you actually want to do this, I'm preeeeetty sure you can still do it without a copy by abusing env->Subframe(). VideoInfo is a property of the clip, not of the VFB - the VFB has no notion of what data it's holding (for efficiency reasons - VFB's can be recycled). It has been proven in the past* that Subframe (perhaps unintentionally) allows negative offsets, and since Avisynth's framebuffer is really one big buffer for the entire frame rather than separate buffers for each plane, that's all you need to replicate the behavior of VapourSynth's ShufflePlanes.

* In that absolutely braindamaged "let's optimize flipvertical" thread. Turns out you can set negative pitch using subframe().

edit: pinterf got there first and with more info to boot

MysteryX
31st January 2017, 23:22
args... in this line of absolutely stupid stuff not working...

This works

AVSValue __cdecl Create_GetFormat(AVSValue args, void* user_data, IScriptEnvironment* env) {
return AVSValue("Y8");
}


This returns weird data

AVSValue __cdecl Create_GetFormat(AVSValue args, void* user_data, IScriptEnvironment* env) {
return AVSValue((std::string("Y") + std::to_string(8)).c_str());
}


What am I missing again? Sleep, perhaps


What I'm trying to accomplish is to add native high-bit-depth support to AviSynthShader by calling a series of standard functions instead of writing the full operation in assembly.

YUV420 -> YUV444 -> CopyYuvToRgbPlanar -> RGBA -> (ReverseComponents?) -> ConvertToDoubleWidth

TheFluff
31st January 2017, 23:31
If you allocate an array on the stack and keep using the pointer to it after the function returns, you're gonna have a bad time. This is absolutely fundamental in C and C++. AVSValue's constructor doesn't copy strings, so what you need is env->SaveString.

pinterf
31st January 2017, 23:39
What I'm trying to accomplish is to add native high-bit-depth support to AviSynthShader by calling a series of standard functions instead of writing the full operation in assembly.

YUV420 -> YUV444 -> CopyYuvToRgbPlanar -> RGBA -> (ReverseComponents?) -> ConvertToDoubleWidth

If you are using avs+ specific planar rgb in parts of your filter, just use Invoke and call ConvertToPlanarRGB or ConvertToPlanarRGBA with appropriate parameters. I'm using that also in Avisynth+, e.g. in Overlay.cpp or Histogram.cpp, check source, learn and use it.

MysteryX
1st February 2017, 00:31
env->SaveString? Had never seen that function before. Unfortunately there is very little (none) documentation regarding these internal functions.

This should work right? Still missing something...

std::String Result = "YV24";
return new AVSValue(env->SaveString(Result.c_str(), Result.length()));


Pinterf, if I call ConvertToPlanarRGB on a YV24 frame, it will convert YUV into RGB, which I want to avoid. I want to preserve the data as it is and the YUV to RGB conversion will happen on the GPU. I don't see any parameter to do such non-conversion.

feisty2
1st February 2017, 02:18
If you allocate an array on the stack and keep using the pointer to it after the function returns, you're gonna have a bad time. This is absolutely fundamental in C and C++. AVSValue's constructor doesn't copy strings, so what you need is env->SaveString.

Edit: my bad, misread the passage..:p

TheFluff
1st February 2017, 02:54
Unfortunately there is very little (none) documentation regarding these internal functions.
Unfortunately I have to inform you that you are either illiterate, incapable of using a search engine, or both.

http://avisynth.nl/index.php/Filter_SDK/Cplusplus_API#SaveString

I mean, really now. It's right there in the public API in avisynth.h, it's been there since forever, it's documented in the filter SDK, there's dozens of posts discussing it on this very forum that pop if you google for it and yet here you are, going "hurr durr undocumented internal function".


This should work right? Still missing something...

std::String Result = "YV24";
return new AVSValue(env->SaveString(Result.c_str(), Result.length()));


The .length() of a std::string is the length of the string in bytes. What is the thing you must always remember when allocating memory for C strings?

THE NULL TERMINATOR, THAT'S WHAT

(you don't even need to pass a length to SaveString unless you explicitly want to allocate a larger buffer for later use)

also, are you sure you want to allocate that avsvalue on the heap?
(you almost certainly don't, return by value instead)

MysteryX
1st February 2017, 03:09
2 errors in 1 line, wow, I impress myself. Almost makes me wonder how I wrote fully working DirectX code.

I've never seen that documentation link, and it would have been very useful if I saw it before! That page doesn't come up in Google when searching "avisynth bitblt".

TheFluff, your tone is lot more useful when my posts are dumb :) somehow

Meanwhile, I wrote a 432hz Audio Player and playlist manager in a few hours. Been more successful at that. I'll keep it playing all night while I get some good rest.

Gavino
1st February 2017, 10:25
I've never seen that documentation link, and it would have been very useful if I saw it before!
There is also documentation installed on your hard disk in C:\Program Files\AviSynth 2.5\FilterSDK when you install the SDK (see EnvSaveString.htm).