View Full Version : How to "recursively" affect frames?
Dark Shikari
7th October 2007, 04:47
I am trying to write a filter for Avisynth that works in the following fashion:
Frame 1: Does nothing.
Frame 2: Modifies frame 2 based on frame 1.
Frame 3: Modifies frame 3 based on the modified frame 2.
Frame 4: Modifies frame 4 based on the modified frame 3.
etc
Obviously for practical operation it would require being run in sequence.
How would I do this?
neuron2
7th October 2007, 05:11
Save a copy of the modified previous frame and use it for the next frame, then ditch it.
Dark Shikari
7th October 2007, 05:14
Save a copy of the modified previous frame and use it for the next frame, then ditch it.How about keeping a single array storing the values of the previous frame, and overwriting them each time, to avoid repetitive mallocs?
neuron2
7th October 2007, 05:27
Sure, you can do that. The overhead of a malloc is pretty small, though, compared to processing a frame.
Dark Shikari
7th October 2007, 05:32
Another question: why doesn't this work?
*PreviousFrame = malloc(src_width*src_height*sizeof(int));
1>.\Main.cpp(121) : error C2440: '=' : cannot convert from 'void *' to 'int'
1> There is no context in which this conversion is possible
I didn't have to do anything when my code was in c, in x264:
int *array=x264_malloc(h->param.i_height * h->param.i_width * sizeof(int));
Why won't this work in C++?
squid_80
7th October 2007, 05:34
If you're doing this inside a filter, just use a PVideoFrame variable (that has scope larger than the getframe call) and assign it the frame you want to keep. Then it'll still be there when you want to use it.
Dark Shikari
7th October 2007, 05:37
If you're doing this inside a filter, just use a PVideoFrame variable (that has scope larger than the getframe call) and assign it the frame you want to keep. Then it'll still be there when you want to use it.OK, but I still need the same syntax for another part of my code, which keeps an array of data from previous frames' processing for the algorithm to use:
*FrameTracker = malloc(src_width*src_height*sizeof(int));
squid_80
7th October 2007, 05:37
Another question: why doesn't this work?
*PreviousFrame = malloc(src_width*src_height*sizeof(int));
1>.\Main.cpp(121) : error C2440: '=' : cannot convert from 'void *' to 'int'
1> There is no context in which this conversion is possible
I didn't have to do anything when my code was in c, in x264:
int *array=x264_malloc(h->param.i_height * h->param.i_width * sizeof(int));
Why won't this work in C++?
C++ won't automatically cast. Are you sure PreviousFrame should be dereferenced here? At a guess I'd say this is what you want:
PreviousFrame = (int*)malloc(src_width*src_height*sizeof(int));
...But I still think my idea is better. If you give me a bit more code to work with (just blank out the processing bit if you want it secret) I could give an example.
Dark Shikari
7th October 2007, 05:45
C++ won't automatically cast. Are you sure PreviousFrame should be dereferenced here? At a guess I'd say this is what you want:
PreviousFrame = (int*)malloc(src_width*src_height*sizeof(int));
...But I still think my idea is better. If you give me a bit more code to work with (just blank out the processing bit if you want it secret) I could give an example.
Here's the first-frame initialization code:
if(FrameNumber == 0)
{
*PreviousFrame = malloc(src_width*src_height*sizeof(int));
*FrameTracker = malloc(src_width*src_height*sizeof(int));
for (h=0; h < src_height;h++)
{
for (w = 0; w < src_width; w++)
PreviousFrame[w + src_width * h] = *(srcp + w);
srcp = srcp + src_pitch;
}
for (h=0; h < src_height;h++)
for (w = 0; w < src_width; w++)
FrameTracker[w + src_width * h] = 0;
srcp = src->GetReadPtr();
dstp = dst->GetWritePtr();
for (h=0; h < src_height;h++)
{
for (w = 0; w < src_width; w++)
*(dstp + w) = *(srcp + w);
srcp = srcp + src_pitch;
dstp = dstp + dst_pitch;
}
}
In other words, in the second frame, the previous frame is the unprocessed first frame. Later on, however, the "previous frame" has to be the processed previous frame.
Dark Shikari
7th October 2007, 05:50
Another question: In x264, I used this:
uint8_t *curframe_block = &fenc->plane[0][x+y*fenc->i_stride[0]];
uint8_t *prevframe_block = &prevframe->plane[0][x+y*fenc->i_stride[0]];
to create pointers to the current macroblock of the current and previous frame. Can I do this with Avisynth? What type do I declare them to be, since C++ seems to have no uint8_t?
(Also, come on #avisynth IRC channel, on freenode--your help will be appreciated :) )
IanB
7th October 2007, 06:50
Are you sure PreviousFrame should be dereferenced here?Your usage of PreviousFrame is inconsitant, how have you declared it*PreviousFrame = malloc(src_width*src_height*sizeof(int));
...
PreviousFrame[w + src_width * h] = *(srcp + w);in the 1st case I would expect it to be an int** in the 2nd case an int* :confused:
Dark Shikari
7th October 2007, 06:57
Your usage of PreviousFrame is inconsitant, how have you declared it*PreviousFrame = malloc(src_width*src_height*sizeof(int));
...
PreviousFrame[w + src_width * h] = *(srcp + w);in the 1st case I would expect it to be an int** in the 2nd case an int* :confused:
Yeah, I fixed that up, problem solved.
The filter actually works now--I just have to work on error handling to deal with unsupported color spaces/etc--I can't seem to find any documentation on that?
neuron2
7th October 2007, 07:00
Put something like this in your constructor:
if (!vi.IsYUY2() && !vi.IsYV12())
env->ThrowError("Telecide: YUY2 or YV12 data only");
Refer to avisynth.h for vi member functions.
Instead of uint8_t, use unsigned char, or make a typedef of your own for it:
typedef unsigned char uint8_t;
Dark Shikari
7th October 2007, 07:09
Thanks, working on the error handling.
Some other issues:
1. I want to check my mallocs, but c++ doesn't have an identifier called "null"--what do I do for == null? Edit: nevermind, NULL seems to work.
2. How do I deallocate my memory? free(ptr)?
3. What licensing requirements are there for an Avisynth filter? I assume it doesn't have to be GPL, given the exception given in the license--but what requirements are there?
4. How do I make certain parameter values default if not specified? Edit: Found this, thanks anyways.
neuron2
7th October 2007, 07:28
2. if (ptr) free(ptr);
3. If all you do is include avisynth.h, there are no requirements. Ben made an exception for that.
4. As Ben writes in http://neuron2.net/www.math.berkeley.edu/benrg/avisynth-extensions.html:
"For convenience, AVSValue offers a set of As...() functions which take default values. See avisynth.h."
This example sets defaults of 0 and 7 for mode and threshold, respectively:
AVSValue __cdecl Create_AutoYUY2(AVSValue args, void* user_data, IScriptEnvironment* env)
{
return new AutoYUY2(args[0].AsClip(), args[1].AsInt(0), args[2].AsInt(7), env);
}
extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
{
env->AddFunction("AutoYUY2", "c[mode]i[threshold]i", Create_AutoYUY2, 0);
return 0;
}
Dark Shikari
7th October 2007, 09:21
Filter is done (http://forum.doom9.org/showthread.php?t=130611).
squid_80
7th October 2007, 15:37
if(FrameNumber == 0)
{
*PreviousFrame = malloc(src_width*src_height*sizeof(int));
*FrameTracker = malloc(src_width*src_height*sizeof(int));
for (h=0; h < src_height;h++)
{
for (w = 0; w < src_width; w++)
PreviousFrame[w + src_width * h] = *(srcp + w);
srcp = srcp + src_pitch;
}
for (h=0; h < src_height;h++)
for (w = 0; w < src_width; w++)
FrameTracker[w + src_width * h] = 0;
srcp = src->GetReadPtr();
dstp = dst->GetWritePtr();
for (h=0; h < src_height;h++)
{
for (w = 0; w < src_width; w++)
*(dstp + w) = *(srcp + w);
srcp = srcp + src_pitch;
dstp = dstp + dst_pitch;
}
}
Let's try something else:
/*
* assume these are declared/defined earlier:
PVideoFrame PreviousFrame;
PVideoFrame FrameTracker = env->NewVideoFrame(vi);
int lastframe = -1;
*/
if(FrameNumber == 0)
{
// the lazy way
memset(FrameTracker->GetWritePtr(PLANAR_Y), 0, FrameTracker->GetPitch(PLANAR_Y)*vi.height);
memset(FrameTracker->GetWritePtr(PLANAR_U), 0, FrameTracker->GetPitch(PLANAR_U)*vi.height/2);
memset(FrameTracker->GetWritePtr(PLANAR_V), 0, FrameTracker->GetPitch(PLANAR_V)*vi.height/2);
PreviousFrame = srcp;
lastframe = 0;
return srcp;
}
else
{
if (FrameNumber-1 != lastframe) {
/* Frames haven't been accessed in sequential order! *
* Recurse backwards *
* (You'd probably not want to do this) */
GetFrame(FrameNumber-1, env);
}
/* do processing here and put the new frame in dstp */
lastframe = FrameNumber;
PreviousFrame = dstp;
return dstp;
}
/* Put in destructor:
* PreviousFrame = NULL;
* FrameTracker = NULL;
*/
stickboy
15th October 2007, 08:39
2. if (ptr) free(ptr);Just:
free(ptr)is fine. Calling free() on NULL is guaranteed by the C standard to be safe.
vBulletin® v3.8.5, Copyright ©2000-2012, Jelsoft Enterprises Ltd.