Browse Source

fix qsv scaling and watermarks with new transcoder (#656)

* fix qsv scaling

* fix qsv watermarks
pull/657/head
Jason Dove 4 years ago committed by GitHub
parent
commit
040785b0d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 11
      ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs
  3. 32
      ErsatzTV.FFmpeg/Encoder/Qsv/EncoderHevcQsv.cs
  4. 3
      ErsatzTV.FFmpeg/Filter/AvailableOverlayFilters.cs
  5. 14
      ErsatzTV.FFmpeg/Filter/Qsv/OverlayQsvFilter.cs
  6. 8
      ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs
  7. 1
      ErsatzTV.FFmpeg/Filter/WatermarkPixelFormatFilter.cs
  8. 1
      ErsatzTV.FFmpeg/PipelineBuilder.cs

1
CHANGELOG.md

@ -7,6 +7,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Fixed ### Fixed
- Add improved but experimental transcoder logic, which can be toggled on and off in `Settings` - Add improved but experimental transcoder logic, which can be toggled on and off in `Settings`
- Fix `HLS Segmenter` bug when source video packet contains no duration (`N/A`) - Fix `HLS Segmenter` bug when source video packet contains no duration (`N/A`)
- Fix green line at the bottom of some content scaled using QSV acceleration
### Added ### Added
- Add configurable channel group (M3U) and categories (XMLTV) - Add configurable channel group (M3U) and categories (XMLTV)

11
ErsatzTV.FFmpeg/Encoder/AvailableEncoders.cs

@ -11,13 +11,20 @@ namespace ErsatzTV.FFmpeg.Encoder;
public static class AvailableEncoders public static class AvailableEncoders
{ {
public static Option<IEncoder> ForVideoFormat(FFmpegState ffmpegState, FrameState currentState, FrameState desiredState, ILogger logger) => public static Option<IEncoder> ForVideoFormat(
FFmpegState ffmpegState,
FrameState currentState,
FrameState desiredState,
Option<WatermarkInputFile> maybeWatermarkInputFile,
ILogger logger) =>
(ffmpegState.HardwareAccelerationMode, desiredState.VideoFormat) switch (ffmpegState.HardwareAccelerationMode, desiredState.VideoFormat) switch
{ {
(HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) => new EncoderHevcNvenc(), (HardwareAccelerationMode.Nvenc, VideoFormat.Hevc) => new EncoderHevcNvenc(),
(HardwareAccelerationMode.Nvenc, VideoFormat.H264) => new EncoderH264Nvenc(), (HardwareAccelerationMode.Nvenc, VideoFormat.H264) => new EncoderH264Nvenc(),
(HardwareAccelerationMode.Qsv, VideoFormat.Hevc) => new EncoderHevcQsv(), (HardwareAccelerationMode.Qsv, VideoFormat.Hevc) => new EncoderHevcQsv(
currentState,
maybeWatermarkInputFile),
(HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(currentState), (HardwareAccelerationMode.Qsv, VideoFormat.H264) => new EncoderH264Qsv(currentState),
(HardwareAccelerationMode.Vaapi, VideoFormat.Hevc) => new EncoderHevcVaapi(currentState), (HardwareAccelerationMode.Vaapi, VideoFormat.Hevc) => new EncoderHevcVaapi(currentState),

32
ErsatzTV.FFmpeg/Encoder/Qsv/EncoderHevcQsv.cs

@ -1,9 +1,19 @@
using ErsatzTV.FFmpeg.Format; using ErsatzTV.FFmpeg.Format;
using LanguageExt;
namespace ErsatzTV.FFmpeg.Encoder.Qsv; namespace ErsatzTV.FFmpeg.Encoder.Qsv;
public class EncoderHevcQsv : EncoderBase public class EncoderHevcQsv : EncoderBase
{ {
private readonly FrameState _currentState;
private readonly Option<WatermarkInputFile> _maybeWatermarkInputFile;
public EncoderHevcQsv(FrameState currentState, Option<WatermarkInputFile> maybeWatermarkInputFile)
{
_currentState = currentState;
_maybeWatermarkInputFile = maybeWatermarkInputFile;
}
public override FrameState NextState(FrameState currentState) => currentState with public override FrameState NextState(FrameState currentState) => currentState with
{ {
VideoFormat = VideoFormat.Hevc, VideoFormat = VideoFormat.Hevc,
@ -12,4 +22,26 @@ public class EncoderHevcQsv : EncoderBase
public override string Name => "hevc_qsv"; public override string Name => "hevc_qsv";
public override StreamKind Kind => StreamKind.Video; public override StreamKind Kind => StreamKind.Video;
// need to upload if we're still in software and a watermark is used
public override string Filter
{
get
{
// only upload to hw if we need to overlay a watermark
if (_maybeWatermarkInputFile.IsSome && _currentState.FrameDataLocation == FrameDataLocation.Software)
{
// pixel format should already be converted to a supported format by QsvHardwareAccelerationOption
foreach (IPixelFormat pixelFormat in _currentState.PixelFormat)
{
return $"format={pixelFormat.FFmpegName},hwupload=extra_hw_frames=64";
}
// default to nv12
return "format=nv12,hwupload=extra_hw_frames=64";
}
return string.Empty;
}
}
} }

3
ErsatzTV.FFmpeg/Filter/AvailableOverlayFilters.cs

@ -1,4 +1,5 @@
using ErsatzTV.FFmpeg.Filter.Cuda; using ErsatzTV.FFmpeg.Filter.Cuda;
using ErsatzTV.FFmpeg.Filter.Qsv;
using ErsatzTV.FFmpeg.State; using ErsatzTV.FFmpeg.State;
namespace ErsatzTV.FFmpeg.Filter; namespace ErsatzTV.FFmpeg.Filter;
@ -12,7 +13,7 @@ public static class AvailableOverlayFilters
accelMode switch accelMode switch
{ {
HardwareAccelerationMode.Nvenc => new OverlayCudaFilter(watermarkState, resolution), HardwareAccelerationMode.Nvenc => new OverlayCudaFilter(watermarkState, resolution),
// HardwareAccelerationMode.Qsv => new DeinterlaceQsvFilter(), HardwareAccelerationMode.Qsv => new OverlayQsvFilter(watermarkState, resolution),
// HardwareAccelerationMode.Vaapi => new DeinterlaceVaapiFilter(), // HardwareAccelerationMode.Vaapi => new DeinterlaceVaapiFilter(),
_ => new OverlayFilter(watermarkState, resolution) _ => new OverlayFilter(watermarkState, resolution)
}; };

14
ErsatzTV.FFmpeg/Filter/Qsv/OverlayQsvFilter.cs

@ -0,0 +1,14 @@
using ErsatzTV.FFmpeg.State;
namespace ErsatzTV.FFmpeg.Filter.Qsv;
public class OverlayQsvFilter : OverlayFilter
{
public OverlayQsvFilter(WatermarkState watermarkState, FrameSize resolution) : base(watermarkState, resolution)
{
}
public override FrameState NextState(FrameState currentState) => currentState;
public override string Filter => $"overlay_qsv={Position}";
}

8
ErsatzTV.FFmpeg/Filter/Qsv/ScaleQsvFilter.cs

@ -17,6 +17,8 @@ public class ScaleQsvFilter : BaseFilter
{ {
get get
{ {
// use vpp_qsv because scale_qsv sometimes causes green lines at the bottom
string scale = string.Empty; string scale = string.Empty;
if (_currentState.ScaledSize == _scaledSize) if (_currentState.ScaledSize == _scaledSize)
@ -24,7 +26,7 @@ public class ScaleQsvFilter : BaseFilter
foreach (IPixelFormat pixelFormat in _currentState.PixelFormat) foreach (IPixelFormat pixelFormat in _currentState.PixelFormat)
{ {
// don't need scaling, but still need pixel format // don't need scaling, but still need pixel format
scale = $"scale_qsv=format={pixelFormat.FFmpegName}"; scale = $"vpp_qsv=format={pixelFormat.FFmpegName}";
} }
} }
else else
@ -35,8 +37,8 @@ public class ScaleQsvFilter : BaseFilter
format = $":format={pixelFormat.FFmpegName}"; format = $":format={pixelFormat.FFmpegName}";
} }
string targetSize = $"{_scaledSize.Width}:{_scaledSize.Height}"; string targetSize = $"w={_scaledSize.Width}:h={_scaledSize.Height}";
scale = $"scale_qsv={targetSize}{format}"; scale = $"vpp_qsv={targetSize}{format}";
} }
if (_currentState.FrameDataLocation == FrameDataLocation.Hardware) if (_currentState.FrameDataLocation == FrameDataLocation.Hardware)

1
ErsatzTV.FFmpeg/Filter/WatermarkPixelFormatFilter.cs

@ -26,6 +26,7 @@ public class WatermarkPixelFormatFilter : BaseFilter
Option<string> maybeFormat = _ffmpegState.HardwareAccelerationMode switch Option<string> maybeFormat = _ffmpegState.HardwareAccelerationMode switch
{ {
HardwareAccelerationMode.Nvenc => "yuva420p", HardwareAccelerationMode.Nvenc => "yuva420p",
HardwareAccelerationMode.Qsv => "yuva420p",
_ when _watermarkState.Opacity != 100 || hasFadePoints => _ when _watermarkState.Opacity != 100 || hasFadePoints =>
"yuva420p|yuva444p|yuva422p|rgba|abgr|bgra|gbrap|ya8", "yuva420p|yuva444p|yuva422p|rgba|abgr|bgra|gbrap|ya8",
_ => None _ => None

1
ErsatzTV.FFmpeg/PipelineBuilder.cs

@ -387,6 +387,7 @@ public class PipelineBuilder
ffmpegState, ffmpegState,
currentState, currentState,
desiredState, desiredState,
_watermarkInputFile,
_logger)) _logger))
{ {
encoder = e; encoder = e;

Loading…
Cancel
Save