SansGrip
12th November 2002, 06:59
First off I apologise for using the b**t word in the subject ;).
I'm about halfway through my first "proper" port to YV12 and wondered if I was the only one having problems working out a "canonical" GetFrame structure. We all know that
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < row_size; ++x)
and so on is often the "best" way to loop over YUY2 data. Is there an equivalent for YV12? Of course for simple stuff like Invert the two-consecutive-loops approach (one loop for luma, one for chroma) is probably the nicest way of doing it, but this seems to break down with more complex algorithms.
What I've come up with so far (since I need to process all components jointly) is something like this:
const unsigned char* py = frame->GetReadPtr(PLANAR_Y),
ppy = py + pitch_y;
const int pitch_y_2 = pitch_y * 2;
// etc.
unsigned char* dpy = dest->GetWritePtr(PLANAR_Y),
dppy = dpy + dpitch_y;
const int dpitch_y_2 = dpitch_y * 2;
// etc.
for(int y = 0; y < height_uv; ++y)
{
for(int x = 0; i < row_size_uv; ++x)
{
int yx = x << 1;
// Here py[yx], py[yx + 1], ppy[yx],
// ppy[yx + 1], pu[x] and pv[x] are
// magically transformed into new_y1_1,
// new_y2_1, new_y1_2, new_y2_2, new_u and
// new_v respectively
dpy[yx] = new_y1_1;
dpy[yx + 1] = new_y2_1;
dppy[yx] = new_y1_2;
dppy[yx + 1] = new_y1_2;
dpu[x] = new_u;
dpv[x] = new_v;
}
py += pitch_y_2;
ppy += pitch_y_2;
dpy += dpitch_y_2;
dppy += dpitch_y_2;
pu += pitch_uv;
pv += pitch_uv;
dpu += dpitch_uv;
dpv += dpitch_uv;
}
Does this look okay, or is it merely the product of a deranged mind? That's a terrifying number of pointers to maintain...
As I was working all this out it occurred to me that while there was an awful lot of code repetition (and related bugs, e.g. the old using-the-wrong-pitch snafu) writing for 2.0, there's even more with 2.5. I've already fixed two bugs involving switched pitch_y and pitch_uv, which are real easy to mix up if you've been staring at the screen for hours.
To this end I started considering an STL-esque class library for Avisynth filters. By maximizing inlined code and (unfortunately) avoiding polymorphism, etc., it should be possible to maintain performance while dramatically easing code readability and simplifying maintenance. It would also have the virtue of reducing the number of typo bugs because, well, there'd be less typing ;). What's more, judicious use of assert()s would catch buffer overruns first time, every time. Stupid idea? If it is, it's an appealing stupid idea :D.
Anyway, as to the second part of my question: Are there any "best practices" for 2.5 in general? My understanding is that temporal filters should always call SetCacheHints, and that IsYUV() no longer means IsYUY2(), but is there anything other than that? How about the idea of a function to return filter information such as version number? I think it would be very useful.
Note to mods: I considered putting this in the development section but it seemed more pertinent to this one. Feel free to move it there (or merge with another 2.5-related thread) if you think it better.
Thanks for listening :).
I'm about halfway through my first "proper" port to YV12 and wondered if I was the only one having problems working out a "canonical" GetFrame structure. We all know that
for(int y = 0; y < height; ++y)
{
for(int x = 0; x < row_size; ++x)
and so on is often the "best" way to loop over YUY2 data. Is there an equivalent for YV12? Of course for simple stuff like Invert the two-consecutive-loops approach (one loop for luma, one for chroma) is probably the nicest way of doing it, but this seems to break down with more complex algorithms.
What I've come up with so far (since I need to process all components jointly) is something like this:
const unsigned char* py = frame->GetReadPtr(PLANAR_Y),
ppy = py + pitch_y;
const int pitch_y_2 = pitch_y * 2;
// etc.
unsigned char* dpy = dest->GetWritePtr(PLANAR_Y),
dppy = dpy + dpitch_y;
const int dpitch_y_2 = dpitch_y * 2;
// etc.
for(int y = 0; y < height_uv; ++y)
{
for(int x = 0; i < row_size_uv; ++x)
{
int yx = x << 1;
// Here py[yx], py[yx + 1], ppy[yx],
// ppy[yx + 1], pu[x] and pv[x] are
// magically transformed into new_y1_1,
// new_y2_1, new_y1_2, new_y2_2, new_u and
// new_v respectively
dpy[yx] = new_y1_1;
dpy[yx + 1] = new_y2_1;
dppy[yx] = new_y1_2;
dppy[yx + 1] = new_y1_2;
dpu[x] = new_u;
dpv[x] = new_v;
}
py += pitch_y_2;
ppy += pitch_y_2;
dpy += dpitch_y_2;
dppy += dpitch_y_2;
pu += pitch_uv;
pv += pitch_uv;
dpu += dpitch_uv;
dpv += dpitch_uv;
}
Does this look okay, or is it merely the product of a deranged mind? That's a terrifying number of pointers to maintain...
As I was working all this out it occurred to me that while there was an awful lot of code repetition (and related bugs, e.g. the old using-the-wrong-pitch snafu) writing for 2.0, there's even more with 2.5. I've already fixed two bugs involving switched pitch_y and pitch_uv, which are real easy to mix up if you've been staring at the screen for hours.
To this end I started considering an STL-esque class library for Avisynth filters. By maximizing inlined code and (unfortunately) avoiding polymorphism, etc., it should be possible to maintain performance while dramatically easing code readability and simplifying maintenance. It would also have the virtue of reducing the number of typo bugs because, well, there'd be less typing ;). What's more, judicious use of assert()s would catch buffer overruns first time, every time. Stupid idea? If it is, it's an appealing stupid idea :D.
Anyway, as to the second part of my question: Are there any "best practices" for 2.5 in general? My understanding is that temporal filters should always call SetCacheHints, and that IsYUV() no longer means IsYUY2(), but is there anything other than that? How about the idea of a function to return filter information such as version number? I think it would be very useful.
Note to mods: I considered putting this in the development section but it seemed more pertinent to this one. Feel free to move it there (or merge with another 2.5-related thread) if you think it better.
Thanks for listening :).