* cleanup scanner project * cleanup infrastructure projects * cleanup ffmpeg project * cleanup core project * cleanup app project * cleanup main project * update dependencies * code cleanup
85 lines
3.5 KiB
C#
85 lines
3.5 KiB
C#
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);
|
|
}
|