diff --git a/avisynth_prs/avisynth.h b/avisynth_prs/avisynth.h new file mode 100644 index 000000000..b1e68deb4 --- /dev/null +++ b/avisynth_prs/avisynth.h @@ -0,0 +1,749 @@ +// Avisynth v2.5. Copyright 2002 Ben Rudiak-Gould et al. +// http://www.avisynth.org + +// 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 . +// +// Linking Avisynth statically or dynamically with other modules is making a +// combined work based on Avisynth. Thus, the terms and conditions of the GNU +// General Public License cover the whole combination. +// +// As a special exception, the copyright holders of Avisynth give you +// permission to link Avisynth with independent modules that communicate with +// Avisynth solely through the interfaces defined in avisynth.h, regardless of the license +// terms of these independent modules, and to copy and distribute the +// resulting combined work under terms of your choice, provided that +// every copy of the combined work is accompanied by a complete copy of +// the source code of Avisynth (the version of Avisynth used to produce the +// combined work), being distributed under the terms of the GNU General +// Public License plus this exception. An independent module is a module +// which is not derived from or based on Avisynth, such as 3rd-party filters, +// import and export plugins, or graphical user interfaces. + + + + + +#ifndef __AVISYNTH_H__ +#define __AVISYNTH_H__ + +enum { AVISYNTH_INTERFACE_VERSION = 3 }; + + +/* Define all types necessary for interfacing with avisynth.dll + Moved from internal.h */ + +// Win32 API macros, notably the types BYTE, DWORD, ULONG, etc. +#include + +// COM interface macros +#include + + +// Raster types used by VirtualDub & Avisynth +#define in64 (__int64)(unsigned short) +typedef unsigned long Pixel; // this will break on 64-bit machines! +typedef unsigned long Pixel32; +typedef unsigned char Pixel8; +typedef long PixCoord; +typedef long PixDim; +typedef long PixOffset; + + +/* Compiler-specific crap */ + +// Tell MSVC to stop precompiling here +#ifdef _MSC_VER + #pragma hdrstop +#endif + +// Set up debugging macros for MS compilers; for others, step down to the +// standard interface +#ifdef _MSC_VER + #include +#else + #define _RPT0(a,b) ((void)0) + #define _RPT1(a,b,c) ((void)0) + #define _RPT2(a,b,c,d) ((void)0) + #define _RPT3(a,b,c,d,e) ((void)0) + #define _RPT4(a,b,c,d,e,f) ((void)0) + + #define _ASSERTE(x) assert(x) + #include +#endif + + + +// I had problems with Premiere wanting 1-byte alignment for its structures, +// so I now set the Avisynth struct alignment explicitly here. +#pragma pack(push,8) + +#define FRAME_ALIGN 16 +// Default frame alignment is 16 bytes, to help P4, when using SSE2 + +// The VideoInfo struct holds global information about a clip (i.e. +// information that does not depend on the frame number). The GetVideoInfo +// method in IClip returns this struct. + +// Audio Sample information +typedef float SFLOAT; + +enum {SAMPLE_INT8 = 1<<0, + SAMPLE_INT16 = 1<<1, + SAMPLE_INT24 = 1<<2, // Int24 is a very stupid thing to code, but it's supported by some hardware. + SAMPLE_INT32 = 1<<3, + SAMPLE_FLOAT = 1<<4}; + +enum { + PLANAR_Y=1<<0, + PLANAR_U=1<<1, + PLANAR_V=1<<2, + PLANAR_ALIGNED=1<<3, + PLANAR_Y_ALIGNED=PLANAR_Y|PLANAR_ALIGNED, + PLANAR_U_ALIGNED=PLANAR_U|PLANAR_ALIGNED, + PLANAR_V_ALIGNED=PLANAR_V|PLANAR_ALIGNED, + }; + +struct VideoInfo { + int width, height; // width=0 means no video + unsigned fps_numerator, fps_denominator; + int num_frames; + // This is more extensible than previous versions. More properties can be added seeminglesly. + + // Colorspace properties. + enum { + CS_BGR = 1<<28, + CS_YUV = 1<<29, + CS_INTERLEAVED = 1<<30, + CS_PLANAR = 1<<31 + }; + + // Specific colorformats + enum { CS_UNKNOWN = 0, + CS_BGR24 = 1<<0 | CS_BGR | CS_INTERLEAVED, + CS_BGR32 = 1<<1 | CS_BGR | CS_INTERLEAVED, + CS_YUY2 = 1<<2 | CS_YUV | CS_INTERLEAVED, + CS_YV12 = 1<<3 | CS_YUV | CS_PLANAR, // y-v-u, planar + CS_I420 = 1<<4 | CS_YUV | CS_PLANAR, // y-u-v, planar + CS_IYUV = 1<<4 | CS_YUV | CS_PLANAR // same as above + }; + int pixel_type; // changed to int as of 2.5 + + + int audio_samples_per_second; // 0 means no audio + int sample_type; // as of 2.5 + __int64 num_audio_samples; // changed as of 2.5 + int nchannels; // as of 2.5 + + // Imagetype properties + + int image_type; + + enum { + IT_BFF = 1<<0, + IT_TFF = 1<<1, + IT_FIELDBASED = 1<<2 + }; + + // useful functions of the above + bool HasVideo() const { return (width!=0); } + bool HasAudio() const { return (audio_samples_per_second!=0); } + bool IsRGB() const { return !!(pixel_type&CS_BGR); } + bool IsRGB24() const { return (pixel_type&CS_BGR24)==CS_BGR24; } // Clear out additional properties + bool IsRGB32() const { return (pixel_type & CS_BGR32) == CS_BGR32 ; } + bool IsYUV() const { return !!(pixel_type&CS_YUV ); } + bool IsYUY2() const { return (pixel_type & CS_YUY2) == CS_YUY2; } + bool IsYV12() const { return ((pixel_type & CS_YV12) == CS_YV12)||((pixel_type & CS_I420) == CS_I420); } + bool IsColorSpace(int c_space) const { return ((pixel_type & c_space) == c_space); } + bool Is(int property) const { return ((pixel_type & property)==property ); } + bool IsPlanar() const { return !!(pixel_type & CS_PLANAR); } + bool IsFieldBased() const { return !!(image_type & IT_FIELDBASED); } + bool IsParityKnown() const { return ((image_type & IT_FIELDBASED)&&(image_type & (IT_BFF|IT_TFF))); } + bool IsBFF() const { return !!(image_type & IT_BFF); } + bool IsTFF() const { return !!(image_type & IT_TFF); } + + bool IsVPlaneFirst() const {return ((pixel_type & CS_YV12) == CS_YV12); } // Don't use this + int BytesFromPixels(int pixels) const { return pixels * (BitsPerPixel()>>3); } // Will not work on planar images, but will return only luma planes + int RowSize() const { return BytesFromPixels(width); } // Also only returns first plane on planar images + int BMPSize() const { if (IsPlanar()) {int p = height * ((RowSize()+3) & ~3); p+=p>>1; return p; } return height * ((RowSize()+3) & ~3); } + __int64 AudioSamplesFromFrames(__int64 frames) const { return (fps_numerator && HasVideo()) ? ((__int64)(frames) * audio_samples_per_second * fps_denominator / fps_numerator) : 0; } + int FramesFromAudioSamples(__int64 samples) const { return (fps_denominator && HasAudio()) ? (int)((samples * (__int64)fps_numerator)/((__int64)fps_denominator * (__int64)audio_samples_per_second)) : 0; } + __int64 AudioSamplesFromBytes(__int64 bytes) const { return HasAudio() ? bytes / BytesPerAudioSample() : 0; } + __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); } + int AudioChannels() const { return nchannels; } + int SampleType() const{ return sample_type;} + bool IsSampleType(int testtype) const{ return !!(sample_type&testtype);} + int SamplesPerSecond() const { return audio_samples_per_second; } + int BytesPerAudioSample() const { return nchannels*BytesPerChannelSample();} + void SetFieldBased(bool isfieldbased) { if (isfieldbased) image_type|=IT_FIELDBASED; else image_type&=~IT_FIELDBASED; } + void Set(int property) { image_type|=property; } + void Clear(int property) { image_type&=~property; } + + int BitsPerPixel() const { + switch (pixel_type) { + case CS_BGR24: + return 24; + case CS_BGR32: + return 32; + case CS_YUY2: + return 16; + case CS_YV12: + case CS_I420: + return 12; + default: + return 0; + } + } + int BytesPerChannelSample() const { + switch (sample_type) { + case SAMPLE_INT8: + return sizeof(signed char); + case SAMPLE_INT16: + return sizeof(signed short); + case SAMPLE_INT24: + return 3; + case SAMPLE_INT32: + return sizeof(signed int); + case SAMPLE_FLOAT: + return sizeof(SFLOAT); + default: + _ASSERTE("Sample type not recognized!"); + return 0; + } + } + + // useful mutator + void SetFPS(unsigned numerator, unsigned denominator) { + if ((numerator == 0) || (denominator == 0)) { + fps_numerator = 0; + fps_denominator = 1; + } + else { + unsigned x=numerator, y=denominator; + while (y) { // find gcd + unsigned t = x%y; x = y; y = t; + } + fps_numerator = numerator/x; + fps_denominator = denominator/x; + } + } + + // Range protected multiply-divide of FPS + void MulDivFPS(unsigned multiplier, unsigned divisor) { + unsigned __int64 numerator = UInt32x32To64(fps_numerator, multiplier); + unsigned __int64 denominator = UInt32x32To64(fps_denominator, divisor); + + unsigned __int64 x=numerator, y=denominator; + while (y) { // find gcd + unsigned __int64 t = x%y; x = y; y = t; + } + numerator /= x; // normalize + denominator /= x; + + unsigned __int64 temp = numerator | denominator; // Just looking top bit + unsigned u = 0; + while (temp & 0xffffffff80000000) { // or perhaps > 16777216*2 + temp = Int64ShrlMod32(temp, 1); + u++; + } + if (u) { // Scale to fit + const unsigned round = 1 << (u-1); + SetFPS( (unsigned)Int64ShrlMod32(numerator + round, u), + (unsigned)Int64ShrlMod32(denominator + round, u) ); + } + else { + fps_numerator = (unsigned)numerator; + fps_denominator = (unsigned)denominator; + } + } + + // Test for same colorspace + bool IsSameColorspace(const VideoInfo& vi) const { + if (vi.pixel_type == pixel_type) return TRUE; + if (IsYV12() && vi.IsYV12()) return TRUE; + return FALSE; + } + +}; + + + + +// VideoFrameBuffer holds information about a memory block which is used +// for video data. For efficiency, instances of this class are not deleted +// when the refcount reaches zero; instead they're stored in a linked list +// to be reused. The instances are deleted when the corresponding AVS +// file is closed. + +class VideoFrameBuffer { + BYTE* const data; + const int data_size; + // sequence_number is incremented every time the buffer is changed, so + // that stale views can tell they're no longer valid. + long sequence_number; + + friend class VideoFrame; + friend class Cache; + friend class ScriptEnvironment; + long refcount; + +public: + VideoFrameBuffer(int size); + VideoFrameBuffer(); + ~VideoFrameBuffer(); + + const BYTE* GetReadPtr() const { return data; } + BYTE* GetWritePtr() { ++sequence_number; return data; } + int GetDataSize() { return data_size; } + int GetSequenceNumber() { return sequence_number; } + int GetRefcount() { return refcount; } +}; + + +class IClip; +class PClip; +class PVideoFrame; +class IScriptEnvironment; +class AVSValue; + + +// VideoFrame holds a "window" into a VideoFrameBuffer. Operator new +// is overloaded to recycle class instances. + +class VideoFrame { + int refcount; + VideoFrameBuffer* const vfb; + const int offset, pitch, row_size, height, offsetU, offsetV, pitchUV; // U&V offsets are from top of picture. + + friend class PVideoFrame; + void AddRef() { InterlockedIncrement((long *)&refcount); } + void Release() { if (refcount==1) InterlockedDecrement(&vfb->refcount); InterlockedDecrement((long *)&refcount); } + + friend class ScriptEnvironment; + friend class Cache; + + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height); + VideoFrame(VideoFrameBuffer* _vfb, int _offset, int _pitch, int _row_size, int _height, int _offsetU, int _offsetV, int _pitchUV); + + void* operator new(unsigned size); +// TESTME: OFFSET U/V may be switched to what could be expected from AVI standard! +public: + int GetPitch() const { return pitch; } + int GetPitch(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: return pitchUV;} return pitch; } + int GetRowSize() const { return row_size; } + int GetRowSize(int plane) const { + switch (plane) { + case PLANAR_U: case PLANAR_V: if (pitchUV) return row_size>>1; else return 0; + case PLANAR_U_ALIGNED: case PLANAR_V_ALIGNED: + if (pitchUV) { + int r = ((row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)) )>>1; // Aligned rowsize + if (r<=pitchUV) + return r; + return row_size>>1; + } else return 0; + case PLANAR_Y_ALIGNED: + int r = (row_size+FRAME_ALIGN-1)&(~(FRAME_ALIGN-1)); // Aligned rowsize + if (r<=pitch) + return r; + return row_size; + } + return row_size; } + int GetHeight() const { return height; } + int GetHeight(int plane) const { switch (plane) {case PLANAR_U: case PLANAR_V: if (pitchUV) return height>>1; return 0;} return height; } + + // generally you shouldn't use these three + VideoFrameBuffer* GetFrameBuffer() const { return vfb; } + int GetOffset() const { return offset; } + int GetOffset(int plane) const { switch (plane) {case PLANAR_U: return offsetU;case PLANAR_V: return offsetV;default: return offset;}; } + + // in plugins use env->SubFrame() + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height) const; + VideoFrame* Subframe(int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int pitchUV) const; + + + const BYTE* GetReadPtr() const { return vfb->GetReadPtr() + offset; } + const BYTE* GetReadPtr(int plane) const { return vfb->GetReadPtr() + GetOffset(plane); } + + bool IsWritable() const { return (refcount == 1 && vfb->refcount == 1); } + + BYTE* GetWritePtr() const { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); + //throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? (vfb->GetWritePtr() + offset) : 0; + } + + BYTE* GetWritePtr(int plane) const { + if (plane==PLANAR_Y) { + if (vfb->GetRefcount()>1) { + _ASSERT(FALSE); +// throw AvisynthError("Internal Error - refcount was more than one!"); + } + return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0; + } + return vfb->data + GetOffset(plane); + } + + ~VideoFrame() { InterlockedDecrement(&vfb->refcount); } +}; + +enum { + CACHE_NOTHING=0, + CACHE_RANGE=1, + CACHE_ALL=2, + CACHE_AUDIO=3, + CACHE_AUDIO_NONE=4 + }; + +// Base class for all filters. +class IClip { + friend class PClip; + friend class AVSValue; + int refcnt; + void AddRef() { InterlockedIncrement((long *)&refcnt); } + void Release() { InterlockedDecrement((long *)&refcnt); if (!refcnt) delete this; } +public: + IClip() : refcnt(0) {} + + virtual int __stdcall GetVersion() { return AVISYNTH_INTERFACE_VERSION; } + + virtual PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) = 0; + virtual bool __stdcall GetParity(int n) = 0; // return field parity if field_based, else parity of first field in frame + virtual void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) = 0; // start and count are in samples + virtual void __stdcall SetCacheHints(int cachehints,int frame_range) = 0 ; // We do not pass cache requests upwards, only to the next filter. + virtual const VideoInfo& __stdcall GetVideoInfo() = 0; + virtual __stdcall ~IClip() {} +}; + + +// smart pointer to IClip +class PClip { + + IClip* p; + + IClip* GetPointerWithAddRef() const { if (p) p->AddRef(); return p; } + friend class AVSValue; + friend class VideoFrame; + + void Init(IClip* x) { + if (x) x->AddRef(); + p=x; + } + void Set(IClip* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PClip() { p = 0; } + PClip(const PClip& x) { Init(x.p); } + PClip(IClip* x) { Init(x); } + void operator=(IClip* x) { Set(x); } + void operator=(const PClip& x) { Set(x.p); } + + IClip* operator->() const { return p; } + + // useful in conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PClip() { if (p) p->Release(); } +}; + + +// smart pointer to VideoFrame +class PVideoFrame { + + VideoFrame* p; + + void Init(VideoFrame* x) { + if (x) x->AddRef(); + p=x; + } + void Set(VideoFrame* x) { + if (x) x->AddRef(); + if (p) p->Release(); + p=x; + } + +public: + PVideoFrame() { p = 0; } + PVideoFrame(const PVideoFrame& x) { Init(x.p); } + PVideoFrame(VideoFrame* x) { Init(x); } + void operator=(VideoFrame* x) { Set(x); } + void operator=(const PVideoFrame& x) { Set(x.p); } + + VideoFrame* operator->() const { return p; } + + // for conditional expressions + operator void*() const { return p; } + bool operator!() const { return !p; } + + ~PVideoFrame() { if (p) p->Release();} +}; + + +class AVSValue { +public: + + AVSValue() { type = 'v'; } + AVSValue(IClip* c) { type = 'c'; clip = c; if (c) c->AddRef(); } + AVSValue(const PClip& c) { type = 'c'; clip = c.GetPointerWithAddRef(); } + AVSValue(bool b) { type = 'b'; boolean = b; } + AVSValue(int i) { type = 'i'; integer = i; } +// AVSValue(__int64 l) { type = 'l'; longlong = l; } + AVSValue(float f) { type = 'f'; floating_pt = f; } + AVSValue(double f) { type = 'f'; floating_pt = float(f); } + AVSValue(const char* s) { type = 's'; string = s; } + AVSValue(const AVSValue* a, int size) { type = 'a'; array = a; array_size = size; } + AVSValue(const AVSValue& v) { Assign(&v, true); } + + ~AVSValue() { if (IsClip() && clip) clip->Release(); } + AVSValue& operator=(const AVSValue& v) { Assign(&v, false); return *this; } + + // Note that we transparently allow 'int' to be treated as 'float'. + // There are no int<->bool conversions, though. + + bool Defined() const { return type != 'v'; } + bool IsClip() const { return type == 'c'; } + bool IsBool() const { return type == 'b'; } + bool IsInt() const { return type == 'i'; } +// bool IsLong() const { return (type == 'l'|| type == 'i'); } + bool IsFloat() const { return type == 'f' || type == 'i'; } + bool IsString() const { return type == 's'; } + bool IsArray() const { return type == 'a'; } + + PClip AsClip() const { _ASSERTE(IsClip()); return IsClip()?clip:0; } + bool AsBool() const { _ASSERTE(IsBool()); return boolean; } + int AsInt() const { _ASSERTE(IsInt()); return integer; } +// int AsLong() const { _ASSERTE(IsLong()); return longlong; } + const char* AsString() const { _ASSERTE(IsString()); return IsString()?string:0; } + double AsFloat() const { _ASSERTE(IsFloat()); return IsInt()?integer:floating_pt; } + + bool AsBool(bool def) const { _ASSERTE(IsBool()||!Defined()); return IsBool() ? boolean : def; } + int AsInt(int def) const { _ASSERTE(IsInt()||!Defined()); return IsInt() ? integer : def; } + double AsFloat(double def) const { _ASSERTE(IsFloat()||!Defined()); return IsInt() ? integer : type=='f' ? floating_pt : def; } + const char* AsString(const char* def) const { _ASSERTE(IsString()||!Defined()); return IsString() ? string : def; } + + int ArraySize() const { _ASSERTE(IsArray()); return IsArray()?array_size:1; } + + const AVSValue& operator[](int index) const { + _ASSERTE(IsArray() && index>=0 && index=0 && indexIsClip() && src->clip) + src->clip->AddRef(); + if (!init && IsClip() && clip) + clip->Release(); + // make sure this copies the whole struct! + ((__int32*)this)[0] = ((__int32*)src)[0]; + ((__int32*)this)[1] = ((__int32*)src)[1]; + } +}; + + +// instantiable null filter +class GenericVideoFilter : public IClip { +protected: + PClip child; + VideoInfo vi; +public: + GenericVideoFilter(PClip _child) : child(_child) { vi = child->GetVideoInfo(); } + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env) { return child->GetFrame(n, env); } + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env) { child->GetAudio(buf, start, count, env); } + const VideoInfo& __stdcall GetVideoInfo() { return vi; } + bool __stdcall GetParity(int n) { return child->GetParity(n); } + void __stdcall SetCacheHints(int cachehints,int frame_range) { } ; // We do not pass cache requests upwards, only to the next filter. +}; + + +class AvisynthError /* exception */ { +public: + const char* const msg; + AvisynthError(const char* _msg) : msg(_msg) {} +}; + + + + +/* Helper classes useful to plugin authors */ + +class AlignPlanar : public GenericVideoFilter +{ +public: + AlignPlanar(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class FillBorder : public GenericVideoFilter +{ +public: + FillBorder(PClip _clip); + static PClip Create(PClip clip); + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; + + + +class ConvertAudio : public GenericVideoFilter +/** + * Helper class to convert audio to any format + **/ +{ +public: + ConvertAudio(PClip _clip, int prefered_format); + void __stdcall GetAudio(void* buf, __int64 start, __int64 count, IScriptEnvironment* env); + void __stdcall SetCacheHints(int cachehints,int frame_range); // We do pass cache requests upwards, to the cache! + + static PClip Create(PClip clip, int sample_type, int prefered_type); + static AVSValue __cdecl Create_float(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_32bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_24bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_16bit(AVSValue args, void*, IScriptEnvironment*); + static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*); + virtual ~ConvertAudio(); + +private: + void convertToFloat(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_3DN(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE(char* inbuf, float* outbuf, char sample_type, int count); + void convertToFloat_SSE2(char* inbuf, float* outbuf, char sample_type, int count); + void convertFromFloat(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_3DN(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE(float* inbuf, void* outbuf, char sample_type, int count); + void convertFromFloat_SSE2(float* inbuf, void* outbuf, char sample_type, int count); + + __inline int Saturate_int8(float n); + __inline short Saturate_int16(float n); + __inline int Saturate_int24(float n); + __inline int Saturate_int32(float n); + + char src_format; + char dst_format; + int src_bps; + char *tempbuffer; + SFLOAT *floatbuffer; + int tempbuffer_size; +}; + + +// For GetCPUFlags. These are backwards-compatible with those in VirtualDub. +enum { + /* slowest CPU to support extension */ + CPUF_FORCE = 0x01, // N/A + CPUF_FPU = 0x02, // 386/486DX + CPUF_MMX = 0x04, // P55C, K6, PII + CPUF_INTEGER_SSE = 0x08, // PIII, Athlon + CPUF_SSE = 0x10, // PIII, Athlon XP/MP + CPUF_SSE2 = 0x20, // PIV, Hammer + CPUF_3DNOW = 0x40, // K6-2 + CPUF_3DNOW_EXT = 0x80, // Athlon + CPUF_X86_64 = 0xA0, // Hammer (note: equiv. to 3DNow + SSE2, which only Hammer + // will have anyway) + CPUF_SSE3 = 0x100, // Some P4 & Athlon 64. +}; +#define MAX_INT 0x7fffffff +#define MIN_INT -0x7fffffff + + + +class IScriptEnvironment { +public: + virtual __stdcall ~IScriptEnvironment() {} + + virtual /*static*/ long __stdcall GetCPUFlags() = 0; + + virtual char* __stdcall SaveString(const char* s, int length = -1) = 0; + virtual char* __stdcall Sprintf(const char* fmt, ...) = 0; + // note: val is really a va_list; I hope everyone typedefs va_list to a pointer + virtual char* __stdcall VSprintf(const char* fmt, void* val) = 0; + + __declspec(noreturn) virtual void __stdcall ThrowError(const char* fmt, ...) = 0; + + class NotFound /*exception*/ {}; // thrown by Invoke and GetVar + + typedef AVSValue (__cdecl *ApplyFunc)(AVSValue args, void* user_data, IScriptEnvironment* env); + + virtual void __stdcall AddFunction(const char* name, const char* params, ApplyFunc apply, void* user_data) = 0; + virtual bool __stdcall FunctionExists(const char* name) = 0; + virtual AVSValue __stdcall Invoke(const char* name, const AVSValue args, const char** arg_names=0) = 0; + + virtual AVSValue __stdcall GetVar(const char* name) = 0; + virtual bool __stdcall SetVar(const char* name, const AVSValue& val) = 0; + virtual bool __stdcall SetGlobalVar(const char* name, const AVSValue& val) = 0; + + virtual void __stdcall PushContext(int level=0) = 0; + virtual void __stdcall PopContext() = 0; + + // align should be 4 or 8 + virtual PVideoFrame __stdcall NewVideoFrame(const VideoInfo& vi, int align=FRAME_ALIGN) = 0; + + virtual bool __stdcall MakeWritable(PVideoFrame* pvf) = 0; + + virtual /*static*/ void __stdcall BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp, int src_pitch, int row_size, int height) = 0; + + typedef void (__cdecl *ShutdownFunc)(void* user_data, IScriptEnvironment* env); + virtual void __stdcall AtExit(ShutdownFunc function, void* user_data) = 0; + + virtual void __stdcall CheckVersion(int version = AVISYNTH_INTERFACE_VERSION) = 0; + + virtual PVideoFrame __stdcall Subframe(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height) = 0; + + virtual int __stdcall SetMemoryMax(int mem) = 0; + + virtual int __stdcall SetWorkingDir(const char * newdir) = 0; + + virtual void* __stdcall ManageCache(int key, void* data) = 0; + + enum PlanarChromaAlignmentMode { + PlanarChromaAlignmentOff, + PlanarChromaAlignmentOn, + PlanarChromaAlignmentTest }; + + virtual bool __stdcall PlanarChromaAlignment(PlanarChromaAlignmentMode key) = 0; + + virtual PVideoFrame __stdcall SubframePlanar(PVideoFrame src, int rel_offset, int new_pitch, int new_row_size, int new_height, int rel_offsetU, int rel_offsetV, int new_pitchUV) = 0; +}; + + +// avisynth.dll exports this; it's a way to use it as a library, without +// writing an AVS script or without going through AVIFile. +IScriptEnvironment* __stdcall CreateScriptEnvironment(int version = AVISYNTH_INTERFACE_VERSION); + + +#pragma pack(pop) + +#endif //__AVISYNTH_H__ diff --git a/avisynth_prs/draw_prs.cpp b/avisynth_prs/draw_prs.cpp new file mode 100644 index 000000000..3f8580945 --- /dev/null +++ b/avisynth_prs/draw_prs.cpp @@ -0,0 +1,96 @@ +// Copyright (c) 2006, Rodrigo Braz Monteiro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////// +// Headers +#include "draw_prs.h" +#include "../prs/prs_file.h" +#include "../prs/prs_video_frame.h" + + +/////////////// +// Constructor +DrawPRS::DrawPRS (IScriptEnvironment* _env, PClip _child, const char *filename) +: GenericVideoFilter(_child) +{ + // Set environment + env = _env; + + // Load file + try { + file.Load(filename); + } + + // Catch exception + catch (std::exception e) { + env->ThrowError(e.what()); + } +} + + +////////////// +// Destructor +DrawPRS::~DrawPRS() { +} + + +///////////// +// Get frame +PVideoFrame __stdcall DrawPRS::GetFrame(int n, IScriptEnvironment* env) { + // Get frame + PVideoFrame avsFrame = child->GetFrame(n,env); + + try { + // Create the PRSFrame structure + PRSVideoFrame frame; + frame.data[0] = (char*) avsFrame->GetWritePtr(); + frame.w = avsFrame->GetRowSize(); + frame.h = avsFrame->GetHeight(); + frame.pitch = avsFrame->GetPitch(); + frame.colorSpace = ColorSpace_RGB32; + + // Draw into the frame + file.DrawFrame(n,&frame); + } + + // Catch exception + catch (std::exception e) { + env->ThrowError(e.what()); + } + + // Return frame + return avsFrame; +} diff --git a/avisynth_prs/draw_prs.h b/avisynth_prs/draw_prs.h new file mode 100644 index 000000000..c4ee4cc9d --- /dev/null +++ b/avisynth_prs/draw_prs.h @@ -0,0 +1,59 @@ +// Copyright (c) 2006, Rodrigo Braz Monteiro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +#pragma once + + +/////////// +// Headers +#include +#include "avisynth.h" +#include "../prs/prs_file.h" + + +///////// +// Class +class DrawPRS : public GenericVideoFilter { +private: + IScriptEnvironment* env; + PRSFile file; + +public: + DrawPRS (IScriptEnvironment* _env, PClip _child, const char *file); + ~DrawPRS (); + + PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env); +}; diff --git a/avisynth_prs/filter_main.cpp b/avisynth_prs/filter_main.cpp new file mode 100644 index 000000000..81ef8d4ec --- /dev/null +++ b/avisynth_prs/filter_main.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2006, Rodrigo Braz Monteiro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + + +/////////// +// Headers +#include +#include "avisynth.h" +#include "draw_prs.h" + + +// This is the function that created the filter, when the filter has been called. +AVSValue __cdecl CreateDrawPRS(AVSValue args, void* user_data, IScriptEnvironment* env) { + return new DrawPRS(env, args[0].AsClip(), args[1].AsString()); +} + + +// The following function is the function that actually registers the filter in AviSynth +// It is called automatically, when the plugin is loaded to see which functions this filter contains. +extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env) { + env->AddFunction("DrawPRS", "c[file]s", CreateDrawPRS, 0); + return "`Pre-Rendered Subtitles' by Rodrigo Braz Monteiro (ArchMage ZeratuL)"; +} diff --git a/avisynth_prs/shoo.txt b/avisynth_prs/shoo.txt deleted file mode 100644 index 65d19bc2b..000000000 --- a/avisynth_prs/shoo.txt +++ /dev/null @@ -1 +0,0 @@ -Here be dragons. \ No newline at end of file diff --git a/core/subtitle_format_prs.cpp b/core/subtitle_format_prs.cpp index a821ceae9..3134cfbe9 100644 --- a/core/subtitle_format_prs.cpp +++ b/core/subtitle_format_prs.cpp @@ -115,7 +115,7 @@ void PRSSubtitleFormat::WriteFile(wxString filename,wxString encoding) { // Set variables id = 0; lastDisplay = NULL; - optimizer = 0; // 0 = none, 1 = optipng, 2 = pngout + optimizer = 1; // 0 = none, 1 = optipng, 2 = pngout // Progress bool canceled = false; diff --git a/core/subtitles_rasterizer.h b/core/subtitles_rasterizer.h index 573fae7bb..a2fcbced9 100644 --- a/core/subtitles_rasterizer.h +++ b/core/subtitles_rasterizer.h @@ -39,7 +39,7 @@ ////////////// // Prototypes -class VideoFrame; +class AegisubVideoFrame; class AssFile; @@ -53,5 +53,5 @@ public: virtual void Load(AssFile *subs)=0; virtual void Close() {} - virtual void RenderFrame(VideoFrame *frame,int ms)=0; + virtual void RenderFrame(AegisubVideoFrame *frame,int ms)=0; }; diff --git a/prs/prs_file.cpp b/prs/prs_file.cpp index e1579090b..c474fb0bc 100644 --- a/prs/prs_file.cpp +++ b/prs/prs_file.cpp @@ -79,7 +79,7 @@ void PRSFile::Save(std::string path) { // Open file FILE *fp = fopen(path.c_str(),"wb"); - if (!fp) throw "Failed to open file"; + if (!fp) throw new std::exception("Failed to open file"); try { // Write the "PRS" (zero-terminated) string ID (4 bytes) @@ -127,19 +127,19 @@ void PRSFile::Load(std::string path, bool reset) { // Open file FILE *fp = fopen(path.c_str(),"rb"); - if (!fp) throw "Failed to open file"; + if (!fp) throw new std::exception("Failed to open file"); try { // Read first four bytes char buf[5]; buf[4] = 0; fread(buf,1,4,fp); - if (strcmp(buf,"PRS") != 0) throw "Invalid file type."; + if (strcmp(buf,"PRS") != 0) throw new std::exception("Invalid file type."); // Read version number unsigned __int32 temp = 0; fread(&temp,4,1,fp); - if (temp != 1) throw "Invalid version."; + if (temp != 1) throw new std::exception("Invalid version."); // Read stream name length fread(&temp,4,1,fp); @@ -237,3 +237,24 @@ PRSImage *PRSFile::FindDuplicateImage(PRSImage *img) { // No duplicate found return NULL; } + + +//////////////// +// Draw a frame +void PRSFile::DrawFrame(int n,PRSVideoFrame *frame) { + // Get list of display blocks + std::vector blocks; + GetDisplayBlocksAtFrame(n,blocks); + + // Draw the blocks + int nblocks = blocks.size(); + for (int i=0;i &blocks) { +} diff --git a/prs/prs_file.h b/prs/prs_file.h index 04a9e3d83..2cef49bde 100644 --- a/prs/prs_file.h +++ b/prs/prs_file.h @@ -41,11 +41,14 @@ // Prototypes class PRSEntry; class PRSImage; +class PRSDisplay; /////////// // Headers #include +#include +#include "prs_video_frame.h" /////////////////////////////// @@ -64,5 +67,8 @@ public: void Save(std::string path); void Load(std::string path,bool reset=true); + void GetDisplayBlocksAtFrame(int n,std::vector &blocks); + void DrawFrame(int n,PRSVideoFrame *frame); + PRSImage *FindDuplicateImage(PRSImage *img); }; diff --git a/prs/prs_image.cpp b/prs/prs_image.cpp index 07af2a160..a985acf64 100644 --- a/prs/prs_image.cpp +++ b/prs/prs_image.cpp @@ -99,7 +99,7 @@ void PRSImage::WriteData(std::vector &vec) { // Read data void PRSImage::ReadData(std::vector &vec) { // Set length - unsigned __int32 size = vec.size(); + size_t size = vec.size(); size_t pos = 0; // Read image identifier diff --git a/prs/prs_video_frame.cpp b/prs/prs_video_frame.cpp new file mode 100644 index 000000000..5b8c743fa --- /dev/null +++ b/prs/prs_video_frame.cpp @@ -0,0 +1,34 @@ +// Copyright (c) 2005, Rodrigo Braz Monteiro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// diff --git a/prs/prs_video_frame.h b/prs/prs_video_frame.h new file mode 100644 index 000000000..c6bfc99bf --- /dev/null +++ b/prs/prs_video_frame.h @@ -0,0 +1,58 @@ +// Copyright (c) 2005, Rodrigo Braz Monteiro +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// * Neither the name of the Aegisub Group nor the names of its contributors +// may be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// ----------------------------------------------------------------------------- +// +// AEGISUB +// +// Website: http://aegisub.cellosoft.com +// Contact: mailto:zeratul@cellosoft.com +// + +#pragma once + + +/////////////// +// Color space +enum ColorSpaceType { + ColorSpace_RGB32, + ColorSpace_RGB24, + ColorSpace_YUY2, + ColorSpace_YV12 +}; + + +///////////////////// +// Video frame class +class PRSVideoFrame { +public: + char *data[4]; + int w; + int h; + int pitch; + ColorSpaceType colorSpace; +};