diff --git a/CHANGELOG.md b/CHANGELOG.md index a8c6184be..7a9157bbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Use latest iHD driver (21.2.3 vs 20.1.1) in vaapi docker images +### Fixed +- Add downsampling to support transcoding 10-bit HEVC content with the h264_vaapi encoder + ## [0.0.62-alpha] - 2021-10-05 ### Added - Support IMDB ids from Plex libraries, which may improve Trakt matching for some items diff --git a/ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs b/ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs index 3c91928d0..a3af18272 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs @@ -21,6 +21,7 @@ namespace ErsatzTV.Core.FFmpeg private Option _scaleToSize = None; private Option _watermark; private string _pixelFormat; + private string _videoEncoder; public FFmpegComplexFilterBuilder WithHardwareAcceleration(HardwareAccelerationKind hardwareAccelerationKind) { @@ -77,6 +78,12 @@ namespace ErsatzTV.Core.FFmpeg return this; } + public FFmpegComplexFilterBuilder WithVideoEncoder(string videoEncoder) + { + _videoEncoder = videoEncoder; + return this; + } + public Option Build(int videoStreamIndex, Option audioStreamIndex) { var complexFilter = new StringBuilder(); @@ -247,6 +254,13 @@ namespace ErsatzTV.Core.FFmpeg complexFilter.Append(audioLabel); } + // vaapi downsample 10bit hevc to 8bit h264 + if (acceleration == HardwareAccelerationKind.Vaapi && !videoFilterQueue.Any() && + _pixelFormat == "yuv420p10le" && _videoEncoder.StartsWith("h264")) + { + videoFilterQueue.Add("scale_vaapi=format=nv12"); + } + if (videoFilterQueue.Any() || !string.IsNullOrWhiteSpace(watermarkOverlay)) { if (hasAudioFilters) diff --git a/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs b/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs index 3aa093c7e..de8c378db 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs @@ -402,8 +402,13 @@ namespace ErsatzTV.Core.FFmpeg return this; } - public FFmpegProcessBuilder WithFilterComplex(MediaStream videoStream, Option maybeAudioStream) + public FFmpegProcessBuilder WithFilterComplex( + MediaStream videoStream, + Option maybeAudioStream, + string videoCodec) { + _complexFilterBuilder = _complexFilterBuilder.WithVideoEncoder(videoCodec); + int videoStreamIndex = videoStream.Index; Option maybeIndex = maybeAudioStream.Map(ms => ms.Index); diff --git a/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs b/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs index efe371d3b..84d2781ba 100644 --- a/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs +++ b/ErsatzTV.Core/FFmpeg/FFmpegProcessService.cs @@ -82,7 +82,7 @@ namespace ErsatzTV.Core.FFmpeg } builder = builder - .WithFilterComplex(videoStream, maybeAudioStream); + .WithFilterComplex(videoStream, maybeAudioStream, channel.FFmpegProfile.VideoCodec); }, () => { @@ -91,18 +91,18 @@ namespace ErsatzTV.Core.FFmpeg builder = builder .WithDeinterlace(playbackSettings.Deinterlace) .WithBlackBars(channel.FFmpegProfile.Resolution) - .WithFilterComplex(videoStream, maybeAudioStream); + .WithFilterComplex(videoStream, maybeAudioStream, channel.FFmpegProfile.VideoCodec); } else if (playbackSettings.Deinterlace) { builder = builder.WithDeinterlace(playbackSettings.Deinterlace) .WithAlignedAudio(playbackSettings.AudioDuration) - .WithFilterComplex(videoStream, maybeAudioStream); + .WithFilterComplex(videoStream, maybeAudioStream, channel.FFmpegProfile.VideoCodec); } else { builder = builder - .WithFilterComplex(videoStream, maybeAudioStream); + .WithFilterComplex(videoStream, maybeAudioStream, channel.FFmpegProfile.VideoCodec); } });