Exemple #1
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            var resFrame = NewVideoFrame(env);

            if (realPlanar)
            {
                OverlayUtils.ResetChroma(resFrame);
            }
            using (var srcFrame = base.GetFrame(n, env))
            {
                unsafe
                {
                    var src        = (byte *)srcFrame.GetReadPtr();
                    var srcStride  = srcFrame.GetPitch();
                    var dest       = (byte *)resFrame.GetWritePtr();
                    var destStride = resFrame.GetPitch();
                    var rowSize    = resFrame.GetRowSize();

                    for (var y = 0; y < height; y++, src += srcStride, dest += destStride)
                    {
                        for (var x = 0; x < rowSize; x++)
                        {
                            var val = src[x];
                            dest[x] = val >= low && val <= high ? byte.MaxValue : byte.MinValue;
                        }
                    }
                }
            }
            return(resFrame);
        }
Exemple #2
0
 protected override void Dispose(bool A_0)
 {
     Filters.Remove(this);
     OverlayUtils.Dispose(this);
     base.Dispose(A_0);
     topLevel.Dispose();
 }
 public sealed override void Initialize(AVSValue args, ScriptEnvironment env)
 {
     try
     {
         using (new DynamicEnvironment(env))
         {
             OverlayUtils.InitArgs(this, args);
             Initialize(args);
             base.Initialize(args, env);
         }
         topLevel = new DynamicEnvironment(env, false);
         AfterInitialize();
         topLevel.Detach();
     }
     catch (Exception ex)
     {
         try
         {
             DisposeAll();
         }
         catch
         {
             // ignored
         }
         finally
         {
             if (ex is SEHException)
             {
                 throw new AvisynthException("Runtime function call error: " + DynamicEnvironment.LastError);
             }
             DynamicEnvironment.LastError = ex.Message;
             throw new AvisynthException(ex.Message);
         }
     }
 }
Exemple #4
0
        public override void Initialize(AVSValue args, ScriptEnvironment env)
        {
            width  = Child?.GetVideoInfo().width ?? args[1].AsInt();
            height = Child?.GetVideoInfo().height ?? args[2].AsInt();

            left   = args[3].AsInt(left);
            top    = args[4].AsInt(top);
            right  = args[5].AsInt(right);
            bottom = args[6].AsInt(bottom);

            noise    = args[7].AsBool(noise);
            gradient = args[8].AsBool(gradient);
            if (!noise && !gradient)
            {
                env.ThrowError("No gradient, no noise");
            }
            seed = args[9].AsInt(seed);

            var vi = GetVideoInfo();

            vi.width           = width;
            vi.height          = height;
            vi.pixel_type      = Child?.GetVideoInfo().pixel_type ?? ColorSpaces.CS_BGR24;
            vi.num_frames      = Child?.GetVideoInfo().num_frames ?? 1000;
            vi.fps_numerator   = Child?.GetVideoInfo().fps_numerator ?? 25;
            vi.fps_denominator = Child?.GetVideoInfo().fps_denominator ?? 1;
            SetVideoInfo(ref vi);
            realPlanar = Child == null || OverlayUtils.IsRealPlanar(Child); //Y8 is interleaved
            rgb        = GetVideoInfo().IsRGB();
        }
        private void Initialize(Clip src, Clip over)
        {
            var srcInfo  = src.GetVideoInfo();
            var overInfo = over.GetVideoInfo();

            var vi = src.GetVideoInfo();

            if (Width > 0)
            {
                vi.width = Width;
            }
            if (Height > 0)
            {
                vi.height = Height;
            }
            var srcBitDepth  = srcInfo.pixel_type.GetBitDepth();
            var overBitDepth = overInfo.pixel_type.GetBitDepth();

            if (srcBitDepth != overBitDepth && ColorAdjust > 0 && ColorAdjust < 1)
            {
                throw new AvisynthException("ColorAdjust -1, 0, 1 only allowed when video bit depth is different");
            }
            var targetBitDepth = ColorAdjust >= 1 - double.Epsilon ? overBitDepth : srcBitDepth;

            vi.pixel_type   = vi.pixel_type.ChangeBitDepth(targetBitDepth);
            vi.num_frames   = Child.GetVideoInfo().num_frames;
            planes          = OverlayUtils.GetPlanes(vi.pixel_type);
            targetSubsample = new Size(srcInfo.pixel_type.GetWidthSubsample(), srcInfo.pixel_type.GetHeightSubsample());
            SetVideoInfo(ref vi);
        }
