Browse Source

fix transcoding tests; fix vaapi subtitle crop (#2568)

* fix transcoding tests using text subtitles

* fix vaapi picture subtitle overlay with crop

* more test improvements
pull/2569/head
Jason Dove 7 months ago committed by GitHub
parent
commit
3b254735e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 1
      ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs
  3. 1
      ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs
  4. 28
      ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs
  5. 1
      ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegProcessService.cs
  6. 16
      ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs
  7. 41
      ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs

1
CHANGELOG.md

@ -41,6 +41,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Improve reliability of live remote streams; they should transcode closer to realtime in most cases - Improve reliability of live remote streams; they should transcode closer to realtime in most cases
- Dramatically improve stream startup time - Dramatically improve stream startup time
- VAAPI: fix scaling image-based subtitles (e.g. dvdsub) - VAAPI: fix scaling image-based subtitles (e.g. dvdsub)
- VAAPI: fix overlaying picture subtitles with scaling behavior crop
- Fix HLS Segmenter (fmp4) on Windows - Fix HLS Segmenter (fmp4) on Windows
- Playback troubleshooting: wait for at least 2 initial segments (up to configured initial segment count) to reduce stalls - Playback troubleshooting: wait for at least 2 initial segments (up to configured initial segment count) to reduce stalls
- Fix Trakt List sync - Fix Trakt List sync

1
ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs

@ -437,6 +437,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler<
request.TargetFramerate, request.TargetFramerate,
Option<string>.None, Option<string>.None,
_ => { }, _ => { },
canProxy: true,
cancellationToken); cancellationToken);
var result = new PlayoutItemProcessModel( var result = new PlayoutItemProcessModel(

1
ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs

@ -251,6 +251,7 @@ public class PrepareTroubleshootingPlaybackHandler(
Option<int>.None, Option<int>.None,
FileSystemLayout.TranscodeTroubleshootingFolder, FileSystemLayout.TranscodeTroubleshootingFolder,
_ => { }, _ => { },
canProxy: true,
cancellationToken); cancellationToken);
return playoutItemResult; return playoutItemResult;

28
ErsatzTV.Core/FFmpeg/FFmpegLibraryProcessService.cs

@ -86,6 +86,7 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
Option<int> targetFramerate, Option<int> targetFramerate,
Option<string> customReportsFolder, Option<string> customReportsFolder,
Action<FFmpegPipeline> pipelineAction, Action<FFmpegPipeline> pipelineAction,
bool canProxy,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
MediaStream videoStream = await _ffmpegStreamSelector.SelectVideoStream(videoVersion); MediaStream videoStream = await _ffmpegStreamSelector.SelectVideoStream(videoVersion);
@ -153,17 +154,20 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
maybeSubtitle = allSubtitles.HeadOrNone(); maybeSubtitle = allSubtitles.HeadOrNone();
} }
foreach (Subtitle subtitle in maybeSubtitle) if (canProxy)
{ {
if (subtitle.SubtitleKind == SubtitleKind.Sidecar || subtitle is foreach (Subtitle subtitle in maybeSubtitle)
{ SubtitleKind: SubtitleKind.Embedded, IsImage: false, IsExtracted: true })
{ {
// proxy to avoid dealing with escaping if (subtitle.SubtitleKind == SubtitleKind.Sidecar || subtitle is
subtitle.Path = $"http://localhost:{Settings.StreamingPort}/media/subtitle/{subtitle.Id}"; { SubtitleKind: SubtitleKind.Embedded, IsImage: false, IsExtracted: true })
foreach (TimeSpan seek in playbackSettings.StreamSeek)
{ {
subtitle.Path += $"?seekToMs={(int)seek.TotalMilliseconds}"; // proxy to avoid dealing with escaping
subtitle.Path = $"http://localhost:{Settings.StreamingPort}/media/subtitle/{subtitle.Id}";
foreach (TimeSpan seek in playbackSettings.StreamSeek)
{
subtitle.Path += $"?seekToMs={(int)seek.TotalMilliseconds}";
}
} }
} }
} }
@ -282,7 +286,13 @@ public class FFmpegLibraryProcessService : IFFmpegProcessService
subtitle.Codec, subtitle.Codec,
StreamKind.Video); StreamKind.Video);
string path = subtitle.IsImage ? videoPath : subtitle.Path; string subtitlePath = subtitle.Path;
if (!canProxy && !subtitle.IsImage && subtitle.IsExtracted)
{
subtitlePath = Path.Combine(FileSystemLayout.SubtitleCacheFolder, subtitlePath);
}
string path = subtitle.IsImage ? videoPath : subtitlePath;
SubtitleMethod method = SubtitleMethod.Burn; SubtitleMethod method = SubtitleMethod.Burn;
if (channel.StreamingMode == StreamingMode.HttpLiveStreamingDirect) if (channel.StreamingMode == StreamingMode.HttpLiveStreamingDirect)

