protected override void Initialize(AVSValue args) { base.Initialize(args); var srcInfo = Source.GetVideoInfo(); var overInfo = Overlay.GetVideoInfo(); overlaySettings = new OverlayInfo { X = X, Y = Y, Angle = (int)Math.Round(Angle * 100), Width = OverlayWidth == 0 ? overInfo.width : OverlayWidth, Height = OverlayHeight == 0 ? overInfo.height : OverlayHeight, Diff = Diff, BaseWidth = overInfo.width, BaseHeight = overInfo.height, SourceWidth = srcInfo.width, SourceHeight = srcInfo.height }; overlaySettings.SetCrop(RectangleF.FromLTRB( (float)CropLeft, (float)CropTop, (float)CropRight, (float)CropBottom)); }
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 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); }
public FrameInterval(OverlayInfo frame) { if (frame == null) { throw new ArgumentException(); } Add(frame); }
private static void WriteInfo(BinaryWriter writer, OverlayInfo info) { writer.Write(info.FrameNumber + 1); writer.Write((int)(info.Diff * 1000)); writer.Write((short)info.X); writer.Write((short)info.Y); writer.Write((short)info.Width); writer.Write((short)info.Height); writer.Write((short)info.CropLeft); writer.Write((short)info.CropTop); writer.Write((short)info.CropRight); writer.Write((short)info.CropBottom); writer.Write((short)info.Angle); }
protected override void Initialize(AVSValue args) { srcClip = args[0].AsClip(); overClip = args[1].AsClip(); overlaySettings = new OverlayInfo { X = args[2].AsInt(), Y = args[3].AsInt(), Angle = (int)Math.Round(args[4].AsFloat() * 100), Width = args[5].AsInt(overClip.GetVideoInfo().width), Height = args[6].AsInt(overClip.GetVideoInfo().height), Diff = args[11].AsFloat(-1) }; overlaySettings.SetCrop(RectangleF.FromLTRB( (float)args[7].AsFloat(), (float)args[8].AsFloat(), (float)args[9].AsFloat(), (float)args[10].AsFloat())); srcSize = new Size(srcClip.GetVideoInfo().width, srcClip.GetVideoInfo().height); overSize = new Size(overClip.GetVideoInfo().width, overClip.GetVideoInfo().height); srcMaskClip = args[12].IsClip() ? args[12].AsClip() : null; overMaskClip = args[13].IsClip() ? args[13].AsClip() : null; lumaOnly = args[14].AsBool(lumaOnly); var width = args[15].AsInt(srcClip.GetVideoInfo().width); var height = args[16].AsInt(srcClip.GetVideoInfo().height); var vi = srcClip.GetVideoInfo(); vi.width = width; vi.height = height; vi.pixel_type = srcClip.GetVideoInfo().pixel_type; SetVideoInfo(ref vi); gradient = args[17].AsInt(gradient); noise = args[18].AsInt(noise); dynamicNoise = args[19].AsBool(dynamicNoise); overlayMode = (OverlayMode)args[20].AsInt((int)overlayMode); opacity = args[21].AsFloat(opacity); colorAdjust = (ColorAdjustMode)args[22].AsInt((int)colorAdjust); matrix = args[23].AsString(matrix); upsizeFunc = args[24].AsString(upsizeFunc); downsizeFunc = args[25].AsString(downsizeFunc); rotateFunc = args[26].AsString(rotateFunc); debug = args[27].AsBool(debug); }
protected dynamic RenderFrame(OverlayInfo info) { var src = srcClip.Dynamic(); var crop = info.GetCrop(); var over = overClip.Dynamic(); if (info.GetCrop() != RectangleF.Empty || info.Width != overSize.Width || info.Height != overSize.Height) { over = over.Invoke( info.Width > overClip.GetVideoInfo().width ? upsizeFunc : downsizeFunc, info.Width, info.Height, crop.Left, crop.Top, -crop.Right, -crop.Bottom); } var overMask = overMaskClip?.Dynamic().BilinearResize(info.Width, info.Height); var mergedWidth = srcSize.Width + Math.Max(-info.X, 0) + Math.Max(info.Width + info.X - srcSize.Width, 0); var mergedHeight = srcSize.Height + Math.Max(-info.Y, 0) + Math.Max(info.Height + info.Y - srcSize.Height, 0); var mergedAr = mergedWidth / (double)mergedHeight; var outAr = GetVideoInfo().width / (double)GetVideoInfo().height; var wider = mergedAr > outAr; if (overlayMode == OverlayMode.FitBorders) { wider = !wider; } var finalWidth = wider ? GetVideoInfo().width : (int)Math.Round(GetVideoInfo().width *(mergedAr / outAr)); var finalHeight = wider ? (int)Math.Round(GetVideoInfo().height *(outAr / mergedAr)) : GetVideoInfo().height; var finalX = wider ? 0 : (GetVideoInfo().width - finalWidth) / 2; var finalY = wider ? (GetVideoInfo().height - finalHeight) / 2 : 0; if (colorAdjust != ColorAdjustMode.None && colorAdjust != ColorAdjustMode.Average) { var clip2Adjust = colorAdjust == ColorAdjustMode.AsOverlay ? src : over; var srcTest = src.Crop(Math.Max(0, info.X), Math.Max(0, info.Y), -Math.Max(0, srcSize.Width - info.X - info.Width), -Math.Max(0, srcSize.Height - info.Y - info.Height)); var overTest = over.Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y), -Math.Max(0, -(srcSize.Width - info.X - info.Width)), -Math.Max(0, -(srcSize.Height - info.Y - info.Height))); var maskTest = srcMaskClip?.Dynamic(); if (overMask != null) { maskTest = (maskTest ?? GetBlankClip(srcClip, true).Dynamic()) .Overlay(overMask, info.X, info.Y, mode: "darken") .Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y), -Math.Max(0, -(srcSize.Width - info.X - info.Width)), -Math.Max(0, -(srcSize.Height - info.Y - info.Height))); } if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(matrix)) { srcTest = srcTest.ConvertToRgb24(matrix: matrix); overTest = overTest.ConvertToRgb24(matrix: matrix); maskTest = maskTest?.ConvertToRgb24(matrix: matrix); clip2Adjust = clip2Adjust.ConvertToRgb24(matrix: matrix); } var sample = colorAdjust == ColorAdjustMode.AsOverlay ? srcTest : overTest; var reference = colorAdjust == ColorAdjustMode.AsOverlay ? overTest : srcTest; var adjusted = clip2Adjust.ColorAdjust(sample, reference, maskTest); if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(matrix)) { adjusted = adjusted.ConvertToYV24(matrix: matrix); } if (colorAdjust == ColorAdjustMode.AsOverlay) { src = adjusted; } else { over = adjusted; } } if (colorAdjust == ColorAdjustMode.Average) { var srcTest = src.Crop(Math.Max(0, info.X), Math.Max(0, info.Y), -Math.Max(0, srcSize.Width - info.X - info.Width), -Math.Max(0, srcSize.Height - info.Y - info.Height)); var overTest = over.Crop(Math.Max(0, -info.X), Math.Max(0, -info.Y), -Math.Max(0, -(srcSize.Width - info.X - info.Width)), -Math.Max(0, -(srcSize.Height - info.Y - info.Height))); src = src.ConvertToRgb24().ColorAdjust(srcTest.ConvertToRgb24(), overTest.ConvertToRgb24()).ConvertToYV24(); srcTest = src.Crop(Math.Max(0, info.X), Math.Max(0, info.Y), -Math.Max(0, srcSize.Width - info.X - info.Width), -Math.Max(0, srcSize.Height - info.Y - info.Height)); over = over.ConvertToRgb24().ColorAdjust(overTest.ConvertToRgb24(), srcTest.ConvertToRgb24()).ConvertToYV24(); } dynamic GetOverMask(int length, bool gradientMask, bool noiseMask) { return(over.OverlayMask( left: info.X > 0 ? length : 0, top: info.Y > 0 ? length : 0, right: srcSize.Width - info.X - info.Width > 0 ? length : 0, bottom: srcSize.Height - info.Y - info.Height > 0 ? length : 0, gradient: gradientMask, noise: noiseMask, seed: dynamicNoise ? info.FrameNumber : 0)); } dynamic GetSourceMask(int length, bool gradientMask, bool noiseMask) { return(src.OverlayMask( left: info.X < 0 ? length : 0, top: info.Y < 0 ? length : 0, right: srcSize.Width - info.X - info.Width < 0 ? length : 0, bottom: srcSize.Height - info.Y - info.Height < 0 ? length : 0, gradient: gradientMask, noise: noiseMask, seed: dynamicNoise ? info.FrameNumber : 0)); } dynamic GetMask(Func <int, bool, bool, dynamic> func) { if (gradient > 0 && gradient == noise) { return(func(gradient, true, true)); } dynamic mask = null; if (gradient > 0) { mask = func(gradient, true, false); } if (noise > 0) { var noiseMask = func(noise, false, true); mask = mask == null ? noiseMask : mask.Overlay(noiseMask, mode: "darken"); } return(mask); } dynamic Rotate(dynamic clip, bool invert) => clip == null ? null : (info.Angle == 0 ? clip : clip.Invoke(rotateFunc, (invert ? -info.Angle : info.Angle) / 100.0)); switch (overlayMode) { case OverlayMode.Fit: case OverlayMode.Difference: { if (opacity < double.Epsilon) { return(src); } var mode = lumaOnly ? "luma" : "blend"; if (overlayMode == OverlayMode.Difference) { mode = "difference"; } var mask = GetMask(GetOverMask); if (overMask != null && mask != null) { mask = mask.Overlay(overMask, mode: "darken"); } if (srcMaskClip != null && mask != null) { mask = mask.Overlay(Rotate(srcMaskClip.Dynamic().Invert(), true), -info.X, -info.Y, mode: "lighten"); } if (mask == null && info.Angle != 0) { mask = ((Clip)GetBlankClip(over, true)).Dynamic(); } var hybrid = src.Overlay(Rotate(over, false), info.X, info.Y, mask: Rotate(mask, false), opacity: opacity, mode: mode); if (GetVideoInfo().width == srcSize.Width && GetVideoInfo().height == srcSize.Height) { return(hybrid); } return(hybrid.Invoke(downsizeFunc, GetVideoInfo().width, GetVideoInfo().height)); } case OverlayMode.Fill: { var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (srcMaskClip != null && maskOver != null) { maskOver = maskOver.Overlay(srcMaskClip.Dynamic().Invert().Invoke(rotateFunc, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } dynamic hybrid = src.BlankClip(width: mergedWidth, height: mergedHeight); if (opacity - 1 < double.Epsilon) { hybrid = hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y)); } else { maskSrc = null; } if (maskOver != null || opacity - 1 < double.Epsilon) { hybrid = hybrid.Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y)); } if (maskOver == null && info.Angle != 0) { maskOver = GetBlankClip(over, true); } return(hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc) .Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), opacity: opacity, mask: maskOver?.Invoke(rotateFunc, info.Angle / 100.0)) .Invoke(downsizeFunc, finalWidth, finalHeight) .AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight)); } case OverlayMode.FillRectangle: case OverlayMode.FitBorders: { var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (srcMaskClip != null && maskOver != null) { maskOver = maskOver.Overlay(srcMaskClip.Dynamic().Invert().Invoke(rotateFunc, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } var background = src.BilinearResize(mergedWidth / 3, mergedHeight / 3).Overlay(over.BilinearResize(mergedWidth / 3, mergedHeight / 3), opacity: 0.5); //TODO !!!!!!!!!! for (var i = 0; i < 15; i++) { background = background.Blur(1.5); } background = background.GaussResize(mergedWidth, mergedHeight, p: 3); if (opacity - 1 < double.Epsilon) { background = background.Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), mask: maskOver?.Invoke(rotateFunc, info.Angle / 100.0)); } var hybrid = background.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc) .Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), mask: maskOver?.Invoke(rotateFunc, info.Angle / 100.0), opacity: opacity) .Invoke(downsizeFunc, finalWidth, finalHeight); if (overlayMode == OverlayMode.FillRectangle) { return(hybrid.AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight)); } var srcRect = new Rectangle(0, 0, srcSize.Width, srcSize.Height); var overRect = new Rectangle(info.X, info.Y, info.Width, info.Height); var union = Rectangle.Union(srcRect, overRect); var intersect = Rectangle.Intersect(srcRect, overRect); var cropLeft = intersect.Left - union.Left; var cropTop = intersect.Top - union.Top; var cropRight = union.Right - intersect.Right; var cropBottom = union.Bottom - intersect.Bottom; var cropWidthCoef = cropRight == 0 ? 1 : ((double)cropLeft / cropRight) / ((double)cropLeft / cropRight + 1); var cropHeightCoef = cropBottom == 0 ? 1 : ((double)cropTop / cropBottom) / ((double)cropTop / cropBottom + 1); cropLeft = (int)((finalWidth - GetVideoInfo().width) * cropWidthCoef); cropTop = (int)((finalHeight - GetVideoInfo().height) * cropHeightCoef); cropRight = finalWidth - GetVideoInfo().width - cropLeft; cropBottom = finalHeight - GetVideoInfo().height - cropTop; return(hybrid.Crop(cropLeft, cropTop, -cropRight, -cropBottom)); } case OverlayMode.FillFull: { finalWidth = wider ? mergedWidth : (int)Math.Round(mergedHeight * outAr); finalHeight = wider ? (int)Math.Round(mergedWidth / outAr) : mergedHeight; finalX = (finalWidth - mergedWidth) / 2; finalY = (finalHeight - mergedHeight) / 2; var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (maskSrc != null && maskOver != null) { maskOver = maskOver.Overlay(maskSrc.Invert().Invoke(rotateFunc, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (srcMaskClip != null && maskOver != null) { maskOver = maskOver.Overlay(srcMaskClip.Dynamic().Invert().Invoke(rotateFunc, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } var background = over.BilinearResize(finalWidth / 4, finalHeight / 4); for (var i = 0; i < 10; i++) { background = background.Blur(1.5); } var hybrid = background.GaussResize(finalWidth, finalHeight, p: 3); if (maskOver != null) { hybrid = hybrid.Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), finalX + Math.Max(0, info.X), finalY + Math.Max(0, info.Y)); } if (maskOver == null && info.Angle != 0) { maskOver = GetBlankClip(over, true); } return(hybrid.Overlay(src, finalX + Math.Max(0, -info.X), finalY + Math.Max(0, -info.Y)) .Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), finalX + Math.Max(0, info.X), finalY + Math.Max(0, info.Y), mask: maskOver?.Invoke(rotateFunc, info.Angle / 100.0)) .Invoke(downsizeFunc, GetVideoInfo().width, GetVideoInfo().height)); } case OverlayMode.Mask: { src = GetBlankClip((Clip)src, true).Dynamic(); over = GetBlankClip((Clip)over, true).Dynamic(); return(src.BlankClip(width: mergedWidth, height: mergedHeight) .Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y)) .Overlay(over.Invoke(rotateFunc, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y)) .Invoke(downsizeFunc, finalWidth, finalHeight) .AddBorders(finalX, finalY, GetVideoInfo().width - finalX - finalWidth, GetVideoInfo().height - finalY - finalHeight)); } default: throw new AvisynthException(); } }
public void Add(OverlayInfo frame) { frames[frame.FrameNumber] = frame; ClearCache(); }
protected dynamic RenderFrame(OverlayContext ctx, OverlayInfo info) { info = info.Resize(ctx.SourceInfo.Size, ctx.OverlayInfo.Size); var src = ctx.Source; var over = ctx.Overlay; var srcSize = ctx.SourceInfo.Size; var overSize = ctx.OverlayInfo.Size; if (Mode == FramingMode.Fit && srcSize != ctx.TargetInfo.Size) { info = info.Resize(ctx.TargetInfo.Size, overSize); src = src.Invoke(srcSize.GetArea() < ctx.TargetInfo.Size.GetArea() ? Upsize : Downsize, ctx.TargetInfo.Width, ctx.TargetInfo.Height); srcSize = ctx.TargetInfo.Size; } if (Mode == FramingMode.Fit) { info = info.Shrink(srcSize, overSize); } var resizeFunc = info.Width > overSize.Width ? Upsize : Downsize; var crop = info.GetCrop(); if (!crop.IsEmpty || info.Width != overSize.Width || info.Height != overSize.Height) { over = ResizeRotate(over, resizeFunc, null, info.Width, info.Height, 0, crop); } var overMask = ctx.OverlayMask?.Dynamic().BicubicResize(info.Width, info.Height); if (ColorAdjust > -double.Epsilon && Mode != FramingMode.Mask) { Func <dynamic, bool, dynamic> adjCrop = (clp, invert) => { var sign = invert ? -1 : 1; return(clp?.Crop( Math.Max(SrcColorBorderOffset.Left, sign * (info.X + OverColorBorderOffset.Left)), Math.Max(SrcColorBorderOffset.Top, sign * (info.Y + OverColorBorderOffset.Top)), -Math.Max(SrcColorBorderOffset.Right, sign * (srcSize.Width - info.X - info.Width + OverColorBorderOffset.Right)), -Math.Max(SrcColorBorderOffset.Bottom, sign * (srcSize.Height - info.Y - info.Height + OverColorBorderOffset.Bottom)))); }; var srcTest = adjCrop(src, false); var overTest = adjCrop(over, true); var maskTest = adjCrop(ctx.SourceMask, false); if (overMask != null) { var input = (maskTest ?? GetBlankClip(src, true).Dynamic()) .Overlay(overMask, info.X, info.Y, mode: "darken"); maskTest = adjCrop(input, true); } if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(Matrix)) { srcTest = srcTest.ConvertToRgb24(matrix: Matrix); overTest = overTest.ConvertToRgb24(matrix: Matrix); maskTest = maskTest?.ConvertToRgb24(matrix: Matrix); if (ColorAdjust > double.Epsilon) { src = src.ConvertToRgb24(matrix: Matrix); } if (ColorAdjust < 1 - double.Epsilon) { over = over.ConvertToRgb24(matrix: Matrix); } } if (ColorAdjust > double.Epsilon) { src = src.ColorAdjust(srcTest, overTest, maskTest, maskTest, intensity: ColorAdjust, channels: AdjustChannels, debug: Debug, SIMD: SIMD, extrapolation: Extrapolation, dynamicNoise: DynamicNoise); if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(Matrix)) { src = src.ConvertToYV24(matrix: Matrix); } } if (ColorAdjust < 1 - double.Epsilon) { over = over.ColorAdjust(overTest, srcTest, maskTest, maskTest, intensity: 1 - ColorAdjust, channels: AdjustChannels, debug: Debug, SIMD: SIMD, extrapolation: Extrapolation, dynamicNoise: DynamicNoise); if (!GetVideoInfo().IsRGB() && !string.IsNullOrEmpty(Matrix)) { over = over.ConvertToYV24(matrix: Matrix); } } } dynamic GetOverMask(int length, bool gradientMask, bool noiseMask) { return(over.OverlayMask( left: info.X > BorderOffset.Left ? length : 0, top: info.Y > BorderOffset.Top ? length : 0, right: srcSize.Width - info.X - info.Width > BorderOffset.Right ? length : 0, bottom: srcSize.Height - info.Y - info.Height > BorderOffset.Bottom ? length : 0, gradient: gradientMask, noise: noiseMask, seed: DynamicNoise ? info.FrameNumber : 0)); } dynamic GetSourceMask(int length, bool gradientMask, bool noiseMask) { return(src.OverlayMask( //TODO BorderOffset left: info.X < 0 ? length : 0, top: info.Y < 0 ? length : 0, right: srcSize.Width - info.X - info.Width < 0 ? length : 0, bottom: srcSize.Height - info.Y - info.Height < 0 ? length : 0, gradient: gradientMask, noise: noiseMask, seed: DynamicNoise ? info.FrameNumber : 0)); } dynamic GetMask(Func <int, bool, bool, dynamic> func) { if (Gradient > 0 && Gradient == Noise) { return(func(Gradient, true, true)); } dynamic mask = null; if (Gradient > 0) { mask = func(Gradient, true, false); } if (Noise > 0) { var noiseMask = func(Noise, false, true); mask = mask == null ? noiseMask : mask.Overlay(noiseMask, mode: "darken"); } return(mask); } dynamic Rotate(dynamic clip, bool invert) => clip == null ? null : (info.Angle == 0 ? clip : clip.Invoke(this.Rotate, (invert ? -info.Angle : info.Angle) / 100.0)); dynamic GetBackground(int width, int height) { var background = src.BilinearResize(width / 3, height / 3) .Overlay(over.BilinearResize(width / 3, height / 3), opacity: (Background + 1) / 2, mask: overMask?.BilinearResize(width / 3, height / 3)); for (var i = 0; i < BackBlur; i++) { background = background.Blur(1.5); } return(background.GaussResize(width, height, p: 3)); } var frameParams = ctx.CalcFrame(info); switch (Mode) { case FramingMode.Fit: { var mask = GetMask(GetOverMask); if (overMask != null && mask != null) { mask = mask.Overlay(overMask, mode: "darken"); } if (ctx.SourceMask != null && mask != null) { mask = mask.Overlay(Rotate(ctx.SourceMask.Invert(), true), -info.X, -info.Y, mode: "lighten"); } if (mask == null && info.Angle != 0) { mask = ((Clip)GetBlankClip(over, true)).Dynamic(); } return(Opacity < double.Epsilon ? src : src.Overlay(Rotate(over, false), info.X, info.Y, mask: Rotate(mask, false), opacity: Opacity, mode: OverlayMode)); } case FramingMode.Fill: { var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (ctx.SourceMask != null && maskOver != null) { maskOver = maskOver.Overlay(ctx.SourceMask.Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } dynamic hybrid = InitClip(src, frameParams.MergedWidth, frameParams.MergedHeight, ctx.BlankColor); if (maskSrc != null || Opacity - 1 <= -double.Epsilon) { hybrid = hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y)); } if (maskOver != null || Opacity - 1 < double.Epsilon) { hybrid = hybrid.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y)); } if (maskOver == null && info.Angle != 0) { maskOver = GetBlankClip(over, true).Dynamic()?.Invoke(this.Rotate, info.Angle / 100.0); } var merged = hybrid.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc) .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), opacity: Opacity, mask: maskOver, mode: OverlayMode); var resized = merged.Invoke(Downsize, frameParams.FinalWidth, frameParams.FinalHeight); return(InitClip(src, ctx.TargetInfo.Width, ctx.TargetInfo.Height, ctx.DefaultColor) .Overlay(resized, frameParams.FinalX, frameParams.FinalY)); } case FramingMode.FillRectangle: case FramingMode.FitBorders: { var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (ctx.SourceMask != null && maskOver != null) { maskOver = maskOver.Overlay(ctx.SourceMask.Dynamic().Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } var background = GetBackground(frameParams.MergedWidth, frameParams.MergedHeight); if (Opacity - 1 <= -double.Epsilon) { background = background.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0)); } var hybrid = background.Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y), mask: maskSrc) .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), x: Math.Max(0, info.X), y: Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0), mode: OverlayMode, opacity: Opacity) .Invoke(Downsize, frameParams.FinalWidth, frameParams.FinalHeight); if (Mode == FramingMode.FillRectangle) { return(InitClip(src, ctx.TargetInfo.Width, ctx.TargetInfo.Height, ctx.BlankColor) .Overlay(hybrid, frameParams.FinalX, frameParams.FinalY)); } var srcRect = new Rectangle(0, 0, srcSize.Width, srcSize.Height); var overRect = new Rectangle(info.X, info.Y, info.Width, info.Height); var union = Rectangle.Union(srcRect, overRect); var intersect = Rectangle.Intersect(srcRect, overRect); var cropLeft = intersect.Left - union.Left; var cropTop = intersect.Top - union.Top; var cropRight = union.Right - intersect.Right; var cropBottom = union.Bottom - intersect.Bottom; var cropWidthCoef = cropRight == 0 ? 1 : ((double)cropLeft / cropRight) / ((double)cropLeft / cropRight + 1); var cropHeightCoef = cropBottom == 0 ? 1 : ((double)cropTop / cropBottom) / ((double)cropTop / cropBottom + 1); cropLeft = (int)((frameParams.FinalWidth - ctx.TargetInfo.Width) * cropWidthCoef); cropTop = (int)((frameParams.FinalHeight - ctx.TargetInfo.Height) * cropHeightCoef); cropRight = frameParams.FinalWidth - ctx.TargetInfo.Width - cropLeft; cropBottom = frameParams.FinalHeight - ctx.TargetInfo.Height - cropTop; return(hybrid.Crop(cropLeft, cropTop, -cropRight, -cropBottom)); } case FramingMode.FillFull: { frameParams.FinalWidth = !frameParams.Wider ? frameParams.MergedWidth : (int)Math.Round(frameParams.MergedHeight * frameParams.OutAr); frameParams.FinalHeight = !frameParams.Wider ? (int)Math.Round(frameParams.MergedWidth / frameParams.OutAr) : frameParams.MergedHeight; frameParams.FinalX = (frameParams.FinalWidth - frameParams.MergedWidth) / 2; frameParams.FinalY = (frameParams.FinalHeight - frameParams.MergedHeight) / 2; var maskOver = GetMask(GetOverMask); var maskSrc = GetMask(GetSourceMask); if (maskSrc != null && maskOver != null) { maskOver = maskOver.Overlay(maskSrc.Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } if (overMask != null && maskOver != null) { maskOver = maskOver.Overlay(overMask, mode: "darken"); } if (ctx.SourceMask != null && maskOver != null) { maskOver = maskOver.Overlay(ctx.SourceMask.Dynamic().Invert().Invoke(this.Rotate, -info.Angle / 100.0), -info.X, -info.Y, mode: "lighten"); } var hybrid = GetBackground(frameParams.FinalWidth, frameParams.FinalHeight); if (maskOver != null) { hybrid = hybrid.Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), frameParams.FinalX + Math.Max(0, info.X), frameParams.FinalY + Math.Max(0, info.Y)); } if (maskOver == null && info.Angle != 0) { maskOver = GetBlankClip(over, true).Dynamic(); } return(hybrid.Overlay(src, frameParams.FinalX + Math.Max(0, -info.X), frameParams.FinalY + Math.Max(0, -info.Y)) .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), frameParams.FinalX + Math.Max(0, info.X), frameParams.FinalY + Math.Max(0, info.Y), mask: maskOver?.Invoke(this.Rotate, info.Angle / 100.0)) .Invoke(Downsize, ctx.TargetInfo.Width, ctx.TargetInfo.Height)); } case FramingMode.Mask: { if (ctx.Plane.IsChroma()) { return(InitClip(src, ctx.TargetInfo.Width, ctx.TargetInfo.Height, ctx.DefaultColor)); } src = GetBlankClip((Clip)src, true).Dynamic(); if (ctx.SourceMask != null) { src = src.Overlay(ctx.SourceMask, mode: "darken"); } over = GetBlankClip((Clip)over, true).Dynamic(); return(InitClip(src, frameParams.MergedWidth, frameParams.MergedHeight, ctx.DefaultColor) .Overlay(src, Math.Max(0, -info.X), Math.Max(0, -info.Y)) .Overlay(over.Invoke(this.Rotate, info.Angle / 100.0), Math.Max(0, info.X), Math.Max(0, info.Y)) .Invoke(Downsize, frameParams.FinalWidth, frameParams.FinalHeight) .ColorRangeMask((1 << ctx.TargetInfo.ColorSpace.GetBitDepth()) - 1) .AddBorders(frameParams.FinalX, frameParams.FinalY, ctx.TargetInfo.Width - frameParams.FinalX - frameParams.FinalWidth, ctx.TargetInfo.Height - frameParams.FinalY - frameParams.FinalHeight)); } default: throw new AvisynthException(); } }
public dynamic ResizeRotate(Clip clip, string resizeFunc, string rotateFunc, OverlayInfo info) { return(ResizeRotate(clip, resizeFunc, rotateFunc, info.Width, info.Height, info.Angle, info.GetCrop(), info.Warp)); }
protected override OverlayInfo GetOverlayInfo(int n) { using (var infoFrame = Child.GetFrame(n, StaticEnv)) return(OverlayInfo.FromFrame(infoFrame)); }
protected override List <OverlayInfo> GetOverlayInfo(int n) { using var frame = Child.GetFrame(n, StaticEnv); return(OverlayInfo.FromFrame(frame)); }