Exemple #6
0
 public sealed override void Initialize(AVSValue args, ScriptEnvironment env)
 {
     try
     {
         using (new DynamicEnvironment(env))
         {
             OverlayUtils.InitArgs(this, args);
             Initialize(args);
             base.Initialize(args, env);
         }
         topLevel = new DynamicEnvironment(env, false);
         AfterInitialize();
         topLevel.Detach();
     }
     catch (Exception ex)
     {
         try
         {
             DisposeAll();
         }
         finally
         {
             throw ex;
         }
     }
 }
Exemple #7
0
        protected override void Initialize(AVSValue args)
        {
            LimitedRange = LimitedRange && GetVideoInfo().IsPlanar();
            planes       = GetVideoInfo().pixel_type.HasFlag(ColorSpaces.CS_INTERLEAVED)
                ? new[] { default(YUVPlanes) }
                : (Channels ?? "yuv").ToCharArray().Select(p => Enum.Parse(typeof(YUVPlanes), "PLANAR_" + p, true))
            .Cast <YUVPlanes>().ToArray();
            realChannels = GetVideoInfo().IsPlanar()
                ? new[] { 0 }
                : (Channels ?? "rgb").ToLower().ToCharArray().Select(p => "bgr".IndexOf(p)).ToArray();
            if (!OverlayUtils.IsRealPlanar(Child))
            {
                planes = new[] { default(YUVPlanes) }
            }
            ;
            sampleBits    = Sample.GetVideoInfo().pixel_type.GetBitDepth();
            referenceBits = Reference.GetVideoInfo().pixel_type.GetBitDepth();
            var vi = GetVideoInfo();

            vi.pixel_type = vi.pixel_type.ChangeBitDepth(referenceBits);
            SetVideoInfo(ref vi);
            var cacheSize = tr * 2 + 1;
            var cacheKey  = StaticEnv.GetEnv2() == null ? CacheType.CACHE_25_ALL : CacheType.CACHE_GENERIC;

            Child.SetCacheHints(cacheKey, cacheSize);
            Sample.SetCacheHints(cacheKey, cacheSize);
            Reference.SetCacheHints(cacheKey, cacheSize);
            SampleMask?.SetCacheHints(cacheKey, cacheSize);
            ReferenceMask?.SetCacheHints(cacheKey, cacheSize);
            if (Intensity < 1 && sampleBits != referenceBits)
            {
                throw new AvisynthException("Intensity < 1 is not allowed when sample and reference bit depth are not equal");
            }
        }