1
ErsatzTV.Core/Interfaces/FFmpeg/IFFmpegProcessService.cs

@ -41,6 +41,7 @@ public interface IFFmpegProcessService
Option<int> targetFramerate, Option<int> targetFramerate,
Option<string> customReportsFolder, Option<string> customReportsFolder,
Action<FFmpegPipeline> pipelineAction, Action<FFmpegPipeline> pipelineAction,
bool canProxy,
CancellationToken cancellationToken); CancellationToken cancellationToken);
Task<Command> ForError( Task<Command> ForError(

16
ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs

@ -510,6 +510,14 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
subtitle.FilterSteps.Add(scaleFilter); subtitle.FilterSteps.Add(scaleFilter);
} }
foreach (FrameSize croppedSize in currentState.CroppedSize)
{
var cropStep = new CropFilter(
currentState with { FrameDataLocation = FrameDataLocation.Software },
croppedSize);
subtitle.FilterSteps.Add(cropStep);
}
var subtitlesFilter = new OverlaySubtitleFilter(pf); var subtitlesFilter = new OverlaySubtitleFilter(pf);
subtitleOverlayFilterSteps.Add(subtitlesFilter); subtitleOverlayFilterSteps.Add(subtitlesFilter);
} }
@ -523,6 +531,14 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder
subtitle.FilterSteps.Add(scaleFilter); subtitle.FilterSteps.Add(scaleFilter);
} }
foreach (FrameSize croppedSize in currentState.CroppedSize)
{
var cropStep = new CropFilter(
currentState with { FrameDataLocation = FrameDataLocation.Software },
croppedSize);
subtitle.FilterSteps.Add(cropStep);
}
var subtitleHardwareUpload = new HardwareUploadVaapiFilter(false); var subtitleHardwareUpload = new HardwareUploadVaapiFilter(false);
subtitle.FilterSteps.Add(subtitleHardwareUpload); subtitle.FilterSteps.Add(subtitleHardwareUpload);

41
ErsatzTV.Scanner.Tests/Core/FFmpeg/TranscodingTests.cs

