Stream custom live channels using your own media
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

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);
}