Exemple #8
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            if (noRotate)
            {
                return(base.GetFrame(n, env));
            }
            var res = NewVideoFrame(env);

            using (var frame = Child.GetFrame(n, env))
            {
                var vi = Child.GetVideoInfo();
                Parallel.ForEach(planes, plane =>
                {
                    var zero = plane == YUVPlanes.PLANAR_U || plane == YUVPlanes.PLANAR_V ? 128 : 0;
                    OverlayUtils.MemSet(res.GetWritePtr(plane), zero, res.GetPitch(plane) * res.GetHeight(plane));

                    // get source image size
                    var height    = frame.GetHeight(plane);
                    var width     = vi.width / (vi.height / height);
                    var pixelSize = frame.GetRowSize(plane) / width;

                    NativeUtils.BilinearRotate(
                        frame.GetReadPtr(plane), frame.GetRowSize(plane) / pixelSize, frame.GetHeight(plane),
                        frame.GetPitch(plane),
                        res.GetWritePtr(plane), res.GetRowSize(plane) / pixelSize, res.GetHeight(plane),
                        res.GetPitch(plane),
                        angle, pixelSize);
                });
            }

            return(res);
        }
        protected VideoFrame Copy(VideoFrame frame)
        {
            var res = NewVideoFrame(StaticEnv);

            Copy(frame, res, OverlayUtils.GetPlanes(GetVideoInfo().pixel_type));
            return(res);
        }
        protected override VideoFrame GetFrame(int n)
        {
            OverlayInfo info;

            lock (Child)
                using (var infoFrame = Child.GetFrame(n, StaticEnv))
                    info = OverlayInfo.FromFrame(infoFrame).First();
            var crop   = info.GetCrop();
            var hybrid = DynamicEnv.Invoke(Function,
                                           Engine, Source, Overlay, info.X, info.Y, info.Angle / 100.0, info.Width, info.Height,
                                           crop.Left, crop.Top, crop.Right, crop.Bottom, info.Diff);

            if (Debug)
            {
                hybrid = hybrid.Subtitle(info.ToString().Replace("\n", "\\n"), lsp: 0);
            }
            var res = NewVideoFrame(StaticEnv);

            using (VideoFrame frame = hybrid[n])
            {
                Parallel.ForEach(new[] { YUVPlanes.PLANAR_Y, YUVPlanes.PLANAR_U, YUVPlanes.PLANAR_V }, plane =>
                {
                    for (var y = 0; y < frame.GetHeight(plane); y++)
                    {
                        OverlayUtils.CopyMemory(res.GetWritePtr(plane) + y * res.GetPitch(plane),
                                                frame.GetReadPtr(plane) + y * frame.GetPitch(plane), res.GetRowSize(plane));
                    }
                });
            }
            return(res);
        }
 protected void Copy(VideoFrame frame, VideoFrame res, YUVPlanes[] planes)
 {
     using (frame)
     {
         Parallel.ForEach(planes, plane => OverlayUtils.CopyPlane(frame, res, plane));
     }
 }
        protected override VideoFrame GetFrame(int n)
        {
            OverlayInfo info;

            lock (Child)
                using (var infoFrame = Child.GetFrame(n, StaticEnv))
                    info = OverlayInfo.FromFrame(infoFrame);
            var hybrid = RenderFrame(info);

            if (debug)
            {
                hybrid = hybrid.Subtitle(info.ToString().Replace("\n", "\\n"), lsp: 0);
            }
            var res = NewVideoFrame(StaticEnv);

            using (VideoFrame frame = hybrid[n])
            {
                Parallel.ForEach(new[] { YUVPlanes.PLANAR_Y, YUVPlanes.PLANAR_U, YUVPlanes.PLANAR_V }, plane =>
                {
                    for (var y = 0; y < frame.GetHeight(plane); y++)
                    {
                        OverlayUtils.CopyMemory(res.GetWritePtr(plane) + y * res.GetPitch(plane),
                                                frame.GetReadPtr(plane) + y * frame.GetPitch(plane), res.GetRowSize(plane));
                    }
                });
            }
            return(res);
        }
Exemple #13
0
 public override void Initialize(AVSValue args, ScriptEnvironment env)
 {
     low        = args[1].AsInt(byte.MinValue);
     high       = args[2].AsInt(byte.MaxValue);
     width      = GetVideoInfo().width;
     height     = GetVideoInfo().height;
     realPlanar = OverlayUtils.IsRealPlanar(Child);
 }
 protected override void Dispose(bool disposing)
 {
     Filters.Remove(this);
     base.Dispose(disposing);
     OverlayUtils.Dispose(this);
     topLevel?.Dispose();
     topLevel = null;
 }
        protected override VideoFrame GetFrame(int n)
        {
            var allPlanes = OverlayUtils.GetPlanes(GetVideoInfo().pixel_type);

            if (Smooth > 0)
            {
                return(Copy(GetFrameWithSmooth(n)));
            }
            var output = NewVideoFrame(StaticEnv);

            using (var src = Source.GetFrame(n, StaticEnv))
                using (var over = Overlay.GetFrame(n, StaticEnv))
                {
                    if (GetVideoInfo().IsRGB() && realChannels.Length < 3 || Source.IsRealPlanar() && planes.Length < 3)
                    {
                        Parallel.ForEach(allPlanes, parallelOptions, plane => OverlayUtils.CopyPlane(src, output, plane));
                    }
                    unsafe
                    {
                        Parallel.ForEach(planes, parallelOptions, plane =>
                        {
                            var pixelSize = GetVideoInfo().IsRGB() ? 3 : 1;

                            var size       = new Size(src.GetRowSize(plane), src.GetHeight(plane));
                            var srcStride  = src.GetPitch(plane);
                            var overStride = over.GetPitch(plane);
                            Parallel.ForEach(realChannels, parallelOptions, channel =>
                            {
                                Parallel.For(0, size.Height, parallelOptions, y =>
                                {
                                    var srcData  = (byte *)src.GetReadPtr(plane) + y * srcStride + channel;
                                    var overData = (byte *)over.GetReadPtr(plane) + y * overStride + channel;
                                    var writer   = (byte *)output.GetWritePtr(plane) + y * output.GetPitch(plane) + channel;
                                    for (var x = 0; x < size.Width; x += pixelSize)
                                    {
                                        var srcComplexity  = GetComplexity(srcData, x, y, pixelSize, srcStride, size, Steps);
                                        var overComplexity = GetComplexity(overData, x, y, pixelSize, overStride, size, Steps);
                                        var diff           = srcComplexity - overComplexity;
                                        var srcPreferred   = diff > Preference;
                                        if (Mask)
                                        {
                                            writer[x] = srcPreferred ? byte.MinValue : byte.MaxValue;
                                        }
                                        else
                                        {
                                            writer[x] = srcPreferred ? srcData[x] : overData[x];
                                        }
                                    }
                                });
                            });
                        });
                    }
                }
            return(output);
        }
