diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..db2f574
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.16)
+
+project(libhqdn3d LANGUAGES CXX)
+
+find_package (Git)
+
+if (GIT_FOUND)
+ execute_process (COMMAND ${GIT_EXECUTABLE} describe --tags --abbrev=0
+ OUTPUT_VARIABLE ver
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+else ()
+ message (STATUS "GIT not found")
+endif ()
+
+add_library(hqdn3d SHARED src/hqdn3d.cpp)
+
+if (NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE "Release" CACHE STRING "" FORCE)
+endif()
+
+message(STATUS "Build type - ${CMAKE_BUILD_TYPE}")
+
+target_include_directories(hqdn3d PRIVATE /usr/local/include/avisynth)
+
+set_target_properties(hqdn3d PROPERTIES OUTPUT_NAME "hqdn3d.${ver}")
+
+target_compile_features(hqdn3d PRIVATE cxx_std_11)
+
+include(GNUInstallDirs)
+
+INSTALL(TARGETS hqdn3d LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}/avisynth")
+
+# uninstall target
+if(NOT TARGET uninstall)
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
+
+ add_custom_target(uninstall
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
+endif()
diff --git a/Changelog b/Changelog
index 6dac068..5df37e6 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,11 @@
+hqdn3d 1.0.0 (2021-4-12):
+Add parameters y, u, v.
+Add support for all YUV formats.
+Add support for 10..16-bit formats.
+Reduce intermediate precision - faster code, negligible change to output.
+Add Linux building option.
+Add version.
+
hqdn3d 0.11 (2005-1-25):
Fix a floating-point exception.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..f9fb264
--- /dev/null
+++ b/README.md
@@ -0,0 +1,82 @@
+# Description
+
+High Quality DeNoise 3D is an AviSynth port of the MPlayer filter of the same name. It performs a 3-way low-pass filter, which can completely remove high-frequency noise while minimizing blending artifacts.
+
+High bit depth support ported from the ffmpeg plugin.
+
+# Usage
+
+```
+hqdn3d (clip input, float "ls", float "cs", float "lt", float "ct", int "restart", int "y", int "u", int "v")
+```
+
+## Parameters:
+
+- input\
+ A clip to process.\
+ It must be in YUV 8..16-bit planar format.
+
+- ls\
+ Spatial luma strength.\
+ Increasing the value will improve the smoothing but may overblur.\
+ Anything above about 10 is probably not a good idea.\
+ Must be between 0.0..255.0.\
+ Default: 4.0.
+
+- cs\
+ Spatial chroma strength.\
+ Increasing the value will improve the smoothing but may overblur.\
+ Anything above about 10 is probably not a good idea.\
+ Must be between 0.0..255.0.\
+ Default: 3.0 \* ls / 4.0.
+
+- lt\
+ Luma temporal strength.\
+ Increasing the values will improve the smoothing but may cause ghosting.\
+ Anything above about 13 is probably not a good idea.\
+ Must be between 0.0..255.0.\
+ Default: 6.0 \* ls / 4.0.
+
+- ct\
+ Chroma temporal strength.\
+ Increasing the values will improve the smoothing but may cause ghosting.\
+ Anything above about 13 is probably not a good idea.\
+ Must be between 0.0..255.0.\
+ Default: lt \* cs / ls.
+
+- restart\
+ Whenever a frame is requested out of order, restart filtering this many frames before.\
+ While seeking still slightly affects the content of the frames returned, this should reduce the disturbance to an unnoticeable level.\
+ Must be non-negative value.
+ Default: max(2, 1 + max(lt, ct)).
+
+- y, u, v\
+ Planes to process.\
+ 1: Return garbage.\
+ 2: Copy plane.\
+ 3: Process plane.\
+ Default: y = u = v = 3.
+
+# Building
+
+## Windows
+
+Use solution files.
+
+## Linux
+
+### Requirements
+
+- Git
+- C++11 compiler
+- CMake >= 3.16
+
+```
+git clone https://github.com/Asd-g/hqdn3d && \
+cd hqdn3d && \
+mkdir build && \
+cd build && \
+cmake .. && \
+make -j$(nproc) && \
+sudo make install
+```
diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in
new file mode 100644
index 0000000..c2d34d4
--- /dev/null
+++ b/cmake_uninstall.cmake.in
@@ -0,0 +1,21 @@
+if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt")
+endif()
+
+file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
+string(REGEX REPLACE "\n" ";" files "${files}")
+foreach(file ${files})
+ message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
+ if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ exec_program(
+ "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
+ OUTPUT_VARIABLE rm_out
+ RETURN_VALUE rm_retval
+ )
+ if(NOT "${rm_retval}" STREQUAL 0)
+ message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
+ endif()
+ else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
+ message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
+ endif()
+endforeach()
diff --git a/hqdn3d.txt b/hqdn3d_old.txt
similarity index 100%
rename from hqdn3d.txt
rename to hqdn3d_old.txt
diff --git a/msvc/hqdn3d.sln b/msvc/hqdn3d.sln
new file mode 100644
index 0000000..071eb93
--- /dev/null
+++ b/msvc/hqdn3d.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.30503.244
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hqdn3d", "hqdn3d.vcxproj", "{9A722FBD-65EF-4C8B-BDED-4F632253AE46}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Debug|x64.ActiveCfg = Debug|x64
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Debug|x64.Build.0 = Debug|x64
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Debug|x86.ActiveCfg = Debug|Win32
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Debug|x86.Build.0 = Debug|Win32
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Release|x64.ActiveCfg = Release|x64
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Release|x64.Build.0 = Release|x64
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Release|x86.ActiveCfg = Release|Win32
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {37DAF99A-8D07-4FB9-9A83-6EA2D4EA1423}
+ EndGlobalSection
+EndGlobal
diff --git a/msvc/hqdn3d.vcxproj b/msvc/hqdn3d.vcxproj
new file mode 100644
index 0000000..ceb0611
--- /dev/null
+++ b/msvc/hqdn3d.vcxproj
@@ -0,0 +1,147 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ {9A722FBD-65EF-4C8B-BDED-4F632253AE46}
+ Win32Proj
+ 10.0
+
+
+
+ Application
+ true
+ v142
+
+
+ DynamicLibrary
+ false
+ v142
+
+
+ DynamicLibrary
+ true
+ v142
+
+
+ DynamicLibrary
+ false
+ v142
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+ ..\..\AviSynthPlus\avs_core\include;$(IncludePath)
+
+
+ ..\..\AviSynthPlus\avs_core\include;$(IncludePath)
+
+
+ ..\..\AviSynthPlus\avs_core\include;$(IncludePath)
+ false
+
+
+
+ WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ MultiThreadedDebugDLL
+ Level3
+ ProgramDatabase
+ Disabled
+
+
+ MachineX86
+ true
+ Windows
+
+
+
+
+ WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)
+ MultiThreadedDLL
+ Level3
+ ProgramDatabase
+ true
+ AnySuitable
+ true
+ Speed
+ true
+ true
+ Precise
+
+
+ MachineX86
+ true
+ Windows
+ true
+ true
+
+
+
+
+ stdcpp17
+
+
+
+
+ true
+ AnySuitable
+ true
+ Speed
+ true
+ Precise
+ true
+
+
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/msvc/hqdn3d.vcxproj.filters b/msvc/hqdn3d.vcxproj.filters
new file mode 100644
index 0000000..b5ce961
--- /dev/null
+++ b/msvc/hqdn3d.vcxproj.filters
@@ -0,0 +1,27 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav
+
+
+
+
+ Source Files
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/avisynth.h b/src/avisynth.h
deleted file mode 100644
index 073fc01..0000000
--- a/src/avisynth.h
+++ /dev/null
@@ -1,676 +0,0 @@
-// Avisynth v2.5 alpha. 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 = 2 };
-
-
-/* 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 seemlessly.
-
- // 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 !!(pixel_type & IT_BFF); }
- bool IsTFF() const { return !!(pixel_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 (__int64(frames) * audio_samples_per_second * fps_denominator / fps_numerator); }
- int FramesFromAudioSamples(__int64 samples) const { return (int)(samples * (__int64)fps_numerator / (__int64)fps_denominator / (__int64)audio_samples_per_second); }
- __int64 AudioSamplesFromBytes(__int64 bytes) const { return bytes / BytesPerAudioSample(); }
- __int64 BytesFromAudioSamples(__int64 samples) const { return samples * BytesPerAudioSample(); }
- int AudioChannels() const { return nchannels; }
- int SampleType() const{ return sample_type;}
- 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) {
- 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;
- }
-};
-
-enum {
- FILTER_TYPE=1,
- FILTER_INPUT_COLORSPACE=2,
- FILTER_OUTPUT_TYPE=9,
- FILTER_NAME=4,
- FILTER_AUTHOR=5,
- FILTER_VERSION=6,
- FILTER_ARGS=7,
- FILTER_ARGS_INFO=8,
- FILTER_ARGS_DESCRIPTION=10,
- FILTER_DESCRIPTION=11,
-};
-enum { //SUBTYPES
- FILTER_TYPE_AUDIO=1,
- FILTER_TYPE_VIDEO=2,
- FILTER_OUTPUT_TYPE_SAME=3,
- FILTER_OUTPUT_TYPE_DIFFERENT=4,
-};
-
-
-
-// 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;
- 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() { ++refcount; }
- void Release() { if (refcount==1) --vfb->refcount; --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 {
- _ASSERTE(IsWritable());
- return IsWritable() ? (vfb->GetWritePtr() + offset) : 0;
- }
-
- BYTE* GetWritePtr(int plane) const {
- if (plane==PLANAR_Y)
- return IsWritable() ? vfb->GetWritePtr() + GetOffset(plane) : 0;
- return vfb->data + GetOffset(plane);
- }
-
- ~VideoFrame() { --vfb->refcount; }
-};
-
-enum {
- CACHE_NOTHING=0,
- CACHE_RANGE=1 };
-
-// Base class for all filters.
-class IClip {
- friend class PClip;
- friend class AVSValue;
- int refcnt;
- void AddRef() { ++refcnt; }
- void Release() { 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) {}
-};
-
-
-// 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)
-};
-#define MAX_INT 0x7fffffff
-#define MIN_INT 0x80000000
-
-
-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);
-
- 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_16bit(AVSValue args, void*, IScriptEnvironment*);
- static AVSValue __cdecl Create_8bit(AVSValue args, void*, IScriptEnvironment*);
- virtual ~ConvertAudio()
- {if (tempbuffer_size) {delete[] tempbuffer;tempbuffer_size=0;}}
-private:
-void ConvertAudio::convertToFloat(char* inbuf, float* outbuf, char sample_type, int count);
-void ConvertAudio::convertFromFloat(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;
-};
-
-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 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;
-
-};
-
-
-// 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/src/hqdn3d.cpp b/src/hqdn3d.cpp
index d33d73e..0541faa 100644
--- a/src/hqdn3d.cpp
+++ b/src/hqdn3d.cpp
@@ -1,6 +1,4 @@
/*
- HQDN3D 0.11 for Avisynth
-
Copyright (C) 2003 Daniel Moreno
Avisynth port (C) 2005 Loren Merritt
@@ -19,239 +17,316 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include "internal.h"
+#include
+#include
+#include "avisynth.h"
-static inline unsigned int LowPassMul(unsigned int PrevMul, unsigned int CurrMul, int* Coef){
-// int dMul= (PrevMul&0xFFFFFF)-(CurrMul&0xFFFFFF);
- int dMul= PrevMul-CurrMul;
- int d=((dMul+0x10007FF)/(65536/16));
- return CurrMul + Coef[d];
-}
+typedef union {
+ uint16_t u16;
+ uint8_t u8[2];
+} av_alias;
+
+#define AV_RN16A(p) (((const av_alias*)(p))->u16)
+#define AV_WN16A(p, v) (((av_alias*)(p))->u16 = (v))
+
+#define LUT_BITS (depth==16 ? 8 : 4)
+#define LOAD(x) (((depth == 8 ? src[x] : AV_RN16A(src + (x) * 2)) << (16 - depth)) + (((1 << (16 - depth)) - 1) >> 1))
+#define STORE(x,val) (depth == 8 ? dst[x] = (val) >> (16 - depth) : AV_WN16A(dst + (x) * 2, (val) >> (16 - depth)))
+
+class hqdn3d : public GenericVideoFilter
+{
+ int16_t* coefs[4];
+ uint16_t* line[3];
+ uint16_t* frame_prev[3];
+ int planecount;
+ int process[3];
+ bool has_at_least_v8;
+ int _restartlap;
+ int prev_frame = -99999;
+ PVideoFrame cache;
+
+ PVideoFrame filterFrame(PVideoFrame& src, IScriptEnvironment* env);
-static void deNoise(const unsigned char *Frame, // mpi->planes[x]
- unsigned char *FrameDest, // dmpi->planes[x]
- unsigned int *LineAnt, // vf->priv->Line (width bytes)
- unsigned short *FrameAnt,
- int W, int H, int sStride, int dStride,
- int *Horizontal, int *Vertical, int *Temporal)
+public:
+ hqdn3d(PClip _child, double LumSpac, double ChromSpac, double LumTmp, double ChromTmp, int restart, int y, int u, int v, IScriptEnvironment* env);
+ ~hqdn3d();
+ PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* env);
+};
+
+static inline uint32_t lowpass(int prev, int cur, int16_t* coef, int depth)
{
- int X, Y;
- int sLineOffs = 0, dLineOffs = 0;
- unsigned int PixelAnt;
- int PixelDst;
-
- /* First pixel has no left nor top neightbour. Only previous frame */
- LineAnt[0] = PixelAnt = Frame[0]<<16;
- PixelDst = LowPassMul(FrameAnt[0]<<8, PixelAnt, Temporal);
- FrameAnt[0] = ((PixelDst+0x1000007F)/256);
- FrameDest[0]= ((PixelDst+0x10007FFF)/65536);
-
- /* Fist line has no top neightbour. Only left one for each pixel and
- * last frame */
- for (X = 1; X < W; X++){
- LineAnt[X] = PixelAnt = LowPassMul(PixelAnt, Frame[X]<<16, Horizontal);
- PixelDst = LowPassMul(FrameAnt[X]<<8, PixelAnt, Temporal);
- FrameAnt[X] = ((PixelDst+0x1000007F)/256);
- FrameDest[X]= ((PixelDst+0x10007FFF)/65536);
- }
-
- for (Y = 1; Y < H; Y++){
- unsigned int PixelAnt;
- unsigned short* LinePrev=&FrameAnt[Y*W];
- sLineOffs += sStride, dLineOffs += dStride;
- /* First pixel on each line doesn't have previous pixel */
- PixelAnt = Frame[sLineOffs]<<16;
- LineAnt[0] = LowPassMul(LineAnt[0], PixelAnt, Vertical);
- PixelDst = LowPassMul(LinePrev[0]<<8, LineAnt[0], Temporal);
- LinePrev[0] = ((PixelDst+0x1000007F)/256);
- FrameDest[dLineOffs]= ((PixelDst+0x10007FFF)/65536);
-
- for (X = 1; X < W; X++){
- int PixelDst;
- /* The rest are normal */
- PixelAnt = LowPassMul(PixelAnt, Frame[sLineOffs+X]<<16, Horizontal);
- LineAnt[X] = LowPassMul(LineAnt[X], PixelAnt, Vertical);
- PixelDst = LowPassMul(LinePrev[X]<<8, LineAnt[X], Temporal);
- LinePrev[X] = ((PixelDst+0x1000007F)/256);
- FrameDest[dLineOffs+X]= ((PixelDst+0x10007FFF)/65536);
- }
- }
+ const int d = (prev - cur) >> (8 - LUT_BITS);
+ return cur + coef[d];
}
-#define ABS(A) ( (A) > 0 ? (A) : -(A) )
+static inline void denoise_temporal(const uint8_t* src, uint8_t* dst, uint16_t* frame_ant, int w, int h, int sstride, int dstride, int16_t* temporal, int depth)
+{
+ long x, y;
+ uint32_t tmp;
+
+ temporal += 256 << LUT_BITS;
+
+ for (y = 0; y < h; ++y)
+ {
+ for (x = 0; x < w; ++x)
+ {
+ frame_ant[x] = tmp = lowpass(frame_ant[x], LOAD(x), temporal, depth);
+ STORE(x, tmp);
+ }
+
+ src += sstride;
+ dst += dstride;
+ frame_ant += w;
+ }
+}
-static void PrecalcCoefs(int *Ct, double Dist25)
+static inline void denoise_spatial(const uint8_t* src, uint8_t* dst, uint16_t* line_ant, uint16_t* frame_ant, int w, int h, int sstride, int dstride, int16_t* spatial, int16_t* temporal, int depth)
{
- int i;
- double Gamma, Simil, C;
+ long x, y;
+ uint32_t pixel_ant;
+ uint32_t tmp;
+
+ spatial += 256 << LUT_BITS;
+ temporal += 256 << LUT_BITS;
+
+ /* First line has no top neighbor. Only left one for each tmp and
+ * last frame */
+ pixel_ant = LOAD(0);
+ for (x = 0; x < w; ++x)
+ {
+ line_ant[x] = tmp = pixel_ant = lowpass(pixel_ant, LOAD(x), spatial, depth);
+ frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
+ STORE(x, tmp);
+ }
+
+ w /= (depth == 8) ? 1 : 2;
+
+ for (y = 1; y < h; ++y)
+ {
+ src += sstride;
+ dst += dstride;
+ frame_ant += w;
+
+ pixel_ant = LOAD(0);
+ for (x = 0; x < w - 1; ++x)
+ {
+ line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth);
+ pixel_ant = lowpass(pixel_ant, LOAD(x + 1), spatial, depth);
+ frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
+ STORE(x, tmp);
+ }
+ line_ant[x] = tmp = lowpass(line_ant[x], pixel_ant, spatial, depth);
+ frame_ant[x] = tmp = lowpass(frame_ant[x], tmp, temporal, depth);
+ STORE(x, tmp);
+ }
+}
- Gamma = log(0.25) / log(1.0 - Dist25/255.0 - 0.00001);
+static inline void denoise(const uint8_t* src, uint8_t* dst, uint16_t* line_ant, uint16_t** frame_ant_ptr, int w, int h, int sstride, int dstride, int16_t* spatial, int16_t* temporal, int depth)
+{
+ if (spatial[0])
+ denoise_spatial(src, dst, line_ant, *frame_ant_ptr, w, h, sstride, dstride, spatial, temporal, depth);
+ else
+ denoise_temporal(src, dst, *frame_ant_ptr, w, h, sstride, dstride, temporal, depth);
+}
- for (i = -255*16; i < 256*16; i++)
- {
- Simil = 1.0 - ABS(i) / (16*255.0);
- C = pow(Simil, Gamma) * 65536.0 * (double)i / 16.0;
- Ct[16*256+i] = (int)((C<0) ? (C-0.5) : (C+0.5));
- }
+PVideoFrame hqdn3d::filterFrame(PVideoFrame& src, IScriptEnvironment* env)
+{
+ PVideoFrame dst = (has_at_least_v8) ? env->NewVideoFrameP(vi, &src) : env->NewVideoFrame(vi);
+ const int planes[3] = { PLANAR_Y, PLANAR_U, PLANAR_V };
+
+ for (int i = 0; i < planecount; ++i)
+ {
+ const int pitch = src->GetPitch(planes[i]);
+ const int dst_pitch = dst->GetPitch(planes[i]);
+ const int width = src->GetRowSize(planes[i]);
+ const int height = src->GetHeight(planes[i]);
+ const uint8_t* srcp = src->GetReadPtr(planes[i]);
+ uint8_t* dstp = dst->GetWritePtr(planes[i]);
+
+ if (process[i] == 3)
+ denoise(srcp, dstp, line[i], &frame_prev[i], width, height, pitch, dst_pitch, coefs[(i) ? 2 : 0], coefs[(i) ? 3 : 1], vi.BitsPerComponent());
+ else if (process[i] == 2)
+ env->BitBlt(dstp, dst_pitch, srcp, pitch, width, height);
+ }
+
+ return dst;
}
+static void precalc_coefs(double dist25, int depth, int16_t* ct)
+{
+ int i;
+ double gamma, simil, C;
-class hqdn3d : public GenericVideoFilter
+ gamma = log(0.25) / log(1.0 - std::min(dist25, 252.0) / 255.0 - 0.00001);
+
+ for (i = -256 << LUT_BITS; i < 256 << LUT_BITS; ++i)
+ {
+ double f = ((i << (9 - LUT_BITS)) + (1 << (8 - LUT_BITS)) - 1) / 512.0; // midpoint of the bin
+ simil = std::max(0.0, 1.0 - fabs(f) / 255.0);
+ C = pow(simil, gamma) * 256.0 * f;
+ ct[(256 << LUT_BITS) + i] = lrint(C);
+ }
+
+ ct[0] = !!dist25;
+}
+
+hqdn3d::hqdn3d(PClip _child, double LumSpac, double ChromSpac, double LumTmp, double ChromTmp, int restart, int y, int u, int v, IScriptEnvironment* env)
+ : GenericVideoFilter(_child), _restartlap(restart)
{
-public:
- hqdn3d(PClip _child, double LumSpac, double ChromSpac, double LumTmp, double ChromTmp,
- int RestartLap, IScriptEnvironment* _env) :
- GenericVideoFilter(_child), restart_lap(RestartLap), env(_env)
- {
- if(!vi.IsYV12())
- env->ThrowError("hqdn3d: requires YV12 source");
-
- if(LumSpac < 0)
- LumSpac = 4.0;
- if(ChromSpac < 0)
- ChromSpac = .75 * LumSpac;
- if(LumTmp < 0)
- LumTmp = 1.5 * LumSpac;
- if(ChromTmp < 0) {
- if(LumSpac == 0)
- ChromTmp = ChromSpac * 1.5;
- else
- ChromTmp = LumTmp * ChromSpac / LumSpac;
- }
- LumSpac = __min(254.9, LumSpac);
- ChromSpac = __min(254.9, ChromSpac);
- LumTmp = __min(254.9, LumTmp);
- ChromTmp = __min(254.9, ChromTmp);
-
- if(restart_lap < 0)
- restart_lap = __max(2, (int)(1 + __max(LumTmp, ChromTmp)));
-
- PrecalcCoefs(Coefs[0], LumSpac);
- PrecalcCoefs(Coefs[1], LumTmp);
- PrecalcCoefs(Coefs[2], ChromSpac);
- PrecalcCoefs(Coefs[3], ChromTmp);
-
- prev_frame = -99999;
- w= vi.width;
- h= vi.height;
- cw = w>>1;
- ch = h>>1;
-
- Line = new unsigned int[w];
- Frame[0] = new unsigned short[w*h];
- Frame[1] = new unsigned short[cw*ch];
- Frame[2] = new unsigned short[cw*ch];
- }
- ~hqdn3d()
- {
- if(Line) delete [] Line;
- if(Frame[0]) delete [] Frame[0];
- if(Frame[1]) delete [] Frame[1];
- if(Frame[2]) delete [] Frame[2];
- }
-
- PVideoFrame __stdcall GetFrame(int n, IScriptEnvironment* _env);
-
-private:
- //// Options
- int restart_lap; // how many frames back we look when seeking
-
- //// State
- IScriptEnvironment* env;
- // TODO: cache more than one frame, to speed up playing/seeking backwards
- PVideoFrame cache;
-
- int Coefs[4][512*16];
- unsigned int *Line;
- unsigned short *Frame[3];
-
- int prev_frame;
- int w, cw, h, ch;
-
- PVideoFrame filterFrame(PVideoFrame cur);
-};
+ const int depth = vi.BitsPerComponent();
+
+ if (vi.IsRGB() || depth == 32 || !vi.IsPlanar())
+ env->ThrowError("hqdn3d: clip must be in YUV 8..16-bit planar format.");
+ if (LumSpac < 0.0 || LumSpac > 255.0)
+ env->ThrowError("hqdn3d: ls must be between 0.0..255.0.");
+ if (ChromSpac < 0.0 || ChromSpac > 255.0)
+ env->ThrowError("hqdn3d: cs must be between 0.0..255.0.");
+ if (LumTmp < 0.0 || LumTmp > 255.0)
+ env->ThrowError("hqdn3d: lt must be between 0.0..255.0.");
+ if (ChromTmp < 0.0 || ChromTmp > 255.0)
+ env->ThrowError("hqdn3d: ct must be between 0.0..255.0.");
+ if (_restartlap < 0)
+ env->ThrowError("hqdn3d: restart must be non-negative value.");
+
+ const int process_planes[3] = { y, u, v };
+ for (int i = 0; i < 3; ++i)
+ {
+ switch (process_planes[i])
+ {
+ case 3: process[i] = 3; break;
+ case 2: process[i] = 2; break;
+ default: process[i] = 1; break;
+ }
+ }
+
+ planecount = std::min(vi.NumComponents(), 3);
+ const int planes[3] = { PLANAR_Y, PLANAR_U, PLANAR_V };
+
+ for (int i = 0; i < planecount; ++i)
+ {
+ if (process[i] == 3)
+ {
+ line[i] = new uint16_t[((i) ? vi.width >> vi.GetPlaneWidthSubsampling(planes[i]) : vi.width) * vi.ComponentSize()];
+ frame_prev[i] = new uint16_t[((i) ? (vi.width >> vi.GetPlaneWidthSubsampling(planes[i])) * (vi.height >> vi.GetPlaneHeightSubsampling(planes[i])) : vi.width * vi.height) * vi.ComponentSize()];
+ }
+ else
+ {
+ line[i] = nullptr;
+ frame_prev[i] = nullptr;
+ }
+ }
+
+ double strength[4] = { LumSpac = std::min(254.9, LumSpac),
+ LumTmp = std::min(254.9, LumTmp),
+ ChromSpac = std::min(254.9, ChromSpac),
+ ChromTmp = std::min(254.9, ChromTmp) };
+
+ for (int i = 0; i < 4; ++i)
+ {
+ coefs[i] = new int16_t[512 << LUT_BITS];
+ precalc_coefs(strength[i], depth, coefs[i]);
+ }
+
+ has_at_least_v8 = true;
+ try { env->CheckVersion(8); }
+ catch (const AvisynthError&) { has_at_least_v8 = false; };
+}
-PVideoFrame hqdn3d::filterFrame(PVideoFrame cur)
+hqdn3d::~hqdn3d()
{
- PVideoFrame newframe = env->NewVideoFrame(vi);
-
- deNoise(cur->GetReadPtr(PLANAR_Y),
- newframe->GetWritePtr(PLANAR_Y),
- Line, Frame[0], w, h,
- cur->GetPitch(PLANAR_Y),
- newframe->GetPitch(PLANAR_Y),
- Coefs[0], Coefs[0], Coefs[1]);
- deNoise(cur->GetReadPtr(PLANAR_U),
- newframe->GetWritePtr(PLANAR_U),
- Line, Frame[1], cw, ch,
- cur->GetPitch(PLANAR_U),
- newframe->GetPitch(PLANAR_U),
- Coefs[2], Coefs[2], Coefs[3]);
- deNoise(cur->GetReadPtr(PLANAR_V),
- newframe->GetWritePtr(PLANAR_V),
- Line, Frame[2], cw, ch,
- cur->GetPitch(PLANAR_V),
- newframe->GetPitch(PLANAR_V),
- Coefs[2], Coefs[2], Coefs[3]);
-
- return newframe;
+ for (int i = 0; i < 4; ++i)
+ delete[] coefs[i];
+
+ for (int i = 0; i < planecount; ++i)
+ {
+ if (process[i] == 3)
+ {
+ delete[] frame_prev[i];
+ delete[] line[i];
+ }
+ }
}
-PVideoFrame __stdcall hqdn3d::GetFrame(int n, IScriptEnvironment* _env)
+PVideoFrame __stdcall hqdn3d::GetFrame(int n, IScriptEnvironment* env)
{
- env = _env;
-
- if(n == prev_frame)
- return cache;
- // if we skip some frames, filter the gap anyway
- else if(n > prev_frame+1 && n - prev_frame <= restart_lap+1 && prev_frame >= 0) {
- for(int i=prev_frame+1; iGetFrame(i, env));
- }
- // if processing out of sequence, filter several previous frames to minimize seeking problems
- else if(n == 0 || n != prev_frame+1) {
- int sn = __max(0, n - restart_lap);
- PVideoFrame sf = child->GetFrame(sn, env);
- int x, y, c;
- int sStride = sf->GetPitch(PLANAR_Y);
- const BYTE* srcp = sf->GetReadPtr(PLANAR_Y);
- for(y = 0; y < h; y++) {
- unsigned short* dst=&Frame[0][y*w];
- const BYTE* src=srcp+y*sStride;
- for(x = 0; x < w; x++) dst[x]=src[x]<<8;
- }
- for(c=1; c<=2; c++) {
- sStride = sf->GetPitch(PLANAR_U);
- srcp = sf->GetReadPtr((c==1) ? PLANAR_U : PLANAR_V);
- for(y = 0; y < ch; y++) {
- unsigned short* dst=&Frame[c][y*cw];
- const BYTE* src=srcp+y*sStride;
- for(x = 0; x < cw; x++) dst[x]=src[x]<<8;
- }
- }
- for(int i=sn+1; iGetFrame(i, env));
- }
-
- prev_frame = n;
- cache = filterFrame(child->GetFrame(n, env));
- return cache;
+ if (n == prev_frame)
+ return cache;
+ // if we skip some frames, filter the gap anyway
+ if (n > prev_frame + 1 && n - prev_frame <= _restartlap + 1 && prev_frame >= 0)
+ {
+ for (int i = prev_frame + 1; i < n; ++i)
+ {
+ PVideoFrame src = child->GetFrame(i, env);
+ filterFrame(src, env);
+ }
+ }
+ // if processing out of sequence, filter several previous frames to minimize seeking problems
+ else if (n == 0 || n != prev_frame + 1)
+ {
+ const int sn = std::max(0, n - _restartlap);
+ PVideoFrame sf = child->GetFrame(sn, env);
+ const int planes[3] = { PLANAR_Y, PLANAR_U, PLANAR_V };
+
+ for (int i = 0; i < planecount; ++i)
+ {
+
+ const int sStride = sf->GetPitch(planes[i]);
+ const int w = sf->GetRowSize(planes[i]);
+ const int h = sf->GetHeight(planes[i]);
+ const uint8_t* srcp = sf->GetReadPtr(planes[i]);
+
+ for (int y = 0; y < h; ++y)
+ {
+ const uint8_t* src = srcp + y * sStride;
+ uint16_t* dst = &frame_prev[0][y * w];
+
+ for (int x = 0; x < w; ++x)
+ dst[x] = src[x] << 8;
+ }
+ }
+
+ for (int i = sn + 1; i < n; ++i)
+ {
+ PVideoFrame src = child->GetFrame(i, env);
+ filterFrame(src, env);
+ }
+ }
+
+ prev_frame = n;
+ PVideoFrame src = child->GetFrame(n, env);
+ cache = filterFrame(src, env);
+
+ return cache;
}
AVSValue __cdecl Create_hqdn3d(AVSValue args, void* user_data, IScriptEnvironment* env)
{
- return new hqdn3d(args[0].AsClip(),
- args[1].AsFloat(-1),
- args[2].AsFloat(-1),
- args[3].AsFloat(-1),
- args[4].AsFloat(-1),
- args[5].AsInt(-1),
- env);
+ const float ls = args[1].AsFloatf(4.0f);
+ const float cs = args[2].AsFloatf(3.0f * ls / 4.0f);
+ const float lt = args[3].AsFloatf(6.0f * ls / 4.0f);
+ const float ct = args[4].AsFloatf(lt * cs / ls);
+
+ return new hqdn3d(
+ args[0].AsClip(),
+ ls,
+ cs,
+ lt,
+ ct,
+ args[5].AsInt(std::max(2LL, llrint(1.0 + std::max(lt, ct)))),
+ args[6].AsInt(3),
+ args[7].AsInt(3),
+ args[8].AsInt(3),
+ env);
}
-extern "C" __declspec(dllexport) const char* __stdcall AvisynthPluginInit2(IScriptEnvironment* env)
+const AVS_Linkage* AVS_linkage;
+
+extern "C" __declspec(dllexport)
+const char* __stdcall AvisynthPluginInit3(IScriptEnvironment * env, const AVS_Linkage* const vectors)
{
- env->AddFunction("hqdn3d", "c[ls]f[cs]f[lt]f[ct]f[restart]i", Create_hqdn3d, 0);
+ AVS_linkage = vectors;
+
+ env->AddFunction("hqdn3d", "c[ls]f[cs]f[lt]f[ct]f[restart]i[y]i[u]i[v]i", Create_hqdn3d, 0);
return 0;
}
diff --git a/src/hqdn3d.dsp b/src/hqdn3d.dsp
deleted file mode 100644
index 7d809d5..0000000
--- a/src/hqdn3d.dsp
+++ /dev/null
@@ -1,114 +0,0 @@
-# Microsoft Developer Studio Project File - Name="hqdn3d" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=hqdn3d - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "hqdn3d.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "hqdn3d.mak" CFG="hqdn3d - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "hqdn3d - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "hqdn3d - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "hqdn3d - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DUP_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DUP_EXPORTS" /YX /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "NDEBUG"
-# ADD RSC /l 0x409 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-
-!ELSEIF "$(CFG)" == "hqdn3d - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DUP_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DUP_EXPORTS" /YX /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x409 /d "_DEBUG"
-# ADD RSC /l 0x409 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "hqdn3d - Win32 Release"
-# Name "hqdn3d - Win32 Debug"
-# Begin Group "Source Files"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\hqdn3d.cpp
-# End Source File
-# End Group
-# Begin Group "Header Files"
-
-# PROP Default_Filter "h;hpp;hxx;hm;inl"
-# Begin Source File
-
-SOURCE=.\avisynth.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\internal.h
-# End Source File
-# End Group
-# Begin Group "Resource Files"
-
-# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
-# End Group
-# End Target
-# End Project
diff --git a/src/hqdn3d.dsw b/src/hqdn3d.dsw
deleted file mode 100644
index bf4583f..0000000
--- a/src/hqdn3d.dsw
+++ /dev/null
@@ -1,29 +0,0 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "hqdn3d"=".\hqdn3d.dsp" - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
diff --git a/src/hqdn3d.rc b/src/hqdn3d.rc
new file mode 100644
index 0000000..ac428f8
--- /dev/null
+++ b/src/hqdn3d.rc
@@ -0,0 +1,30 @@
+#include
+#include
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION 1,0,0,0
+PRODUCTVERSION 1,0,0,0
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+FILEFLAGS 0x0L
+FILEOS VOS__WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "Comments", "High Quality DeNoise 3D filter."
+ VALUE "FileDescription", "hqdn3d for AviSynth 2.6 / AviSynth+"
+ VALUE "FileVersion", "1.0.0"
+ VALUE "InternalName", "hqdn3d"
+ VALUE "OriginalFilename", "hqdn3d.dll"
+ VALUE "ProductName", "hqdn3d"
+ VALUE "ProductVersion", "1.0.0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
diff --git a/src/internal.h b/src/internal.h
deleted file mode 100644
index 995a311..0000000
--- a/src/internal.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Avisynth v1.0 beta. Copyright 2000 Ben Rudiak-Gould.
-// http://www.math.berkeley.edu/~benrg/avisynth.html
-
-// 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 .
-
-#ifndef __Internal_H__
-#define __Internal_H__
-
-
-#define WIN32_LEAN_AND_MEAN
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define in64 (__int64)(unsigned short)
-
-#define ATHLON // comment this out if using the Intel compiler, or you need Pentium/K6 support
-
-typedef unsigned long Pixel;
-typedef unsigned long Pixel32;
-typedef unsigned char Pixel8;
-typedef long PixCoord;
-typedef long PixDim;
-typedef long PixOffset;
-
-#pragma hdrstop
-
-#ifndef _MSC_VER
- #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
-#else
- #include
-#endif
-
-#ifndef __max
-#define __max(a,b) (((a) > (b)) ? (a) : (b))
-#define __min(a,b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#include "avisynth.h"
-
-
-struct AVSFunction {
- const char* name;
- const char* param_types;
- AVSValue (__cdecl *apply)(AVSValue args, void* user_data, IScriptEnvironment* env);
- void* user_data;
-};
-
-
-int RGB2YUV(int rgb);
-
-PClip Create_MessageClip(const char* message, int width, int height,
- int pixel_type, bool shrink, int textcolor, int halocolor, int bgcolor,
- IScriptEnvironment* env);
-
-PClip new_Splice(PClip _child1, PClip _child2, bool realign_sound, IScriptEnvironment* env);
-PClip new_SeparateFields(PClip _child, IScriptEnvironment* env);
-PClip new_AssumeFrameBased(PClip _child);
-
-void BitBlt(BYTE* dstp, int dst_pitch, const BYTE* srcp,
- int src_pitch, int row_size, int height);
-
-long GetCPUFlags();
-
-
-class _PixelClip {
- enum { buffer=320 };
- BYTE clip[256+buffer*2];
-public:
- _PixelClip() {
- memset(clip, 0, buffer);
- for (int i=0; i<256; ++i) clip[i+buffer] = (unsigned char) i;
- memset(clip+buffer+256, 255, buffer);
- }
- BYTE operator()(int i) { return clip[i+buffer]; }
-};
-
-extern _PixelClip PixelClip;
-
-
-template
-static __inline void Relink(ListNode* newprev, ListNode* me, ListNode* newnext) {
- if (me == newprev || me == newnext) return;
- me->next->prev = me->prev;
- me->prev->next = me->next;
- me->prev = newprev;
- me->next = newnext;
- me->prev->next = me->next->prev = me;
-}
-
-
-
-/*** Inline helper methods ***/
-
-
-static __inline BYTE ScaledPixelClip(int i) {
- return PixelClip((i+32768) >> 16);
-}
-
-
-static __inline bool IsClose(int a, int b, unsigned threshold)
- { return (unsigned(a-b+threshold) <= threshold*2); }
-
-
-
-
-#endif // __Internal_H__