@ -113,7 +113,7 @@ public class TranscodingTests
public static Watermark[] Watermarks = public static Watermark[] Watermarks =
[ [
Watermark.None, Watermark.None,
//Watermark.PermanentOpaqueScaled, Watermark.PermanentOpaqueScaled,
// Watermark.PermanentOpaqueActualSize, // Watermark.PermanentOpaqueActualSize,
// Watermark.PermanentTransparentScaled, // Watermark.PermanentTransparentScaled,
// Watermark.PermanentTransparentActualSize // Watermark.PermanentTransparentActualSize
@ -122,8 +122,8 @@ public class TranscodingTests
public static Subtitle[] Subtitles = public static Subtitle[] Subtitles =
[ [
Subtitle.None, Subtitle.None,
//Subtitle.Picture, Subtitle.Picture,
// Subtitle.Text Subtitle.Text
]; ];
public static Padding[] Paddings = public static Padding[] Paddings =
@ -151,7 +151,7 @@ public class TranscodingTests
new("libx264", "yuv420p", "tv", "smpte170m", "bt709", "smpte170m"), new("libx264", "yuv420p", "tv", "smpte170m", "bt709", "smpte170m"),
// // // // // //
// // // // example format that requires setparams filter // // // // example format that requires setparams filter
//new("libx264", "yuv420p", string.Empty, string.Empty, string.Empty, string.Empty), new("libx264", "yuv420p", string.Empty, string.Empty, string.Empty, string.Empty),
// // // // // //
// // // // new("libx264", "yuvj420p"), // // // // new("libx264", "yuvj420p"),
//new("libx264", "yuv420p10le"), //new("libx264", "yuv420p10le"),
@ -159,7 +159,7 @@ public class TranscodingTests
// // // // // //
// // // // new("mpeg1video", "yuv420p"), // // // // new("mpeg1video", "yuv420p"),
// // // // // // // //
//new("mpeg2video", "yuv420p"), new("mpeg2video", "yuv420p"),
// // // //
//new InputFormat("libx265", "yuv420p"), //new InputFormat("libx265", "yuv420p"),
//new("libx265", "yuv420p10le"), //new("libx265", "yuv420p10le"),
@ -188,7 +188,7 @@ public class TranscodingTests
public static FFmpegProfileBitDepth[] BitDepths = public static FFmpegProfileBitDepth[] BitDepths =
[ [
FFmpegProfileBitDepth.EightBit, FFmpegProfileBitDepth.EightBit,
//FFmpegProfileBitDepth.TenBit FFmpegProfileBitDepth.TenBit
]; ];
public static FFmpegProfileVideoFormat[] VideoFormats = public static FFmpegProfileVideoFormat[] VideoFormats =
@ -200,10 +200,10 @@ public class TranscodingTests
public static HardwareAccelerationKind[] TestAccelerations = public static HardwareAccelerationKind[] TestAccelerations =
[ [
//HardwareAccelerationKind.None, HardwareAccelerationKind.None,
HardwareAccelerationKind.Nvenc //HardwareAccelerationKind.Nvenc
//HardwareAccelerationKind.Vaapi HardwareAccelerationKind.Vaapi,
//HardwareAccelerationKind.Qsv, HardwareAccelerationKind.Qsv,
// HardwareAccelerationKind.VideoToolbox, // HardwareAccelerationKind.VideoToolbox,
// HardwareAccelerationKind.Amf // HardwareAccelerationKind.Amf
]; ];
@ -388,7 +388,7 @@ public class TranscodingTests
watermarks, watermarks,
[], [],
"drm", "drm",
VaapiDriver.RadeonSI, VaapiDriver.iHD,
"/dev/dri/renderD128", "/dev/dri/renderD128",
Option<int>.None, Option<int>.None,
false, false,
@ -400,6 +400,7 @@ public class TranscodingTests
None, None,
Option<string>.None, Option<string>.None,
_ => { }, _ => { },
canProxy: false,
CancellationToken.None); CancellationToken.None);
// Console.WriteLine($"ffmpeg arguments {process.Arguments}"); // Console.WriteLine($"ffmpeg arguments {process.Arguments}");
@ -410,7 +411,7 @@ public class TranscodingTests
profileBitDepth, profileBitDepth,
profileVideoFormat, profileVideoFormat,
profileAcceleration, profileAcceleration,
VaapiDriver.RadeonSI, VaapiDriver.iHD,
localStatisticsProvider, localStatisticsProvider,
streamingMode, streamingMode,
() => videoVersion); () => videoVersion);
@ -444,7 +445,14 @@ public class TranscodingTests
[ValueSource(typeof(TestData), nameof(TestData.StreamingModes))] [ValueSource(typeof(TestData), nameof(TestData.StreamingModes))]
StreamingMode streamingMode) StreamingMode streamingMode)
{ {
NvEncSharpRedirector.Init(); try
{
NvEncSharpRedirector.Init();
}
catch (FileNotFoundException)
{
// do nothing
}
string file = fileToTest; string file = fileToTest;
if (string.IsNullOrWhiteSpace(file)) if (string.IsNullOrWhiteSpace(file))
@ -602,7 +610,7 @@ public class TranscodingTests
// TODO: bit depth // TODO: bit depth
bool hasPadding = filterChain.VideoFilterSteps.Any(s => s is PadFilter); bool hasPadding = filterChain.VideoFilterSteps.Any(s => s is PadFilter or PadVaapiFilter);
// TODO: optimize out padding // TODO: optimize out padding
// hasPadding.ShouldBe(padding == Padding.WithPadding); // hasPadding.ShouldBe(padding == Padding.WithPadding);
@ -699,7 +707,7 @@ public class TranscodingTests
watermarks, watermarks,
[], [],
"drm", "drm",
VaapiDriver.RadeonSI, VaapiDriver.iHD,
"/dev/dri/renderD128", "/dev/dri/renderD128",
Option<int>.None, Option<int>.None,
false, false,
@ -711,6 +719,7 @@ public class TranscodingTests
None, None,
Option<string>.None, Option<string>.None,
PipelineAction, PipelineAction,
canProxy: false,
CancellationToken.None); CancellationToken.None);
// Console.WriteLine($"ffmpeg arguments {string.Join(" ", process.StartInfo.ArgumentList)}"); // Console.WriteLine($"ffmpeg arguments {string.Join(" ", process.StartInfo.ArgumentList)}");
@ -721,7 +730,7 @@ public class TranscodingTests
profileBitDepth, profileBitDepth,
profileVideoFormat, profileVideoFormat,
profileAcceleration, profileAcceleration,
VaapiDriver.RadeonSI, VaapiDriver.iHD,
localStatisticsProvider, localStatisticsProvider,
streamingMode, streamingMode,
() => v); () => v);

Loading…
Cancel
Save