Exemple #16
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            var resFrame = NewVideoFrame(env);

            if (realPlanar && greyMask)
            {
                OverlayUtils.ResetChroma(resFrame);
            }
            using var srcFrame = base.GetFrame(n, env);
            unsafe
            {
                var planes = greyMask ? new[] { default(YUVPlanes) } : OverlayUtils.GetPlanes(GetVideoInfo().pixel_type);
                Parallel.ForEach(planes, plane =>
                {
                    var srcStride  = srcFrame.GetPitch(plane);
                    var destStride = resFrame.GetPitch(plane);
                    var width      = resFrame.GetRowSize(plane) / (hdr ? 2 : 1);
                    var height     = resFrame.GetHeight(plane);
                    if (hdr)
                    {
                        var src  = (ushort *)srcFrame.GetReadPtr(plane);
                        var dest = (ushort *)resFrame.GetWritePtr(plane);

                        Parallel.For(0, height, y =>
                        {
                            var srcData  = src + y * srcStride;
                            var destData = dest + y * destStride;
                            for (var x = 0; x < width; x++)
                            {
                                var val     = srcData[x];
                                destData[x] = val >= low && val <= high ? ushort.MaxValue : ushort.MinValue;
                            }
                        });
                    }
                    else
                    {
                        var src  = (byte *)srcFrame.GetReadPtr(plane);
                        var dest = (byte *)resFrame.GetWritePtr(plane);

                        Parallel.For(0, height, y =>
                        {
                            var srcData  = src + y * srcStride;
                            var destData = dest + y * destStride;
                            for (var x = 0; x < width; x++)
                            {
                                var val     = srcData[x];
                                destData[x] = val >= low && val <= high ? byte.MaxValue : byte.MinValue;
                            }
                        });
                    }
                });
            }

            return(resFrame);
        }
        public dynamic ResizeRotate(
            Clip clip,
            string resizeFunc, string rotateFunc,
            int width, int height, int angle = 0,
            RectangleD crop = default, Warp warp = default)
        {
            if (clip == null)
            {
                return(null);
            }
            var dynamic = clip.Dynamic();

            if (warp != null && !warp.IsEmpty)
            {
                dynamic = dynamic.Warp(warp.ToArray(), relative: true, resample: OverlayUtils.GetWarpResampleMode(resizeFunc));
            }

            var vi = clip.GetVideoInfo();

            if (crop.IsEmpty && width == vi.width && height == vi.height)
            {
                return(dynamic);
            }

            var intCrop = Rectangle.FromLTRB(
                (int)Math.Floor(crop.Left),
                (int)Math.Floor(crop.Top),
                (int)Math.Floor(crop.Right),
                (int)Math.Floor(crop.Bottom)
                );

            if (!intCrop.IsEmpty)
            {
                dynamic = dynamic.Crop(intCrop.Left, intCrop.Top, -intCrop.Right, -intCrop.Bottom);
                crop    = RectangleD.FromLTRB(
                    crop.Left - intCrop.Left,
                    crop.Top - intCrop.Top,
                    crop.Right - intCrop.Right,
                    crop.Bottom - intCrop.Bottom
                    );
            }
            if (crop.IsEmpty)
            {
                dynamic = dynamic.Invoke(resizeFunc, width, height);
            }
            else
            {
                dynamic = dynamic.Invoke(resizeFunc, width, height,
                                         src_left: crop.Left, src_top: crop.Top,
                                         src_width: -crop.Right, src_height: -crop.Bottom);
            }
            return(angle == 0 ? dynamic : dynamic.Invoke(rotateFunc, angle / 100.0));
        }
