// FrameMap 0.2 + PDecimate 0.1 // Copyright 2004 Carl Ritson // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA, or visit // http://www.gnu.org/copyleft/gpl.html . #include "windows.h" #include "avisynth.h" #include // FrameMap class FrameMap : public GenericVideoFilter { public: FrameMap(int *_frames, int _no_frames, bool setfps, PClip _child, IScriptEnvironment* env); ~FrameMap(); PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); bool __stdcall GetParity(int n); private: int *frames; int no_frames; }; FrameMap::FrameMap(int *_frames, int _no_frames, bool setfps, PClip _child, IScriptEnvironment* env) : GenericVideoFilter(_child) { frames = _frames; no_frames = _no_frames; if(setfps) { VideoInfo cvi = _child->GetVideoInfo(); double n = (((double)cvi.fps_numerator) / ((double)cvi.fps_denominator)); int d = 1; n *= ((double)no_frames) / ((double)vi.num_frames); while (n < 16777216 && d < 16777216) { n*=2; d*=2; } //d *= int((((double)vi.num_frames) / ((double)no_frames))+0.5); vi.SetFPS((unsigned)n,(unsigned)d); } vi.num_frames = no_frames; } FrameMap::~FrameMap() { if(frames) delete frames; } PVideoFrame __stdcall FrameMap::GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(frames[n], env); } bool __stdcall FrameMap::GetParity(int n) { return child->GetParity(frames[n]); } // DLL Handles AVSValue __cdecl Create_FrameMap(AVSValue args, void*, IScriptEnvironment* env) { FILE *fh; int i,*frames,no_frames; fh = fopen(args[1].AsString(""),"r"); if(fh == NULL) env->ThrowError("FrameMap: unable to open file"); if(fscanf(fh,"%d\n\n",&no_frames) < 1 || no_frames <= 0) env->ThrowError("FrameMap: error reading map file"); frames = new int[no_frames]; for(i = 0; i < no_frames; ++i) frames[i] = 0; for(i = 0; i < no_frames; ++i) { int ptr = 0, val = 0; if(fscanf(fh,"%d\t%d\n",&ptr,&val) < 2 || ptr < 0 || val < 0 || ptr >= no_frames) { //|| val >= vi.num_frames) { env->ThrowError("FrameMap: invalid map file"); } frames[ptr] = val; } fclose(fh); return new FrameMap(frames, no_frames, false, args[0].AsClip(), env); } AVSValue __cdecl Create_PDecimate(AVSValue args, void*, IScriptEnvironment* env) { PClip clip = args[0].AsClip(); VideoInfo vi = clip->GetVideoInfo(); const char *pattern = args[1].AsString(""); int plength = strlen(pattern); if(plength == 0) env->ThrowError("PDecimate: invalid pattern (length = 0)"); int no_frames; int *frames; int i, fi, pi, nx = 0, no = 0; for(i = 0; i < plength; ++i) { switch(tolower(pattern[i])) { case 'x': nx++; break; case 'o': no++; break; default: env->ThrowError("PDecimate: invalid pattern (bad character, must be 'x' or 'o')"); } } if(nx == 0) env->ThrowError("PDecimate: invalid pattern (must have at least 1 'x')"); frames = new int[((vi.num_frames / plength) * nx) + plength]; // slack in the allocation for(fi = 0, pi = 0, no_frames = 0; fi < vi.num_frames; ++fi, ++pi) { if(pi >= plength) pi = 0; if(tolower(pattern[pi]) == 'x') frames[no_frames++] = fi; } return new FrameMap(frames, no_frames, true, clip, env); } extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) { env->AddFunction("FrameMap", "cs", Create_FrameMap, 0); env->AddFunction("PDecimate", "cs", Create_PDecimate, 0); return "FrameMap filter"; }