mirror of https://github.com/ErsatzTV/ErsatzTV.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
3.5 KiB
84 lines
3.5 KiB
using ErsatzTV.FFmpeg.Format; |
|
using ErsatzTV.FFmpeg.State; |
|
using Microsoft.Extensions.Logging; |
|
|
|
namespace ErsatzTV.FFmpeg.Filter; |
|
|
|
public class OverlayWatermarkFilter : BaseFilter |
|
{ |
|
private readonly ILogger _logger; |
|
private readonly IPixelFormat _outputPixelFormat; |
|
private readonly FrameSize _resolution; |
|
private readonly FrameSize _squarePixelFrameSize; |
|
private readonly WatermarkState _watermarkState; |
|
|
|
public OverlayWatermarkFilter( |
|
WatermarkState watermarkState, |
|
FrameSize resolution, |
|
FrameSize squarePixelFrameSize, |
|
IPixelFormat outputPixelFormat, |
|
ILogger logger) |
|
{ |
|
_watermarkState = watermarkState; |
|
_resolution = resolution; |
|
_squarePixelFrameSize = squarePixelFrameSize; |
|
_outputPixelFormat = outputPixelFormat; |
|
_logger = logger; |
|
} |
|
|
|
public override string Filter => $"overlay={Position}:format={(_outputPixelFormat.BitDepth == 10 ? '1' : '0')}"; |
|
|
|
protected string Position |
|
{ |
|
get |
|
{ |
|
(double horizontalMargin, double verticalMargin) = _watermarkState.PlaceWithinSourceContent |
|
? SourceContentMargins() |
|
: NormalMargins(); |
|
|
|
return _watermarkState.Location switch |
|
{ |
|
// TODO: can these be pre-calculated (and used with accelerated overlay filters) |
|
WatermarkLocation.BottomLeft => $"x={horizontalMargin}:y=H-h-{verticalMargin}", |
|
WatermarkLocation.TopLeft => $"x={horizontalMargin}:y={verticalMargin}", |
|
WatermarkLocation.TopRight => $"x=W-w-{horizontalMargin}:y={verticalMargin}", |
|
WatermarkLocation.TopMiddle => $"x=(W-w)/2:y={verticalMargin}", |
|
WatermarkLocation.RightMiddle => $"x=W-w-{horizontalMargin}:y=(H-h)/2", |
|
WatermarkLocation.BottomMiddle => $"x=(W-w)/2:y=H-h-{verticalMargin}", |
|
WatermarkLocation.LeftMiddle => $"x={horizontalMargin}:y=(H-h)/2", |
|
_ => $"x=W-w-{horizontalMargin}:y=H-h-{verticalMargin}" |
|
}; |
|
} |
|
} |
|
|
|
public override FrameState NextState(FrameState currentState) => |
|
currentState with { FrameDataLocation = FrameDataLocation.Software }; |
|
|
|
private WatermarkMargins NormalMargins() |
|
{ |
|
double horizontalMargin = Math.Round(_watermarkState.HorizontalMarginPercent / 100.0 * _resolution.Width); |
|
double verticalMargin = Math.Round(_watermarkState.VerticalMarginPercent / 100.0 * _resolution.Height); |
|
|
|
return new WatermarkMargins(horizontalMargin, verticalMargin); |
|
} |
|
|
|
private WatermarkMargins SourceContentMargins() |
|
{ |
|
int horizontalPadding = _resolution.Width - _squarePixelFrameSize.Width; |
|
int verticalPadding = _resolution.Height - _squarePixelFrameSize.Height; |
|
|
|
_logger.LogDebug("Resolution: {Width}x{Height}", _resolution.Width, _resolution.Height); |
|
_logger.LogDebug("Square Pix: {Width}x{Height}", _squarePixelFrameSize.Width, _squarePixelFrameSize.Height); |
|
|
|
double horizontalMargin = Math.Round( |
|
_watermarkState.HorizontalMarginPercent / 100.0 * _squarePixelFrameSize.Width |
|
+ horizontalPadding / 2.0); |
|
double verticalMargin = Math.Round( |
|
_watermarkState.VerticalMarginPercent / 100.0 * _squarePixelFrameSize.Height |
|
+ verticalPadding / 2.0); |
|
|
|
return new WatermarkMargins(horizontalMargin, verticalMargin); |
|
} |
|
|
|
private sealed record WatermarkMargins(double HorizontalMargin, double VerticalMargin); |
|
}
|
|
|