Exemple #18
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            var resFrame = NewVideoFrame(env);

            if (realPlanar)
            {
                OverlayUtils.ResetChroma(resFrame);
            }
            using var srcFrame = base.GetFrame(n, env);
            unsafe
            {
                var srcStride  = srcFrame.GetPitch();
                var destStride = resFrame.GetPitch();
                if (hdr)
                {
                    var src  = (ushort *)srcFrame.GetReadPtr();
                    var dest = (ushort *)resFrame.GetWritePtr();

                    Parallel.For(0, height, y =>
                    {
                        var srcData  = src + y * srcStride;
                        var destData = dest + y * destStride;
                        for (var x = 0; x < width; x++)
                        {
                            var val     = srcData[x];
                            destData[x] = val >= low && val <= high ? ushort.MaxValue : ushort.MinValue;
                        }
                    });
                }
                else
                {
                    var src  = (byte *)srcFrame.GetReadPtr();
                    var dest = (byte *)resFrame.GetWritePtr();

                    Parallel.For(0, height, y =>
                    {
                        var srcData  = src + y * srcStride;
                        var destData = dest + y * destStride;
                        for (var x = 0; x < width; x++)
                        {
                            var val     = srcData[x];
                            destData[x] = val >= low && val <= high ? byte.MaxValue : byte.MinValue;
                        }
                    });
                }
            }

            return(resFrame);
        }
        protected override VideoFrame GetFrame(int n)
        {
            var info = GetOverlayInfo(n);//.Resize(Source.GetSize(), Overlay.GetSize());

            if (Invert)
            {
                info = info.Invert();
            }

            var res = NewVideoFrame(StaticEnv);

            var outClips = contexts.Select(ctx => RenderFrame(ctx, info));

            //outClips = contexts.Select(ctx => ctx.Source);

            var hybrid = contexts.Count == 1 ? outClips.First() : DynamicEnv.CombinePlanes(outClips,
                                                                                           planes: contexts.Select(p => p.Plane.GetLetter()).Aggregate(string.Concat),
                                                                                           pixel_type: $"YUV4{4 / targetSubsample.Width}{(4 / targetSubsample.Width - 4) + 4 / targetSubsample.Height}P{GetVideoInfo().pixel_type.GetBitDepth()}");

            if (BlankColor >= 0 && Mode == FramingMode.Fill)
            {
                var ctx         = contexts.First();
                var frameParams = ctx.CalcFrame(info);

                var mask = DynamicEnv.StaticOverlayRender(ctx.Source.ConvertToY8(), ctx.Overlay.ConvertToY8(),
                                                          info.X, info.Y, info.Angle, info.Width, info.Height, info.GetCrop(), info.Diff, overlayMode: "blend",
                                                          width: frameParams.FinalWidth, height: frameParams.FinalHeight, mode: (int)FramingMode.Mask);
                mask = InitClip(mask, ctx.TargetInfo.Width, ctx.TargetInfo.Height, 0xFF8080).Overlay(mask, frameParams.FinalX, frameParams.FinalY);
                var background = InitClip(hybrid, ctx.TargetInfo.Width, ctx.TargetInfo.Height, ctx.BlankColor);//, ctx.TargetInfo.Info.IsRGB() ? "RGB24" : "YV24");
                hybrid = hybrid.Overlay(background, mask: mask.Invert());
            }

            if (Debug)
            {
                hybrid = hybrid.Subtitle(info.DisplayInfo().Replace("\n", "\\n"), lsp: 0);
            }
            using VideoFrame frame = hybrid[info.FrameNumber];
            Parallel.ForEach(planes, plane =>
            {
                for (var y = 0; y < frame.GetHeight(plane); y++)
                {
                    OverlayUtils.CopyMemory(res.GetWritePtr(plane) + y * res.GetPitch(plane),
                                            frame.GetReadPtr(plane) + y * frame.GetPitch(plane), res.GetRowSize(plane));
                }
            });
            return(res);
        }
