add watermark opacity (#259)

This commit is contained in:
Jason Dove
2021-06-13 20:45:23 -05:00
committed by GitHub
parent 0fb5bfde58
commit 679feb6d21
15 changed files with 3027 additions and 13 deletions
+3
View File
@@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
- Add watermark opacity setting to allow blending with content
### Changed
- Remove unused API and SDK project; may reintroduce in the future but for now they have fallen out of date
@@ -17,5 +17,6 @@ namespace ErsatzTV.Application.Channels
int WatermarkHorizontalMargin,
int WatermarkVerticalMargin,
int WatermarkFrequencyMinutes,
int WatermarkDurationSeconds);
int WatermarkDurationSeconds,
int WatermarkOpacity);
}
@@ -20,5 +20,6 @@ namespace ErsatzTV.Application.Channels.Commands
int WatermarkHorizontalMargin,
int WatermarkVerticalMargin,
int WatermarkFrequencyMinutes,
int WatermarkDurationSeconds) : IRequest<Either<BaseError, CreateChannelResult>>;
int WatermarkDurationSeconds,
int WatermarkOpacity) : IRequest<Either<BaseError, CreateChannelResult>>;
}
@@ -79,7 +79,8 @@ namespace ErsatzTV.Application.Channels.Commands
HorizontalMarginPercent = request.WatermarkHorizontalMargin,
VerticalMarginPercent = request.WatermarkVerticalMargin,
FrequencyMinutes = request.WatermarkFrequencyMinutes,
DurationSeconds = request.WatermarkDurationSeconds
DurationSeconds = request.WatermarkDurationSeconds,
Opacity = request.WatermarkOpacity
};
}
@@ -21,5 +21,6 @@ namespace ErsatzTV.Application.Channels.Commands
int WatermarkHorizontalMargin,
int WatermarkVerticalMargin,
int WatermarkFrequencyMinutes,
int WatermarkDurationSeconds) : IRequest<Either<BaseError, ChannelViewModel>>;
int WatermarkDurationSeconds,
int WatermarkOpacity) : IRequest<Either<BaseError, ChannelViewModel>>;
}
@@ -77,6 +77,7 @@ namespace ErsatzTV.Application.Channels.Commands
c.Watermark.VerticalMarginPercent = update.WatermarkVerticalMargin;
c.Watermark.FrequencyMinutes = update.WatermarkFrequencyMinutes;
c.Watermark.DurationSeconds = update.WatermarkDurationSeconds;
c.Watermark.Opacity = update.WatermarkOpacity;
}
else
{
@@ -89,7 +90,8 @@ namespace ErsatzTV.Application.Channels.Commands
HorizontalMarginPercent = update.WatermarkHorizontalMargin,
VerticalMarginPercent = update.WatermarkVerticalMargin,
FrequencyMinutes = update.WatermarkFrequencyMinutes,
DurationSeconds = update.WatermarkDurationSeconds
DurationSeconds = update.WatermarkDurationSeconds,
Opacity = update.WatermarkOpacity
};
}
}
+2 -1
View File
@@ -22,7 +22,8 @@ namespace ErsatzTV.Application.Channels
channel.Watermark?.HorizontalMarginPercent ?? 5,
channel.Watermark?.VerticalMarginPercent ?? 5,
channel.Watermark?.FrequencyMinutes ?? 15,
channel.Watermark?.DurationSeconds ?? 15);
channel.Watermark?.DurationSeconds ?? 15,
channel.Watermark?.Opacity ?? 100);
private static string GetLogo(Channel channel) =>
Optional(channel.Artwork.FirstOrDefault(a => a.ArtworkKind == ArtworkKind.Logo))
+1
View File
@@ -12,6 +12,7 @@
public int VerticalMarginPercent { get; set; }
public int FrequencyMinutes { get; set; }
public int DurationSeconds { get; set; }
public int Opacity { get; set; }
}
public enum ChannelWatermarkLocation
@@ -88,7 +88,7 @@ namespace ErsatzTV.Core.FFmpeg
var audioFilterQueue = new List<string>();
var videoFilterQueue = new List<string>();
string watermarkScale = string.Empty;
string watermarkPreprocess = string.Empty;
string watermarkOverlay = string.Empty;
if (_normalizeLoudness)
@@ -180,7 +180,20 @@ namespace ErsatzTV.Core.FFmpeg
if (watermark.Size == ChannelWatermarkSize.Scaled)
{
double width = Math.Round(watermark.WidthPercent / 100.0 * _resolution.Width);
watermarkScale = $"scale={width}:-1";
watermarkPreprocess = $"scale={width}:-1";
}
if (watermark.Opacity != 100)
{
const string FORMATS = "yuva420p|yuva444p|yuva422p|rgba|abgr|bgra|gbrap|ya8";
string join = string.Empty;
double opacity = watermark.Opacity / 100.0;
if (!string.IsNullOrWhiteSpace(watermarkPreprocess))
{
join = ",";
}
watermarkPreprocess = $"format={FORMATS},colorchannelmixer=aa={opacity:F2}{join}{watermarkPreprocess}";
}
watermarkOverlay = $"overlay={position}{enable}";
@@ -224,10 +237,10 @@ namespace ErsatzTV.Core.FFmpeg
{
complexFilter.Append("[vt]");
var watermarkLabel = "[1:v]";
if (!string.IsNullOrWhiteSpace(watermarkScale))
if (!string.IsNullOrWhiteSpace(watermarkPreprocess))
{
complexFilter.Append($";{watermarkLabel}{watermarkScale}[wms]");
watermarkLabel = "[wms]";
complexFilter.Append($";{watermarkLabel}{watermarkPreprocess}[wmp]");
watermarkLabel = "[wmp]";
}
complexFilter.Append($";[vt]{watermarkLabel}{watermarkOverlay}");
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_ChannelWatermarkOpacity : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Opacity",
table: "ChannelWatermark",
type: "INTEGER",
nullable: false,
defaultValue: 100);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Opacity",
table: "ChannelWatermark");
}
}
}
@@ -240,6 +240,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<int>("Mode")
.HasColumnType("INTEGER");
b.Property<int>("Opacity")
.HasColumnType("INTEGER");
b.Property<int>("Size")
.HasColumnType("INTEGER");
+13
View File
@@ -141,6 +141,17 @@
Immediate="true"/>
</MudItem>
</MudGrid>
<MudGrid Class="mt-3" Style="align-items: start" Justify="Justify.Center">
<MudItem xs="6">
<MudTextField Label="Opacity" @bind-Value="_model.WatermarkOpacity"
For="@(() => _model.WatermarkOpacity)"
Adornment="Adornment.End"
AdornmentText="%"
Disabled="@(_model.StreamingMode == StreamingMode.HttpLiveStreamingDirect || _model.WatermarkMode == ChannelWatermarkMode.None)"
Immediate="true"/>
</MudItem>
<MudItem xs="6" />
</MudGrid>
</MudCardContent>
<MudCardActions>
<MudButton ButtonType="ButtonType.Submit" Variant="Variant.Filled" Color="Color.Primary">
@@ -190,6 +201,7 @@
_model.WatermarkVerticalMargin = channelViewModel.WatermarkVerticalMargin;
_model.WatermarkFrequencyMinutes = channelViewModel.WatermarkFrequencyMinutes;
_model.WatermarkDurationSeconds = channelViewModel.WatermarkDurationSeconds;
_model.WatermarkOpacity = channelViewModel.WatermarkOpacity;
},
() => _navigationManager.NavigateTo("404"));
}
@@ -213,6 +225,7 @@
_model.WatermarkVerticalMargin = 5;
_model.WatermarkFrequencyMinutes = 15;
_model.WatermarkDurationSeconds = 15;
_model.WatermarkOpacity = 100;
}
}
@@ -49,6 +49,11 @@ namespace ErsatzTV.Validators
.GreaterThan(0)
.LessThan(c => c.WatermarkFrequencyMinutes * 60)
.When(vm => vm.WatermarkMode != ChannelWatermarkMode.None);
RuleFor(x => x.WatermarkOpacity)
.GreaterThan(0)
.LessThanOrEqualTo(100)
.When(vm => vm.WatermarkMode != ChannelWatermarkMode.None);
}
}
}
+5 -2
View File
@@ -20,6 +20,7 @@ namespace ErsatzTV.ViewModels
public int WatermarkVerticalMargin { get; set; }
public int WatermarkFrequencyMinutes { get; set; }
public int WatermarkDurationSeconds { get; set; }
public int WatermarkOpacity { get; set; }
public UpdateChannel ToUpdate() =>
new(
@@ -37,7 +38,8 @@ namespace ErsatzTV.ViewModels
WatermarkHorizontalMargin,
WatermarkVerticalMargin,
WatermarkFrequencyMinutes,
WatermarkDurationSeconds);
WatermarkDurationSeconds,
WatermarkOpacity);
public CreateChannel ToCreate() =>
new(
@@ -54,6 +56,7 @@ namespace ErsatzTV.ViewModels
WatermarkHorizontalMargin,
WatermarkVerticalMargin,
WatermarkFrequencyMinutes,
WatermarkDurationSeconds);
WatermarkDurationSeconds,
WatermarkOpacity);
}
}