remove framerate normalization (#253)
This commit is contained in:
@@ -8,6 +8,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
- Add experimental `HLS Hybrid` channel mode
|
- Add experimental `HLS Hybrid` channel mode
|
||||||
- Media items are transcoded using the channel's ffmpeg profile and served using HLS
|
- Media items are transcoded using the channel's ffmpeg profile and served using HLS
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- Remove framerate normalization; it caused more problems than it solved
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fix serving channels.m3u with missing content ratings
|
- Fix serving channels.m3u with missing content ratings
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,5 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
|
|||||||
bool NormalizeLoudness,
|
bool NormalizeLoudness,
|
||||||
int AudioChannels,
|
int AudioChannels,
|
||||||
int AudioSampleRate,
|
int AudioSampleRate,
|
||||||
bool NormalizeAudio,
|
bool NormalizeAudio) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
|
||||||
string FrameRate) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,8 +53,7 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
|
|||||||
NormalizeLoudness = request.NormalizeLoudness,
|
NormalizeLoudness = request.NormalizeLoudness,
|
||||||
AudioChannels = request.AudioChannels,
|
AudioChannels = request.AudioChannels,
|
||||||
AudioSampleRate = request.AudioSampleRate,
|
AudioSampleRate = request.AudioSampleRate,
|
||||||
NormalizeAudio = request.NormalizeAudio,
|
NormalizeAudio = request.NormalizeAudio
|
||||||
FrameRate = request.FrameRate
|
|
||||||
});
|
});
|
||||||
|
|
||||||
private Validation<BaseError, string> ValidateName(CreateFFmpegProfile createFFmpegProfile) =>
|
private Validation<BaseError, string> ValidateName(CreateFFmpegProfile createFFmpegProfile) =>
|
||||||
|
|||||||
@@ -22,6 +22,5 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
|
|||||||
bool NormalizeLoudness,
|
bool NormalizeLoudness,
|
||||||
int AudioChannels,
|
int AudioChannels,
|
||||||
int AudioSampleRate,
|
int AudioSampleRate,
|
||||||
bool NormalizeAudio,
|
bool NormalizeAudio) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
|
||||||
string FrameRate) : IRequest<Either<BaseError, FFmpegProfileViewModel>>;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ namespace ErsatzTV.Application.FFmpegProfiles.Commands
|
|||||||
p.AudioChannels = update.AudioChannels;
|
p.AudioChannels = update.AudioChannels;
|
||||||
p.AudioSampleRate = update.AudioSampleRate;
|
p.AudioSampleRate = update.AudioSampleRate;
|
||||||
p.NormalizeAudio = update.NormalizeAudio;
|
p.NormalizeAudio = update.NormalizeAudio;
|
||||||
p.FrameRate = update.FrameRate;
|
|
||||||
await _ffmpegProfileRepository.Update(p);
|
await _ffmpegProfileRepository.Update(p);
|
||||||
return ProjectToViewModel(p);
|
return ProjectToViewModel(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,5 @@ namespace ErsatzTV.Application.FFmpegProfiles
|
|||||||
bool NormalizeLoudness,
|
bool NormalizeLoudness,
|
||||||
int AudioChannels,
|
int AudioChannels,
|
||||||
int AudioSampleRate,
|
int AudioSampleRate,
|
||||||
bool NormalizeAudio,
|
bool NormalizeAudio);
|
||||||
string FrameRate);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ namespace ErsatzTV.Application.FFmpegProfiles
|
|||||||
profile.NormalizeLoudness,
|
profile.NormalizeLoudness,
|
||||||
profile.AudioChannels,
|
profile.AudioChannels,
|
||||||
profile.AudioSampleRate,
|
profile.AudioSampleRate,
|
||||||
profile.NormalizeAudio,
|
profile.NormalizeAudio);
|
||||||
profile.FrameRate);
|
|
||||||
|
|
||||||
private static ResolutionViewModel Project(Resolution resolution) =>
|
private static ResolutionViewModel Project(Resolution resolution) =>
|
||||||
new(resolution.Id, resolution.Name, resolution.Width, resolution.Height);
|
new(resolution.Id, resolution.Name, resolution.Width, resolution.Height);
|
||||||
|
|||||||
@@ -467,36 +467,6 @@ namespace ErsatzTV.Core.Tests.FFmpeg
|
|||||||
actual.VideoCodec.Should().Be("copy");
|
actual.VideoCodec.Should().Be("copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void
|
|
||||||
Should_SetCorrectVideoCodec_When_ContentIsCorrectSize_And_CorrectCodec_And_Framerate_ForTransportStream()
|
|
||||||
{
|
|
||||||
var ffmpegProfile = new FFmpegProfile
|
|
||||||
{
|
|
||||||
NormalizeVideo = true,
|
|
||||||
Resolution = new Resolution { Width = 1920, Height = 1080 },
|
|
||||||
VideoCodec = "libx264",
|
|
||||||
FrameRate = "24"
|
|
||||||
};
|
|
||||||
|
|
||||||
// not anamorphic
|
|
||||||
var version = new MediaVersion
|
|
||||||
{ Width = 1920, Height = 1080, SampleAspectRatio = "1:1" };
|
|
||||||
|
|
||||||
FFmpegPlaybackSettings actual = _calculator.CalculateSettings(
|
|
||||||
StreamingMode.TransportStream,
|
|
||||||
ffmpegProfile,
|
|
||||||
version,
|
|
||||||
new MediaStream { Codec = "libx264" },
|
|
||||||
new MediaStream(),
|
|
||||||
DateTimeOffset.Now,
|
|
||||||
DateTimeOffset.Now);
|
|
||||||
|
|
||||||
actual.ScaledSize.IsNone.Should().BeTrue();
|
|
||||||
actual.PadToDesiredResolution.Should().BeFalse();
|
|
||||||
actual.VideoCodec.Should().Be("libx264");
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void
|
public void
|
||||||
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NotNormalizingVideo_ForTransportStream()
|
Should_SetCopyVideoCodec_When_ContentIsCorrectSize_And_NotNormalizingVideo_ForTransportStream()
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
public bool NormalizeVideo { get; set; }
|
public bool NormalizeVideo { get; set; }
|
||||||
public int VideoBitrate { get; set; }
|
public int VideoBitrate { get; set; }
|
||||||
public int VideoBufferSize { get; set; }
|
public int VideoBufferSize { get; set; }
|
||||||
public string FrameRate { get; set; }
|
|
||||||
public string AudioCodec { get; set; }
|
public string AudioCodec { get; set; }
|
||||||
public int AudioBitrate { get; set; }
|
public int AudioBitrate { get; set; }
|
||||||
public int AudioBufferSize { get; set; }
|
public int AudioBufferSize { get; set; }
|
||||||
@@ -40,7 +39,6 @@
|
|||||||
AudioChannels = 2,
|
AudioChannels = 2,
|
||||||
AudioSampleRate = 48,
|
AudioSampleRate = 48,
|
||||||
NormalizeVideo = true,
|
NormalizeVideo = true,
|
||||||
FrameRate = "24",
|
|
||||||
NormalizeAudio = true
|
NormalizeAudio = true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
{
|
{
|
||||||
private Option<TimeSpan> _audioDuration = None;
|
private Option<TimeSpan> _audioDuration = None;
|
||||||
private bool _deinterlace;
|
private bool _deinterlace;
|
||||||
private Option<string> _frameRate = None;
|
|
||||||
private Option<HardwareAccelerationKind> _hardwareAccelerationKind = None;
|
private Option<HardwareAccelerationKind> _hardwareAccelerationKind = None;
|
||||||
private string _inputCodec;
|
private string _inputCodec;
|
||||||
private bool _normalizeLoudness;
|
private bool _normalizeLoudness;
|
||||||
@@ -62,12 +61,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FFmpegComplexFilterBuilder WithFrameRate(Option<string> frameRate)
|
|
||||||
{
|
|
||||||
_frameRate = frameRate;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Option<FFmpegComplexFilter> Build(int videoStreamIndex, Option<int> audioStreamIndex)
|
public Option<FFmpegComplexFilter> Build(int videoStreamIndex, Option<int> audioStreamIndex)
|
||||||
{
|
{
|
||||||
var complexFilter = new StringBuilder();
|
var complexFilter = new StringBuilder();
|
||||||
@@ -118,8 +111,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_frameRate.IfSome(frameRate => videoFilterQueue.Add($"fps=fps={frameRate}"));
|
|
||||||
|
|
||||||
_scaleToSize.IfSome(
|
_scaleToSize.IfSome(
|
||||||
size =>
|
size =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
public Option<TimeSpan> AudioDuration { get; set; }
|
public Option<TimeSpan> AudioDuration { get; set; }
|
||||||
public string AudioCodec { get; set; }
|
public string AudioCodec { get; set; }
|
||||||
public bool Deinterlace { get; set; }
|
public bool Deinterlace { get; set; }
|
||||||
public Option<string> FrameRate { get; set; }
|
|
||||||
public Option<int> VideoTrackTimeScale { get; set; }
|
public Option<int> VideoTrackTimeScale { get; set; }
|
||||||
public bool NormalizeLoudness { get; set; }
|
public bool NormalizeLoudness { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,15 +92,11 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
|
|
||||||
if (ffmpegProfile.NormalizeVideo)
|
if (ffmpegProfile.NormalizeVideo)
|
||||||
{
|
{
|
||||||
result.FrameRate = string.IsNullOrWhiteSpace(ffmpegProfile.FrameRate)
|
|
||||||
? None
|
|
||||||
: Some(ffmpegProfile.FrameRate);
|
|
||||||
|
|
||||||
result.VideoTrackTimeScale = 90000;
|
result.VideoTrackTimeScale = 90000;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.ScaledSize.IsSome || result.PadToDesiredResolution ||
|
if (result.ScaledSize.IsSome || result.PadToDesiredResolution ||
|
||||||
NeedToNormalizeVideoCodec(ffmpegProfile, videoStream) || result.FrameRate.IsSome)
|
NeedToNormalizeVideoCodec(ffmpegProfile, videoStream))
|
||||||
{
|
{
|
||||||
result.VideoCodec = ffmpegProfile.VideoCodec;
|
result.VideoCodec = ffmpegProfile.VideoCodec;
|
||||||
result.VideoBitrate = ffmpegProfile.VideoBitrate;
|
result.VideoBitrate = ffmpegProfile.VideoBitrate;
|
||||||
|
|||||||
@@ -332,12 +332,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FFmpegProcessBuilder WithFrameRate(Option<string> frameRate)
|
|
||||||
{
|
|
||||||
_complexFilterBuilder = _complexFilterBuilder.WithFrameRate(frameRate);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FFmpegProcessBuilder WithVideoTrackTimeScale(Option<int> videoTrackTimeScale)
|
public FFmpegProcessBuilder WithVideoTrackTimeScale(Option<int> videoTrackTimeScale)
|
||||||
{
|
{
|
||||||
videoTrackTimeScale.IfSome(
|
videoTrackTimeScale.IfSome(
|
||||||
|
|||||||
@@ -50,7 +50,6 @@ namespace ErsatzTV.Core.FFmpeg
|
|||||||
.WithRealtimeOutput(playbackSettings.RealtimeOutput)
|
.WithRealtimeOutput(playbackSettings.RealtimeOutput)
|
||||||
.WithSeek(playbackSettings.StreamSeek)
|
.WithSeek(playbackSettings.StreamSeek)
|
||||||
.WithInputCodec(path, playbackSettings.HardwareAcceleration, videoStream.Codec)
|
.WithInputCodec(path, playbackSettings.HardwareAcceleration, videoStream.Codec)
|
||||||
.WithFrameRate(playbackSettings.FrameRate)
|
|
||||||
.WithVideoTrackTimeScale(playbackSettings.VideoTrackTimeScale)
|
.WithVideoTrackTimeScale(playbackSettings.VideoTrackTimeScale)
|
||||||
.WithAlignedAudio(playbackSettings.AudioDuration)
|
.WithAlignedAudio(playbackSettings.AudioDuration)
|
||||||
.WithNormalizeLoudness(playbackSettings.NormalizeLoudness);
|
.WithNormalizeLoudness(playbackSettings.NormalizeLoudness);
|
||||||
|
|||||||
Generated
+2886
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace ErsatzTV.Infrastructure.Migrations
|
||||||
|
{
|
||||||
|
public partial class Remove_FFmpegProfileFrameRate : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "FrameRate",
|
||||||
|
table: "FFmpegProfile");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "FrameRate",
|
||||||
|
table: "FFmpegProfile",
|
||||||
|
type: "TEXT",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -406,9 +406,6 @@ namespace ErsatzTV.Infrastructure.Migrations
|
|||||||
b.Property<int>("AudioSampleRate")
|
b.Property<int>("AudioSampleRate")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
b.Property<string>("FrameRate")
|
|
||||||
.HasColumnType("TEXT");
|
|
||||||
|
|
||||||
b.Property<int>("HardwareAcceleration")
|
b.Property<int>("HardwareAcceleration")
|
||||||
.HasColumnType("INTEGER");
|
.HasColumnType("INTEGER");
|
||||||
|
|
||||||
|
|||||||
@@ -58,9 +58,6 @@
|
|||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
</MudElement>
|
</MudElement>
|
||||||
<MudElement HtmlTag="div" Class="mt-3">
|
|
||||||
<MudTextField Disabled="@(!_model.Transcode)" Label="Frame Rate" @bind-Value="_model.FrameRate" For="@(() => _model.FrameRate)" Adornment="Adornment.End" AdornmentText="fps"/>
|
|
||||||
</MudElement>
|
|
||||||
<MudElement HtmlTag="div" Class="mt-3">
|
<MudElement HtmlTag="div" Class="mt-3">
|
||||||
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Video" @bind-Checked="@_model.NormalizeVideo" For="@(() => _model.NormalizeVideo)"/>
|
<MudCheckBox Disabled="@(!_model.Transcode)" Label="Normalize Video" @bind-Checked="@_model.NormalizeVideo" For="@(() => _model.NormalizeVideo)"/>
|
||||||
</MudElement>
|
</MudElement>
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ namespace ErsatzTV.ViewModels
|
|||||||
VideoBitrate = viewModel.VideoBitrate;
|
VideoBitrate = viewModel.VideoBitrate;
|
||||||
VideoBufferSize = viewModel.VideoBufferSize;
|
VideoBufferSize = viewModel.VideoBufferSize;
|
||||||
VideoCodec = viewModel.VideoCodec;
|
VideoCodec = viewModel.VideoCodec;
|
||||||
FrameRate = viewModel.FrameRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int AudioBitrate { get; set; }
|
public int AudioBitrate { get; set; }
|
||||||
@@ -50,7 +49,6 @@ namespace ErsatzTV.ViewModels
|
|||||||
public int VideoBitrate { get; set; }
|
public int VideoBitrate { get; set; }
|
||||||
public int VideoBufferSize { get; set; }
|
public int VideoBufferSize { get; set; }
|
||||||
public string VideoCodec { get; set; }
|
public string VideoCodec { get; set; }
|
||||||
public string FrameRate { get; set; }
|
|
||||||
|
|
||||||
public CreateFFmpegProfile ToCreate() =>
|
public CreateFFmpegProfile ToCreate() =>
|
||||||
new(
|
new(
|
||||||
@@ -69,8 +67,7 @@ namespace ErsatzTV.ViewModels
|
|||||||
NormalizeLoudness,
|
NormalizeLoudness,
|
||||||
AudioChannels,
|
AudioChannels,
|
||||||
AudioSampleRate,
|
AudioSampleRate,
|
||||||
NormalizeAudio,
|
NormalizeAudio
|
||||||
FrameRate
|
|
||||||
);
|
);
|
||||||
|
|
||||||
public UpdateFFmpegProfile ToUpdate() =>
|
public UpdateFFmpegProfile ToUpdate() =>
|
||||||
@@ -91,8 +88,7 @@ namespace ErsatzTV.ViewModels
|
|||||||
NormalizeLoudness,
|
NormalizeLoudness,
|
||||||
AudioChannels,
|
AudioChannels,
|
||||||
AudioSampleRate,
|
AudioSampleRate,
|
||||||
NormalizeAudio,
|
NormalizeAudio
|
||||||
FrameRate
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user