Exemple #20
0
 public sealed override void Initialize(AVSValue args, ScriptEnvironment env)
 {
     using (new DynamicEnviroment(env))
     {
         try
         {
             OverlayUtils.InitArgs(this, args);
             Initialize(args);
             base.Initialize(args, env);
         }
         catch
         {
             DisposeAll();
             throw;
         }
     }
 }
Exemple #21
0
        protected override void Initialize(AVSValue args)
        {
            LimitedRange = LimitedRange && GetVideoInfo().IsPlanar();
            planes       = GetVideoInfo().IsRGB()
                ? new[] { default(YUVPlanes) }
                : (Channels ?? "yuv").ToCharArray().Select(p => Enum.Parse(typeof(YUVPlanes), "PLANAR_" + p, true))
            .Cast <YUVPlanes>().ToArray();
            realChannels = GetVideoInfo().IsPlanar()
                ? new[] { 0 }
                : (Channels ?? "rgb").ToLower().ToCharArray().Select(p => "bgr".IndexOf(p)).ToArray();
            if (!OverlayUtils.IsRealPlanar(Child))
            {
                planes = new[] { default(YUVPlanes) }
            }
            ;
            var vi    = GetVideoInfo();
            var refVi = Reference.GetVideoInfo();

            sampleBits    = vi.pixel_type.GetBitDepth();
            referenceBits = refVi.pixel_type.GetBitDepth();
            vi.pixel_type = vi.pixel_type.ChangeBitDepth(referenceBits);
            SetVideoInfo(ref vi);
        }
Exemple #22
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            var frame = NewVideoFrame(env);

            if (realPlanar)
            {
                OverlayUtils.ResetChroma(frame);
            }
            OverlayUtils.MemSet(frame.GetWritePtr(), byte.MaxValue, frame.GetHeight() * frame.GetPitch());
            var stride    = frame.GetPitch();
            var pixelSize = frame.GetRowSize() / GetVideoInfo().width;
            var random    = new Random(seed == int.MaxValue ? n : seed);

            unsafe
            {
                void LeftRight(int length, Func <int, int> offset)
                {
                    if (length > 0)
                    {
                        for (var x = 0; x < length; x++)
                        {
                            var data        = (byte *)frame.GetWritePtr() + offset(x) * pixelSize;
                            var gradientVal = GradientVal(x, length);

                            for (var y = 0; y < height; y++, data += stride)
                            {
                                var val = gradientVal;
                                if (noise && random.Next(length + 1) > x && random.Next(length + 1) > x)
                                {
                                    val = 0;
                                }
                                if (val != byte.MaxValue)
                                {
                                    for (var i = 0; i < pixelSize; i++)
                                    {
                                        data[i] = val;
                                    }
                                }
                            }
                        }
                    }
                }

                void TopBottom(int length, Func <int, int> offset)
                {
                    if (length > 0)
                    {
                        for (var y = 0; y < length; y++)
                        {
                            var data        = (byte *)frame.GetWritePtr() + offset(rgb ? (height - y - 1) : y) * stride;
                            var gradientVal = GradientVal(y, length);

                            for (var x = 0; x < width; x++, data += pixelSize)
                            {
                                var val = gradientVal;
                                if (noise && random.Next(length + 1) > y && random.Next(length + 1) > y)
                                {
                                    val = 0;
                                }
                                if (val != byte.MaxValue && data[0] > val)
                                {
                                    for (var i = 0; i < pixelSize; i++)
                                    {
                                        data[i] = val;
                                    }
                                }
                            }
                        }
                    }
                }

                LeftRight(left, x => x);
                LeftRight(right, x => width - x - 1);
                TopBottom(top, y => y);
                TopBottom(bottom, y => height - y - 1);
            }
            return(frame);
        }
