Browse Source

add software tonemap filter to support hdr content (#2027)

pull/2029/head
Jason Dove 2 weeks ago committed by GitHub
parent
commit
5fe3e97b31
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 2
      ErsatzTV.FFmpeg/Filter/TonemapFilter.cs
  3. 4
      ErsatzTV.FFmpeg/MediaStream.cs
  4. 2
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs
  5. 15
      ErsatzTV.FFmpeg/Pipeline/PipelineBuilderFactory.cs
  6. 21
      ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs

2
CHANGELOG.md

@ -22,6 +22,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -22,6 +22,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- As an example, if the current scheduling time is 6:02 AM and the next schedule item has a fixed start time of 6:00 AM
- `Strict` will add nearly 24h (23:58) of unscheduled time so that it can start exactly at 6:00 AM the next day
- `Flexible` will NOT add unscheduled time, and will schedule its item at 6:02 AM (which may also affect the scheduling of later items)
- Add basic HDR transcoding support
- For this initial implementation, HDR content will *always* use a software pipeline
### Changed
- Start to make UI minimally responsive (functional on smaller screens)

2
ErsatzTV.FFmpeg/Filter/TonemapFilter.cs

@ -20,7 +20,7 @@ public class TonemapFilter : BaseFilter @@ -20,7 +20,7 @@ public class TonemapFilter : BaseFilter
string pixelFormat = _currentState.PixelFormat.Match(pf => pf.FFmpegName, () => string.Empty);
var tonemap =
$"setparams=colorspace=bt2020c,zscale=transfer=linear,tonemap=hable,zscale=transfer=bt709,format={_desiredPixelFormat.FFmpegName}";
$"zscale=transfer=linear,tonemap=hable,zscale=transfer=bt709,format={_desiredPixelFormat.FFmpegName}";
if (_currentState.FrameDataLocation == FrameDataLocation.Hardware)
{

4
ErsatzTV.FFmpeg/MediaStream.cs

@ -30,6 +30,8 @@ public record VideoStream( @@ -30,6 +30,8 @@ public record VideoStream(
Codec,
StreamKind.Video)
{
public ColorParams ColorParams { get; private set; } = ColorParams;
public int BitDepth => PixelFormat.Map(pf => pf.BitDepth).IfNone(8);
public string SampleAspectRatio
@ -152,6 +154,8 @@ public record VideoStream( @@ -152,6 +154,8 @@ public record VideoStream(
return result;
}
public void ResetColorParams(ColorParams colorParams) => ColorParams = colorParams;
private double GetSAR()
{
// some media servers don't provide sample aspect ratio so we have to calculate it

2
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -307,7 +307,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -307,7 +307,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
// clearing color params will force it to be re-added
if (videoStream.Codec == "vp9")
{
videoStream = videoStream with { ColorParams = ColorParams.Unknown };
videoStream.ResetColorParams(ColorParams.Unknown);
}
if (!videoStream.ColorParams.IsBt709)

15
ErsatzTV.FFmpeg/Pipeline/PipelineBuilderFactory.cs

@ -40,8 +40,23 @@ public class PipelineBuilderFactory : IPipelineBuilderFactory @@ -40,8 +40,23 @@ public class PipelineBuilderFactory : IPipelineBuilderFactory
vaapiDriver,
vaapiDevice);
bool isHdrContent = videoInputFile.Any(vif => vif.VideoStreams.Any(vs => vs.ColorParams.IsHdr));
return hardwareAccelerationMode switch
{
// force software pipeline when content is HDR
_ when isHdrContent => new SoftwarePipelineBuilder(
ffmpegCapabilities,
HardwareAccelerationMode.None,
videoInputFile,
audioInputFile,
watermarkInputFile,
subtitleInputFile,
concatInputFile,
reportsFolder,
fontsFolder,
_logger),
HardwareAccelerationMode.Nvenc when capabilities is not NoHardwareCapabilities => new NvidiaPipelineBuilder(
ffmpegCapabilities,
capabilities,

21
ErsatzTV.FFmpeg/Pipeline/SoftwarePipelineBuilder.cs

@ -104,6 +104,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase @@ -104,6 +104,7 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
{
SetDeinterlace(videoInputFile, context, currentState);
currentState = SetTonemap(videoInputFile, videoStream, desiredState, currentState);
currentState = SetScale(videoInputFile, videoStream, desiredState, currentState);
currentState = SetPad(videoInputFile, videoStream, desiredState, currentState);
currentState = SetCrop(videoInputFile, desiredState, currentState);
@ -317,6 +318,26 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase @@ -317,6 +318,26 @@ public class SoftwarePipelineBuilder : PipelineBuilderBase
return currentState;
}
private static FrameState SetTonemap(
VideoInputFile videoInputFile,
VideoStream videoStream,
FrameState desiredState,
FrameState currentState)
{
if (videoStream.ColorParams.IsHdr)
{
foreach (IPixelFormat pixelFormat in desiredState.PixelFormat)
{
var tonemapStep = new TonemapFilter(currentState, pixelFormat);
currentState = tonemapStep.NextState(currentState);
videoStream.ResetColorParams(ColorParams.Default);
videoInputFile.FilterSteps.Add(tonemapStep);
}
}
return currentState;
}
private static FrameState SetScale(
VideoInputFile videoInputFile,
VideoStream videoStream,

Loading…
Cancel
Save