Exemple #23
0
        public override VideoFrame GetFrame(int n, ScriptEnvironment env)
        {
            if (noRotate)
            {
                return(base.GetFrame(n, env));
            }
            var res   = NewVideoFrame(env);
            var frame = Child.GetFrame(n, env);
            var vi    = Child.GetVideoInfo();

            Parallel.ForEach(planes, plane =>
            {
                var zero = plane == YUVPlanes.PLANAR_U || plane == YUVPlanes.PLANAR_V ? 128 : 0;
                OverlayUtils.MemSet(res.GetWritePtr(plane), zero, res.GetPitch(plane) * res.GetHeight(plane));

                // get source image size
                var height     = frame.GetHeight(plane);
                var width      = vi.width / (vi.height / height);
                var oldXradius = (width - 1) / 2.0;
                var oldYradius = (height - 1) / 2.0;
                var pixelSize  = frame.GetRowSize(plane) / width;

                // get destination image size
                var newWidth   = GetVideoInfo().width;
                var newHeight  = GetVideoInfo().height;
                var newXradius = (newWidth - 1) / 2.0;
                var newYradius = (newHeight - 1) / 2.0;

                // angle's sine and cosine
                var angleRad = -angle * Math.PI / 180;
                var angleCos = Cos(angleRad);
                var angleSin = Sin(angleRad);

                var ymax = height - 1;
                var xmax = width - 1;

                var srcStride = frame.GetPitch(plane);
                var dstOffset = res.GetPitch(plane) - res.GetRowSize(plane);

                unsafe
                {
                    var src = (byte *)frame.GetReadPtr(plane);
                    var dst = (byte *)res.GetWritePtr(plane);

                    var cy = -newYradius;
                    for (int y = 0; y < newHeight; y++, cy++)
                    {
                        // do some pre-calculations of source points' coordinates
                        // (calculate the part which depends on y-loop, but does not
                        // depend on x-loop)
                        var tx = angleSin * cy + oldXradius;
                        var ty = angleCos * cy + oldYradius;

                        var cx = -newXradius;
                        for (int x = 0; x < newWidth; x++, dst += pixelSize, cx++)
                        {
                            // coordinates of source point
                            var ox = tx + angleCos * cx;
                            var oy = ty - angleSin * cx;

                            // top-left coordinate
                            var ox1 = (int)ox;
                            var oy1 = (int)oy;

                            // validate source pixel's coordinates
                            if (ox1 >= 0 && oy1 >= 0 && ox1 < width && oy1 < height)
                            {
                                // bottom-right coordinate
                                var ox2 = ox1 == xmax ? ox1 : ox1 + 1;
                                var oy2 = oy1 == ymax ? oy1 : oy1 + 1;

                                var dx1 = ox - ox1;
                                if (dx1 < 0)
                                {
                                    dx1 = 0;
                                }
                                var dx2 = 1.0f - dx1;

                                var dy1 = oy - oy1;
                                if (dy1 < 0)
                                {
                                    dy1 = 0;
                                }
                                var dy2 = 1.0f - dy1;

                                // get four points
                                byte *p1, p2;
                                p1  = p2 = src + oy1 * srcStride;
                                p1 += ox1 * pixelSize;
                                p2 += ox2 * pixelSize;

                                byte *p3, p4;
                                p3  = p4 = src + oy2 * srcStride;
                                p3 += ox1 * pixelSize;
                                p4 += ox2 * pixelSize;

                                // interpolate using 4 points

                                for (var z = 0; z < pixelSize; z++)
                                {
                                    dst[z] = (byte)(
                                        dy2 * (dx2 * p1[z] + dx1 * p2[z]) +
                                        dy1 * (dx2 * p3[z] + dx1 * p4[z]));
                                }
                            }
                        }
                        dst += dstOffset;
                    }
                }
            });
            return(res);
        }
        protected override VideoFrame GetFrame(int n)
        {
            var frame = NewVideoFrame(StaticEnv);

            if (realPlanar)
            {
                OverlayUtils.ResetChroma(frame);
            }
            OverlayUtils.MemSet(frame.GetWritePtr(), byte.MaxValue, frame.GetHeight() * frame.GetPitch());
            var stride    = frame.GetPitch() / byteDepth;
            var pixelSize = frame.GetRowSize() / (GetVideoInfo().width *byteDepth);
            var random    = new FastRandom(Seed == 0 ? n : Seed);

            unsafe
            {
                void LeftRightByte(int length, Func <int, int> offset)
                {
                    if (length == 0)
                    {
                        return;
                    }
                    for (var x = 0; x < length; x++)
                    {
                        var data        = (byte *)frame.GetWritePtr() + offset(x) * pixelSize;
                        var gradientVal = GradientValByte(x, length);

                        for (var y = 0; y < Height; y++, data += stride)
                        {
                            var val = gradientVal;

                            if (Noise && random.Next(length) > x && random.Next(length) > x)
                            {
                                val = 0;
                            }
                            if (val != byte.MaxValue)
                            {
                                for (var i = 0; i < pixelSize; i++)
                                {
                                    data[i] = val;
                                }
                            }
                        }
                    }
                }

                void TopBottomByte(int length, Func <int, int> offset)
                {
                    if (length == 0)
                    {
                        return;
                    }
                    for (var y = 0; y < length; y++)
                    {
                        var data        = (byte *)frame.GetWritePtr() + offset(rgb ? (Height - y - 1) : y) * stride;
                        var gradientVal = GradientValByte(y, length);

                        for (var x = 0; x < Width; x++, data += pixelSize)
                        {
                            var val = gradientVal;

                            if (Noise && random.Next(length) > y && random.Next(length) > y)
                            {
                                val = 0;
                            }
                            if (val != byte.MaxValue && data[0] > val)
                            {
                                for (var i = 0; i < pixelSize; i++)
                                {
                                    data[i] = val;
                                }
                            }
                        }
                    }
                }

                void LeftRightShort(int length, Func <int, int> offset)
                {
                    if (length == 0)
                    {
                        return;
                    }
                    for (var x = 0; x < length; x++)
                    {
                        var data        = (ushort *)frame.GetWritePtr() + offset(x) * pixelSize;
                        var gradientVal = GradientValShort(x, length);

                        for (var y = 0; y < Height; y++, data += stride)
                        {
                            var val = gradientVal;

                            if (Noise && random.Next(length) > x && random.Next(length) > x)
                            {
                                val = 0;
                            }
                            if (val != shortMaxValue)
                            {
                                for (var i = 0; i < pixelSize; i++)
                                {
                                    data[i] = val;
                                }
                            }
                        }
                    }
                }

                void TopBottomShort(int length, Func <int, int> offset)
                {
                    if (length == 0)
                    {
                        return;
                    }
                    for (var y = 0; y < length; y++)
                    {
                        var data        = (ushort *)frame.GetWritePtr() + offset(rgb ? (Height - y - 1) : y) * stride;
                        var gradientVal = GradientValShort(y, length);

                        for (var x = 0; x < Width; x++, data += pixelSize)
                        {
                            var val = gradientVal;

                            if (Noise && random.Next(length) > y && random.Next(length) > y)
                            {
                                val = 0;
                            }
                            if (val != shortMaxValue && data[0] > val)
                            {
                                for (var i = 0; i < pixelSize; i++)
                                {
                                    data[i] = val;
                                }
                            }
                        }
                    }
                }

                if (GetVideoInfo().pixel_type.GetBitDepth() == 8)
                {
                    Parallel.Invoke(() => LeftRightByte(Left, x => x), () => LeftRightByte(Right, x => Width - x - 1));
                    Parallel.Invoke(() => TopBottomByte(Top, y => y), () => TopBottomByte(Bottom, y => Height - y - 1));
                }
                else
                {
                    Parallel.Invoke(() => LeftRightShort(Left, x => x), () => LeftRightShort(Right, x => Width - x - 1));
                    Parallel.Invoke(() => TopBottomShort(Top, y => y), () => TopBottomShort(Bottom, y => Height - y - 1));
                }
            }
            return(frame);
        }