Browse Source

upgrade from dotnet 7 to dotnet 8 (#1529)

* upgrade sdk

* fix warnings in ersatztv.ffmpeg

* fix warnings in ersatztv.core

* fix warnings in ersatztv.infrastructure

* fix warnings in ersatztv.application

* disable analysis for migrations projects

* fix warnings in ersatztv.scanner

* fix warnings in ersatztv

* upgrade project framework

* update github actions and dockerfiles
pull/1530/head
Jason Dove 2 years ago committed by GitHub
parent
commit
9471cb55dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      .github/workflows/artifacts.yml
  2. 6
      .github/workflows/pr.yml
  3. 4
      ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs
  4. 2
      ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs
  5. 2
      ErsatzTV.Application/Channels/Queries/GetChannelFramerateHandler.cs
  6. 2
      ErsatzTV.Application/Emby/Commands/SynchronizeEmbyLibrariesHandler.cs
  7. 8
      ErsatzTV.Application/ErsatzTV.Application.csproj
  8. 2
      ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibrariesHandler.cs
  9. 2
      ErsatzTV.Application/Maintenance/Commands/ReleaseMemoryHandler.cs
  10. 2
      ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs
  11. 2
      ErsatzTV.Application/MediaSources/Commands/CallLocalLibraryScannerHandler.cs
  12. 2
      ErsatzTV.Application/Playouts/Commands/CreatePlayoutHandler.cs
  13. 2
      ErsatzTV.Application/Plex/Commands/SynchronizePlexLibrariesHandler.cs
  14. 2
      ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs
  15. 2
      ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs
  16. 15
      ErsatzTV.Application/Streaming/HlsSessionWorker.cs
  17. 2
      ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs
  18. 16
      ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj
  19. 16
      ErsatzTV.Core/ErsatzTV.Core.csproj
  20. 8
      ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs
  21. 4
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs
  22. 4
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  23. 4
      ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs
  24. 6
      ErsatzTV.Core/FFmpeg/HlsPlaylistFilter.cs
  25. 2
      ErsatzTV.Core/FFmpeg/SongVideoGenerator.cs
  26. 2
      ErsatzTV.Core/FFmpeg/WatermarkCalculator.cs
  27. 2
      ErsatzTV.Core/Iptv/ChannelGuide.cs
  28. 2
      ErsatzTV.Core/Plex/PlexPathReplacementService.cs
  29. 2
      ErsatzTV.Core/Scheduling/MultiCollectionGrouper.cs
  30. 6
      ErsatzTV.Core/Scheduling/PlayoutBuilder.cs
  31. 2
      ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs
  32. 16
      ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs
  33. 2
      ErsatzTV.Core/Scheduling/ShuffledScheduleItemsEnumerator.cs
  34. 6
      ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj
  35. 36
      ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs
  36. 6
      ErsatzTV.FFmpeg/Decoder/Cuvid/CuvidDecoder.cs
  37. 4
      ErsatzTV.FFmpeg/Decoder/Cuvid/DecoderImplicitCuda.cs
  38. 10
      ErsatzTV.FFmpeg/Decoder/DecoderBase.cs
  39. 2
      ErsatzTV.FFmpeg/Decoder/DecoderImplicit.cs
  40. 4
      ErsatzTV.FFmpeg/Decoder/DecoderVaapi.cs
  41. 2
      ErsatzTV.FFmpeg/Decoder/DecoderVideoToolbox.cs
  42. 10
      ErsatzTV.FFmpeg/Encoder/EncoderBase.cs
  43. 2
      ErsatzTV.FFmpeg/Encoder/EncoderCopyAll.cs
  44. 2
      ErsatzTV.FFmpeg/Encoder/EncoderImplicitVideo.cs
  45. 2
      ErsatzTV.FFmpeg/Encoder/EncoderLibx265.cs
  46. 2
      ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderHevcNvenc.cs
  47. 2
      ErsatzTV.FFmpeg/Encoder/Qsv/EncoderH264Qsv.cs
  48. 2
      ErsatzTV.FFmpeg/Encoder/Qsv/EncoderHevcQsv.cs
  49. 2
      ErsatzTV.FFmpeg/Encoder/Qsv/EncoderMpeg2Qsv.cs
  50. 6
      ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs
  51. 6
      ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs
  52. 6
      ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderMpeg2Vaapi.cs
  53. 6
      ErsatzTV.FFmpeg/Encoder/VideoToolbox/EncoderHevcVideoToolbox.cs
  54. 14
      ErsatzTV.FFmpeg/Environment/FFReportVariable.cs
  55. 12
      ErsatzTV.FFmpeg/Environment/LibvaDriverNameVariable.cs
  56. 6
      ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj
  57. 10
      ErsatzTV.FFmpeg/Filter/BaseFilter.cs
  58. 23
      ErsatzTV.FFmpeg/Filter/ComplexFilter.cs
  59. 14
      ErsatzTV.FFmpeg/Filter/VideoFilter.cs
  60. 10
      ErsatzTV.FFmpeg/Format/ConcatInputFormat.cs
  61. 10
      ErsatzTV.FFmpeg/GlobalOption/GlobalOption.cs
  62. 2
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/AmfHardwareAccelerationOption.cs
  63. 2
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs
  64. 4
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs
  65. 17
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/VaapiHardwareAccelerationOption.cs
  66. 2
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/VideoToolboxHardwareAccelerationOption.cs
  67. 2
      ErsatzTV.FFmpeg/GlobalOption/HideBannerOption.cs
  68. 2
      ErsatzTV.FFmpeg/GlobalOption/LoglevelErrorOption.cs
  69. 2
      ErsatzTV.FFmpeg/GlobalOption/NoStatsOption.cs
  70. 2
      ErsatzTV.FFmpeg/GlobalOption/StandardFormatFlags.cs
  71. 10
      ErsatzTV.FFmpeg/GlobalOption/StreamSeekFilterOption.cs
  72. 2
      ErsatzTV.FFmpeg/GlobalOption/ThreadCountOption.cs
  73. 10
      ErsatzTV.FFmpeg/IPipelineStep.cs
  74. 10
      ErsatzTV.FFmpeg/InputOption/CopyTimestampInputOption.cs
  75. 10
      ErsatzTV.FFmpeg/InputOption/DoNotIgnoreLoopInputOption.cs
  76. 16
      ErsatzTV.FFmpeg/InputOption/InfiniteLoopInputOption.cs
  77. 10
      ErsatzTV.FFmpeg/InputOption/LavfiInputOption.cs
  78. 2
      ErsatzTV.FFmpeg/InputOption/NoStandardInputOption.cs
  79. 14
      ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs
  80. 10
      ErsatzTV.FFmpeg/InputOption/StreamSeekInputOption.cs
  81. 12
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs
  82. 10
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatMkv.cs
  83. 10
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatMp4.cs
  84. 14
      ErsatzTV.FFmpeg/OutputFormat/OutputFormatMpegTs.cs
  85. 2
      ErsatzTV.FFmpeg/OutputOption/AudioBitrateOutputOption.cs
  86. 2
      ErsatzTV.FFmpeg/OutputOption/AudioBufferSizeOutputOption.cs
  87. 4
      ErsatzTV.FFmpeg/OutputOption/AudioChannelsOutputOption.cs
  88. 2
      ErsatzTV.FFmpeg/OutputOption/AudioSampleRateOutputOption.cs
  89. 2
      ErsatzTV.FFmpeg/OutputOption/ClosedGopOutputOption.cs
  90. 2
      ErsatzTV.FFmpeg/OutputOption/FastStartOutputOption.cs
  91. 2
      ErsatzTV.FFmpeg/OutputOption/FileNameOutputOption.cs
  92. 10
      ErsatzTV.FFmpeg/OutputOption/FrameRateOutputOption.cs
  93. 2
      ErsatzTV.FFmpeg/OutputOption/MapAllStreamsOutputOption.cs
  94. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/DoNotMapMetadataOutputOption.cs
  95. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataAudioLanguageOutputOption.cs
  96. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataServiceNameOutputOption.cs
  97. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataServiceProviderOutputOption.cs
  98. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataSubtitleLanguageOutputOption.cs
  99. 2
      ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataSubtitleTitleOutputOption.cs
  100. 2
      ErsatzTV.FFmpeg/OutputOption/Mp4OutputOptions.cs
  101. Some files were not shown because too many files have changed in this diff Show More

12
.github/workflows/artifacts.yml

@ -49,7 +49,7 @@ jobs: @@ -49,7 +49,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Setup Node.js
uses: actions/setup-node@v3
@ -83,8 +83,8 @@ jobs: @@ -83,8 +83,8 @@ jobs:
shell: bash
run: |
sed -i '' '/Scanner/d' ErsatzTV/ErsatzTV.csproj
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net7.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net7.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net8.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net8.0 --runtime "${{ matrix.target }}" -c Release -o publish -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=false -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
- name: Bundle
shell: bash
@ -175,7 +175,7 @@ jobs: @@ -175,7 +175,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Setup Node.js
uses: actions/setup-node@v3
@ -216,8 +216,8 @@ jobs: @@ -216,8 +216,8 @@ jobs:
# Build everything
sed -i '/Scanner/d' ErsatzTV/ErsatzTV.csproj
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net7.0 --runtime "${{ matrix.target }}" -c Release -o "$release_name" -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net7.0 --runtime "${{ matrix.target }}" -c Release -o "$release_name" -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV.Scanner/ErsatzTV.Scanner.csproj --framework net8.0 --runtime "${{ matrix.target }}" -c Release -o "$release_name" -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
dotnet publish ErsatzTV/ErsatzTV.csproj --framework net8.0 --runtime "${{ matrix.target }}" -c Release -o "$release_name" -p:InformationalVersion="${{ inputs.release_version }}-${{ matrix.target }}" -p:EnableCompressionInSingleFile=true -p:DebugType=Embedded -p:PublishSingleFile=true --self-contained true
# Build Windows launcher
if [ "${{ matrix.kind }}" == "windows" ]; then

6
.github/workflows/pr.yml

@ -11,7 +11,7 @@ jobs: @@ -11,7 +11,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Setup Rust
uses: actions-rs/toolchain@v1
@ -46,7 +46,7 @@ jobs: @@ -46,7 +46,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear
@ -74,7 +74,7 @@ jobs: @@ -74,7 +74,7 @@ jobs:
- name: Setup .NET Core
uses: actions/setup-dotnet@v3
with:
dotnet-version: 7.0.x
dotnet-version: 8.0.x
- name: Clean
run: dotnet clean --configuration Release && dotnet nuget locals all --clear

4
ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs

@ -88,7 +88,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -88,7 +88,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
.ToListAsync(cancellationToken)
.Map(list => list.Collect(p => p.Items).OrderBy(pi => pi.Start).ToList());
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
await using RecyclableMemoryStream ms = _recyclableMemoryStreamManager.GetStream();
await using var xml = XmlWriter.Create(
ms,
new XmlWriterSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment });
@ -492,7 +492,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData> @@ -492,7 +492,7 @@ public class RefreshChannelDataHandler : IRequestHandler<RefreshChannelData>
string[] split = first.Split(':');
if (split.Length == 2)
{
return split[0].ToLowerInvariant() == "us"
return split[0].Equals("us", StringComparison.OrdinalIgnoreCase)
? new ContentRating(system, split[1].ToUpperInvariant())
: new ContentRating(None, split[1].ToUpperInvariant());
}

2
ErsatzTV.Application/Channels/Commands/RefreshChannelListHandler.cs

@ -31,7 +31,7 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList> @@ -31,7 +31,7 @@ public class RefreshChannelListHandler : IRequestHandler<RefreshChannelList>
await using TvContext dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken);
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
await using RecyclableMemoryStream ms = _recyclableMemoryStreamManager.GetStream();
await using var xml = XmlWriter.Create(
ms,
new XmlWriterSettings { Async = true, ConformanceLevel = ConformanceLevel.Fragment });

2
ErsatzTV.Application/Channels/Queries/GetChannelFramerateHandler.cs

@ -86,7 +86,7 @@ public class GetChannelFramerateHandler : IRequestHandler<GetChannelFramerate, O @@ -86,7 +86,7 @@ public class GetChannelFramerateHandler : IRequestHandler<GetChannelFramerate, O
return result;
}
if (distinct.Any())
if (distinct.Count != 0)
{
_logger.LogInformation(
"All content on channel {ChannelNumber} has the same frame rate of {FrameRate}; will not normalize",

2
ErsatzTV.Application/Emby/Commands/SynchronizeEmbyLibrariesHandler.cs

@ -92,7 +92,7 @@ public class SynchronizeEmbyLibrariesHandler : IRequestHandler<SynchronizeEmbyLi @@ -92,7 +92,7 @@ public class SynchronizeEmbyLibrariesHandler : IRequestHandler<SynchronizeEmbyLi
toAdd,
toRemove,
toUpdate);
if (ids.Any())
if (ids.Count != 0)
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();

8
ErsatzTV.Application/ErsatzTV.Application.csproj

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
@ -12,9 +12,9 @@ @@ -12,9 +12,9 @@
<PackageReference Include="Bugsnag" Version="3.1.0" />
<PackageReference Include="CliWrap" Version="3.6.4" />
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="7.0.0" />
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.8.14">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

2
ErsatzTV.Application/Jellyfin/Commands/SynchronizeJellyfinLibrariesHandler.cs

@ -94,7 +94,7 @@ public class @@ -94,7 +94,7 @@ public class
toAdd,
toRemove,
toUpdate);
if (ids.Any())
if (ids.Count != 0)
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();

2
ErsatzTV.Application/Maintenance/Commands/ReleaseMemoryHandler.cs

@ -27,7 +27,7 @@ public class ReleaseMemoryHandler : IRequestHandler<ReleaseMemory> @@ -27,7 +27,7 @@ public class ReleaseMemoryHandler : IRequestHandler<ReleaseMemory>
return Task.CompletedTask;
}
bool hasActiveWorkers = _ffmpegSegmenterService.SessionWorkers.Any() || FFmpegProcess.ProcessCount > 0;
bool hasActiveWorkers = !_ffmpegSegmenterService.SessionWorkers.IsEmpty || FFmpegProcess.ProcessCount > 0;
if (request.ForceAggressive || !hasActiveWorkers)
{
_logger.LogDebug("Starting aggressive garbage collection");

2
ErsatzTV.Application/MediaCollections/Commands/RemoveItemsFromCollectionHandler.cs

@ -46,7 +46,7 @@ public class RemoveItemsFromCollectionHandler : IRequestHandler<RemoveItemsFromC @@ -46,7 +46,7 @@ public class RemoveItemsFromCollectionHandler : IRequestHandler<RemoveItemsFromC
itemsToRemove.ForEach(m => collection.MediaItems.Remove(m));
if (itemsToRemove.Any() && await dbContext.SaveChangesAsync() > 0)
if (itemsToRemove.Count != 0 && await dbContext.SaveChangesAsync() > 0)
{
// refresh all playouts that use this collection
foreach (int playoutId in await _mediaCollectionRepository.PlayoutIdsUsingCollection(collection.Id))

2
ErsatzTV.Application/MediaSources/Commands/CallLocalLibraryScannerHandler.cs

@ -73,7 +73,7 @@ public class CallLocalLibraryScannerHandler : CallLibraryScannerHandler<IScanLoc @@ -73,7 +73,7 @@ public class CallLocalLibraryScannerHandler : CallLibraryScannerHandler<IScanLoc
.Filter(lp => lp.LibraryId == request.LibraryId)
.ToListAsync();
DateTime minDateTime = libraryPaths.Any()
DateTime minDateTime = libraryPaths.Count != 0
? libraryPaths.Min(lp => lp.LastScan ?? SystemTime.MinValueUtc)
: SystemTime.MaxValueUtc;

2
ErsatzTV.Application/Playouts/Commands/CreatePlayoutHandler.cs

@ -79,7 +79,7 @@ public class CreatePlayoutHandler : IRequestHandler<CreatePlayout, Either<BaseEr @@ -79,7 +79,7 @@ public class CreatePlayoutHandler : IRequestHandler<CreatePlayout, Either<BaseEr
private static Validation<BaseError, ProgramSchedule> ProgramScheduleMustHaveItems(
ProgramSchedule programSchedule) =>
Optional(programSchedule)
.Filter(ps => ps.Items.Any())
.Filter(ps => ps.Items.Count != 0)
.ToValidation<BaseError>("Program schedule must have items");
private static Validation<BaseError, ProgramSchedulePlayoutType> ValidatePlayoutType(

2
ErsatzTV.Application/Plex/Commands/SynchronizePlexLibrariesHandler.cs

@ -88,7 +88,7 @@ public class @@ -88,7 +88,7 @@ public class
connectionParameters.PlexMediaSource.Id,
toAdd,
toRemove);
if (ids.Any())
if (ids.Count != 0)
{
await _searchIndex.RemoveItems(ids);
_searchIndex.Commit();

2
ErsatzTV.Application/ProgramSchedules/Commands/CopyProgramScheduleHandler.cs

@ -92,7 +92,7 @@ public class @@ -92,7 +92,7 @@ public class
return (result1, result2).Apply((_, _) => request.Name);
}
private static void DetachEntity<T>(DbContext db, T entity) where T : class
private static void DetachEntity<T>(TvContext db, T entity) where T : class
{
db.Entry(entity).State = EntityState.Detached;
if (entity.GetType().GetProperty("Id") is not null)

2
ErsatzTV.Application/Streaming/Commands/StartFFmpegSessionHandler.cs

@ -116,7 +116,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit @@ -116,7 +116,7 @@ public class StartFFmpegSessionHandler : IRequestHandler<StartFFmpegSession, Eit
private async Task WaitForPlaylistSegments(
string playlistFileName,
int initialSegmentCount,
IHlsSessionWorker worker,
HlsSessionWorker worker,
CancellationToken cancellationToken)
{
var sw = Stopwatch.StartNew();

15
ErsatzTV.Application/Streaming/HlsSessionWorker.cs

@ -1,4 +1,5 @@ @@ -1,4 +1,5 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Text;
using System.Timers;
@ -113,7 +114,7 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -113,7 +114,7 @@ public class HlsSessionWorker : IHlsSessionWorker
public void PlayoutUpdated() => _state = HlsSessionState.PlayoutUpdated;
public void Dispose()
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
@ -123,9 +124,17 @@ public class HlsSessionWorker : IHlsSessionWorker @@ -123,9 +124,17 @@ public class HlsSessionWorker : IHlsSessionWorker
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(incomingCancellationToken);
void Cancel(object o, ElapsedEventArgs e)
[SuppressMessage("Usage", "VSTHRD100:Avoid async void methods")]
async void Cancel(object o, ElapsedEventArgs e)
{
cts.Cancel();
try
{
await cts.CancelAsync();
}
catch (Exception)
{
// do nothing
}
}
try

2
ErsatzTV.Application/Subtitles/Commands/ExtractEmbeddedSubtitlesHandler.cs

@ -130,7 +130,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu @@ -130,7 +130,7 @@ public class ExtractEmbeddedSubtitlesHandler : IRequestHandler<ExtractEmbeddedSu
List<int> mediaItemIdsWithTextSubtitles =
await GetMediaItemIdsWithTextSubtitles(dbContext, mediaItemIds, cancellationToken);
if (mediaItemIdsWithTextSubtitles.Any())
if (mediaItemIdsWithTextSubtitles.Count != 0)
{
_logger.LogDebug(
"Checking media items {MediaItemIds} for text subtitles or fonts to extract for playouts {PlayoutIds}",

16
ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
@ -11,21 +11,21 @@ @@ -11,21 +11,21 @@
<PackageReference Include="CliWrap" Version="3.6.4" />
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="LanguageExt.Core" Version="4.4.7" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.8.14">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Serilog.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
</ItemGroup>

16
ErsatzTV.Core/ErsatzTV.Core.csproj

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<NoWarn>VSTHRD200</NoWarn>
<ImplicitUsings>enable</ImplicitUsings>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
@ -11,15 +11,15 @@ @@ -11,15 +11,15 @@
<ItemGroup>
<PackageReference Include="Bugsnag" Version="3.1.0" />
<PackageReference Include="Destructurama.Attributed" Version="3.1.0" />
<PackageReference Include="Flurl" Version="3.0.7" />
<PackageReference Include="Flurl" Version="4.0.0" />
<PackageReference Include="LanguageExt.Core" Version="4.4.7" />
<PackageReference Include="LanguageExt.Transformers" Version="4.4.7" />
<PackageReference Include="MediatR" Version="12.1.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.8.14">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

8
ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs

@ -214,9 +214,9 @@ public class FFmpegComplexFilterBuilder @@ -214,9 +214,9 @@ public class FFmpegComplexFilterBuilder
videoFilterQueue.Add(subtitle);
}
if (videoFilterQueue.Any() || !string.IsNullOrWhiteSpace(watermarkOverlay))
if (videoFilterQueue.Count != 0 || !string.IsNullOrWhiteSpace(watermarkOverlay))
{
if (videoFilterQueue.Any())
if (videoFilterQueue.Count != 0)
{
complexFilter.Append(CultureInfo.InvariantCulture, $"[{videoLabel}]");
var filters = string.Join(",", videoFilterQueue);
@ -225,7 +225,7 @@ public class FFmpegComplexFilterBuilder @@ -225,7 +225,7 @@ public class FFmpegComplexFilterBuilder
if (!string.IsNullOrWhiteSpace(watermarkOverlay))
{
if (videoFilterQueue.Any())
if (videoFilterQueue.Count != 0)
{
complexFilter.Append("[vt];");
}
@ -244,7 +244,7 @@ public class FFmpegComplexFilterBuilder @@ -244,7 +244,7 @@ public class FFmpegComplexFilterBuilder
}
complexFilter.Append(
videoFilterQueue.Any()
videoFilterQueue.Count != 0
? $"[vt]{watermarkLabel}{watermarkOverlay}"
: $"[{videoLabel}]{watermarkLabel}{watermarkOverlay}");
}

4
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -211,7 +211,7 @@ public static class FFmpegPlaybackSettingsCalculator @@ -211,7 +211,7 @@ public static class FFmpegPlaybackSettingsCalculator
private static bool IsOddSize(MediaVersion version) =>
version.Height % 2 == 1 || version.Width % 2 == 1;
private static IDisplaySize CalculateScaledSize(FFmpegProfile ffmpegProfile, MediaVersion version)
private static DisplaySize CalculateScaledSize(FFmpegProfile ffmpegProfile, MediaVersion version)
{
IDisplaySize sarSize = SARSize(version);
int p = version.Width * sarSize.Width;
@ -269,7 +269,7 @@ public static class FFmpegPlaybackSettingsCalculator @@ -269,7 +269,7 @@ public static class FFmpegPlaybackSettingsCalculator
return version.DisplayAspectRatio != $"{version.Width}:{version.Height}";
}
private static IDisplaySize SARSize(MediaVersion version)
private static DisplaySize SARSize(MediaVersion version)
{
string[] split = version.SampleAspectRatio.Split(":");
return new DisplaySize(

4
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -28,6 +28,8 @@ namespace ErsatzTV.Core.FFmpeg; @@ -28,6 +28,8 @@ namespace ErsatzTV.Core.FFmpeg;
internal class FFmpegProcessBuilder
{
private static readonly string[] QuietArguments = { "-hide_banner", "-loglevel", "error", "-nostats" };
private readonly List<string> _arguments = new();
private readonly string _ffmpegPath;
private FFmpegComplexFilterBuilder _complexFilterBuilder = new();
@ -198,7 +200,7 @@ internal class FFmpegProcessBuilder @@ -198,7 +200,7 @@ internal class FFmpegProcessBuilder
public FFmpegProcessBuilder WithQuiet()
{
_arguments.AddRange(new[] { "-hide_banner", "-loglevel", "error", "-nostats" });
_arguments.AddRange(QuietArguments);
return this;
}

4
ErsatzTV.Core/FFmpeg/FFmpegStreamSelector.cs

@ -206,7 +206,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -206,7 +206,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
s => preferredLanguageCodes.Any(c => string.Equals(s.Language, c, StringComparison.OrdinalIgnoreCase)))
.ToList();
if (correctLanguage.Any())
if (correctLanguage.Count != 0)
{
_logger.LogDebug(
"Found {Count} audio streams with preferred audio language code(s) {Code}",
@ -234,7 +234,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector @@ -234,7 +234,7 @@ public class FFmpegStreamSelector : IFFmpegStreamSelector
var matchingTitle = streams
.Filter(ms => (ms.Title ?? string.Empty).Contains(title, StringComparison.OrdinalIgnoreCase))
.ToList();
if (matchingTitle.Any())
if (matchingTitle.Count != 0)
{
_logger.LogDebug(
"Found {Count} audio streams with preferred title {Title}",

6
ErsatzTV.Core/FFmpeg/HlsPlaylistFilter.cs

@ -119,12 +119,12 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter @@ -119,12 +119,12 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter
int discontinuitySequence,
int maxSegments)
{
if (items.Any() && items[0] is PlaylistDiscontinuity)
if (items.Count != 0 && items[0] is PlaylistDiscontinuity)
{
discontinuitySequence++;
}
while (items.Any() && items[0] is PlaylistDiscontinuity)
while (items.Count != 0 && items[0] is PlaylistDiscontinuity)
{
items.RemoveAt(0);
}
@ -148,7 +148,7 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter @@ -148,7 +148,7 @@ public class HlsPlaylistFilter : IHlsPlaylistFilter
.IfNone(0);
// count all discontinuities that were filtered out
if (allSegments.Any())
if (allSegments.Count != 0)
{
int index = items.IndexOf(allSegments.Head());
int count = items.Take(index + 1).OfType<PlaylistDiscontinuity>().Count();

2
ErsatzTV.Core/FFmpeg/SongVideoGenerator.cs

@ -189,7 +189,7 @@ public class SongVideoGenerator : ISongVideoGenerator @@ -189,7 +189,7 @@ public class SongVideoGenerator : ISongVideoGenerator
artwork.BlurHash64
}.Filter(s => !string.IsNullOrWhiteSpace(s)).ToList();
if (hashes.Any())
if (hashes.Count != 0)
{
string hash = hashes[NextRandom(hashes.Count)];

2
ErsatzTV.Core/FFmpeg/WatermarkCalculator.cs

@ -59,7 +59,7 @@ public static class WatermarkCalculator @@ -59,7 +59,7 @@ public static class WatermarkCalculator
// trim points that are past the end
result.RemoveAll(fp => fp.Time >= outPoint);
if (result.Any())
if (result.Count != 0)
{
for (var i = 0; i < result.Count; i++)
{

2
ErsatzTV.Core/Iptv/ChannelGuide.cs

@ -23,7 +23,7 @@ public class ChannelGuide @@ -23,7 +23,7 @@ public class ChannelGuide
public string ToXml()
{
using MemoryStream ms = _recyclableMemoryStreamManager.GetStream();
using RecyclableMemoryStream ms = _recyclableMemoryStreamManager.GetStream();
using var xml = XmlWriter.Create(ms);
xml.WriteStartDocument();

2
ErsatzTV.Core/Plex/PlexPathReplacementService.cs

@ -77,5 +77,5 @@ public class PlexPathReplacementService : IPlexPathReplacementService @@ -77,5 +77,5 @@ public class PlexPathReplacementService : IPlexPathReplacementService
}
private static bool IsWindows(PlexMediaSource plexMediaSource) =>
plexMediaSource.Platform.ToLowerInvariant() == "windows";
plexMediaSource.Platform.Equals("windows", StringComparison.OrdinalIgnoreCase);
}

2
ErsatzTV.Core/Scheduling/MultiCollectionGrouper.cs

@ -6,7 +6,7 @@ public static class MultiCollectionGrouper @@ -6,7 +6,7 @@ public static class MultiCollectionGrouper
{
var result = new List<GroupedMediaItem>();
foreach (CollectionWithItems collection in collections.Where(collection => collection.MediaItems.Any()))
foreach (CollectionWithItems collection in collections.Where(collection => collection.MediaItems.Count != 0))
{
if (collection.ScheduleAsGroup)
{

6
ErsatzTV.Core/Scheduling/PlayoutBuilder.cs

@ -251,7 +251,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -251,7 +251,7 @@ public class PlayoutBuilder : IPlayoutBuilder
private async Task<Option<PlayoutParameters>> Validate(Playout playout)
{
Map<CollectionKey, List<MediaItem>> collectionMediaItems = await GetCollectionMediaItems(playout);
if (!collectionMediaItems.Any())
if (collectionMediaItems.IsEmpty)
{
_logger.LogWarning("Playout {Playout} has no items", playout.Channel.Name);
return None;
@ -543,7 +543,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -543,7 +543,7 @@ public class PlayoutBuilder : IPlayoutBuilder
// once more to get playout anchor
ProgramScheduleItem anchorScheduleItem = playoutBuilderState.ScheduleItemsEnumerator.Current;
if (playout.Items.Any())
if (playout.Items.Count != 0)
{
DateTimeOffset maxStartTime = playout.Items.Max(i => i.FinishOffset);
if (maxStartTime < playoutBuilderState.CurrentTime)
@ -655,7 +655,7 @@ public class PlayoutBuilder : IPlayoutBuilder @@ -655,7 +655,7 @@ public class PlayoutBuilder : IPlayoutBuilder
items.RemoveAll(zeroItems.Contains);
}
return collectionMediaItems.Find(c => !c.Value.Any()).Map(c => c.Key);
return collectionMediaItems.Find(c => c.Value.Count == 0).Map(c => c.Key);
}
private static PlayoutAnchor FindStartAnchor(

2
ErsatzTV.Core/Scheduling/PlayoutModeSchedulerFlood.cs

@ -130,7 +130,7 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul @@ -130,7 +130,7 @@ public class PlayoutModeSchedulerFlood : PlayoutModeSchedulerBase<ProgramSchedul
nextState = nextState with
{
InFlood = playoutItems.Any() && nextState.CurrentTime >= hardStop,
InFlood = playoutItems.Count != 0 && nextState.CurrentTime >= hardStop,
// only decrement guide group if it was bumped
NextGuideGroup = playoutItems.Select(pi => pi.GuideGroup).Distinct().Count() != 1

16
ErsatzTV.Core/Scheduling/ShuffleInOrderCollectionEnumerator.cs

@ -86,7 +86,7 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator @@ -86,7 +86,7 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
public int Count => _shuffled.Count;
private IList<MediaItem> Shuffle(IList<CollectionWithItems> collections, Random random)
private MediaItem[] Shuffle(IList<CollectionWithItems> collections, Random random)
{
// based on https://keyj.emphy.de/balanced-shuffle/
@ -126,7 +126,7 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator @@ -126,7 +126,7 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
}
}
return result;
return result.ToArray();
}
private List<OrderedCollection> Fill(List<OrderedCollection> orderedCollections, Random random)
@ -166,12 +166,12 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator @@ -166,12 +166,12 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
k--;
}
if (smaller.Any())
if (smaller.Count != 0)
{
ordered.AddRange(smaller);
}
if (larger.Any())
if (larger.Count != 0)
{
ordered.AddRange(larger);
}
@ -188,20 +188,20 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator @@ -188,20 +188,20 @@ public class ShuffleInOrderCollectionEnumerator : IMediaCollectionEnumerator
return result;
}
private static IList<Option<MediaItem>> OrderItems(CollectionWithItems collectionWithItems)
private static Option<MediaItem>[] OrderItems(CollectionWithItems collectionWithItems)
{
if (collectionWithItems.UseCustomOrder)
{
return collectionWithItems.MediaItems.Map(Some).ToList();
return collectionWithItems.MediaItems.Map(Some).ToArray();
}
return collectionWithItems.MediaItems
.OrderBy(identity, new ChronologicalMediaComparer())
.Map(Some)
.ToList();
.ToArray();
}
private static IList<Option<MediaItem>> Shuffle(IEnumerable<Option<MediaItem>> list, Random random)
private static Option<MediaItem>[] Shuffle(IEnumerable<Option<MediaItem>> list, Random random)
{
Option<MediaItem>[] copy = list.ToArray();

2
ErsatzTV.Core/Scheduling/ShuffledScheduleItemsEnumerator.cs

@ -87,7 +87,7 @@ public class ShuffledScheduleItemsEnumerator : IScheduleItemsEnumerator @@ -87,7 +87,7 @@ public class ShuffledScheduleItemsEnumerator : IScheduleItemsEnumerator
return _shuffled[(State.Index + offset) % _scheduleItemsCount];
}
private static IList<ProgramScheduleItem> Shuffle(IEnumerable<ProgramScheduleItem> list, CloneableRandom random)
private static ProgramScheduleItem[] Shuffle(IEnumerable<ProgramScheduleItem> list, CloneableRandom random)
{
ProgramScheduleItem[] copy = list.ToArray();

6
ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
@ -9,10 +9,10 @@ @@ -9,10 +9,10 @@
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
<PackageReference Include="NSubstitute" Version="5.1.0" />
<PackageReference Include="NUnit" Version="3.14.0" />
<PackageReference Include="NUnit" Version="4.0.1" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
<PackageReference Include="System.IO.FileSystem.Primitives" Version="4.3.0" />
<PackageReference Include="System.Text.Encoding.Extensions" Version="4.3.0" />

36
ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs

@ -18,9 +18,19 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -18,9 +18,19 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
{
private const string ArchitectureCacheKey = "ffmpeg.hardware.nvidia.architecture";
private const string ModelCacheKey = "ffmpeg.hardware.nvidia.model";
private const string VaapiCacheKeyFormat = "ffmpeg.hardware.vaapi.{0}.{1}";
private const string QsvCacheKeyFormat = "ffmpeg.hardware.qsv.{0}";
private const string FFmpegCapabilitiesCacheKeyFormat = "ffmpeg.{0}";
private static readonly CompositeFormat VaapiCacheKeyFormat = CompositeFormat.Parse("ffmpeg.hardware.vaapi.{0}.{1}");
private static readonly CompositeFormat QsvCacheKeyFormat = CompositeFormat.Parse("ffmpeg.hardware.qsv.{0}");
private static readonly CompositeFormat FFmpegCapabilitiesCacheKeyFormat = CompositeFormat.Parse("ffmpeg.{0}");
private static readonly string[] QsvArguments =
{
"-f", "lavfi",
"-i", "nullsrc",
"-t", "00:00:01",
"-c:v", "h264_qsv",
"-f", "null", "-"
};
private readonly ILogger<HardwareCapabilitiesFactory> _logger;
private readonly IMemoryCache _memoryCache;
@ -118,21 +128,13 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -118,21 +128,13 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
return output;
}
public async Task<QsvOutput> GetQsvOutput(string ffmpegPath, Option<string> qsvDevice)
{
var option = new QsvHardwareAccelerationOption(qsvDevice);
var arguments = option.GlobalOptions.ToList();
arguments.AddRange(
new[]
{
"-f", "lavfi",
"-i", "nullsrc",
"-t", "00:00:01",
"-c:v", "h264_qsv",
"-f", "null", "-"
});
arguments.AddRange(QsvArguments);
BufferedCommandResult result = await Cli.Wrap(ffmpegPath)
.WithArguments(arguments)
@ -200,7 +202,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -200,7 +202,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
.Bind(l => parseLine(l))
.ToImmutableHashSet();
}
private async Task<IReadOnlySet<string>> GetFFmpegOptions(string ffmpegPath)
{
var cacheKey = string.Format(CultureInfo.InvariantCulture, FFmpegCapabilitiesCacheKeyFormat, "options");
@ -246,7 +248,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -246,7 +248,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
Match match = Regex.Match(input, PATTERN);
return match.Success ? match.Groups[1].Value : Option<string>.None;
}
private async Task<IHardwareCapabilities> GetVaapiCapabilities(
Option<string> vaapiDriver,
Option<string> vaapiDevice)
@ -286,7 +288,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -286,7 +288,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
profileEntrypoints = VaapiCapabilityParser.ParseFull(o);
}
if (profileEntrypoints?.Any() ?? false)
if (profileEntrypoints is not null && profileEntrypoints.Count != 0)
{
_logger.LogInformation(
"Detected {Count} VAAPI profile entrypoints for using {Driver} {Device}",
@ -352,7 +354,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory @@ -352,7 +354,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory
profileEntrypoints = VaapiCapabilityParser.ParseFull(o);
}
if (profileEntrypoints?.Any() ?? false)
if (profileEntrypoints is not null && profileEntrypoints.Count != 0)
{
_logger.LogInformation(
"Detected {Count} VAAPI profile entrypoints for using QSV device {Device}",

6
ErsatzTV.FFmpeg/Decoder/Cuvid/CuvidDecoder.cs

@ -12,9 +12,9 @@ public abstract class CuvidDecoder : DecoderBase @@ -12,9 +12,9 @@ public abstract class CuvidDecoder : DecoderBase
? FrameDataLocation.Software
: FrameDataLocation.Hardware;
public override IList<string> InputOptions(InputFile inputFile)
public override string[] InputOptions(InputFile inputFile)
{
IList<string> result = base.InputOptions(inputFile);
var result = new List<string>(base.InputOptions(inputFile));
if (HardwareAccelerationMode != HardwareAccelerationMode.None)
{
@ -27,6 +27,6 @@ public abstract class CuvidDecoder : DecoderBase @@ -27,6 +27,6 @@ public abstract class CuvidDecoder : DecoderBase
result.Add(InputBitDepth(inputFile) == 10 ? "p010le" : "nv12");
}
return result;
return result.ToArray();
}
}

4
ErsatzTV.FFmpeg/Decoder/Cuvid/DecoderImplicitCuda.cs

@ -4,8 +4,8 @@ public class DecoderImplicitCuda : DecoderBase @@ -4,8 +4,8 @@ public class DecoderImplicitCuda : DecoderBase
{
protected override FrameDataLocation OutputFrameDataLocation => FrameDataLocation.Hardware;
public override string Name => string.Empty;
public override IList<string> InputOptions(InputFile inputFile) =>
new List<string>
public override string[] InputOptions(InputFile inputFile) =>
new[]
{
"-hwaccel_output_format",
"cuda"

10
ErsatzTV.FFmpeg/Decoder/DecoderBase.cs

@ -6,11 +6,11 @@ namespace ErsatzTV.FFmpeg.Decoder; @@ -6,11 +6,11 @@ namespace ErsatzTV.FFmpeg.Decoder;
public abstract class DecoderBase : IDecoder
{
protected abstract FrameDataLocation OutputFrameDataLocation { get; }
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public virtual IList<string> InputOptions(InputFile inputFile) => new List<string> { "-c:v", Name };
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public virtual string[] InputOptions(InputFile inputFile) => new[] { "-c:v", Name };
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public virtual FrameState NextState(FrameState currentState) =>
currentState with { FrameDataLocation = OutputFrameDataLocation };

2
ErsatzTV.FFmpeg/Decoder/DecoderImplicit.cs

@ -4,5 +4,5 @@ public class DecoderImplicit : DecoderBase @@ -4,5 +4,5 @@ public class DecoderImplicit : DecoderBase
{
protected override FrameDataLocation OutputFrameDataLocation => FrameDataLocation.Software;
public override string Name => string.Empty;
public override IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public override string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
}

4
ErsatzTV.FFmpeg/Decoder/DecoderVaapi.cs

@ -8,8 +8,8 @@ public class DecoderVaapi : DecoderBase @@ -8,8 +8,8 @@ public class DecoderVaapi : DecoderBase
public override string Name => "implicit_vaapi";
public override IList<string> InputOptions(InputFile inputFile) =>
new List<string> { "-hwaccel_output_format", "vaapi" };
public override string[] InputOptions(InputFile inputFile) =>
new[] { "-hwaccel_output_format", "vaapi" };
public override FrameState NextState(FrameState currentState)
{

2
ErsatzTV.FFmpeg/Decoder/DecoderVideoToolbox.cs

@ -4,5 +4,5 @@ public class DecoderVideoToolbox : DecoderBase @@ -4,5 +4,5 @@ public class DecoderVideoToolbox : DecoderBase
{
protected override FrameDataLocation OutputFrameDataLocation => FrameDataLocation.Software;
public override string Name => "implicit_videotoolbox";
public override IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public override string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
}

10
ErsatzTV.FFmpeg/Encoder/EncoderBase.cs

@ -4,12 +4,12 @@ namespace ErsatzTV.FFmpeg.Encoder; @@ -4,12 +4,12 @@ namespace ErsatzTV.FFmpeg.Encoder;
public abstract class EncoderBase : IEncoder
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public virtual IList<string> OutputOptions => new List<string>
public virtual string[] OutputOptions => new[]
{
Kind switch
{

2
ErsatzTV.FFmpeg/Encoder/EncoderCopyAll.cs

@ -4,6 +4,6 @@ public class EncoderCopyAll : EncoderBase @@ -4,6 +4,6 @@ public class EncoderCopyAll : EncoderBase
{
public override string Name => "copy";
public override StreamKind Kind => StreamKind.All;
public override IList<string> OutputOptions => new List<string> { "-c", Name };
public override string[] OutputOptions => new[] { "-c", Name };
public override FrameState NextState(FrameState currentState) => currentState;
}

2
ErsatzTV.FFmpeg/Encoder/EncoderImplicitVideo.cs

@ -4,6 +4,6 @@ public class EncoderImplicitVideo : EncoderBase @@ -4,6 +4,6 @@ public class EncoderImplicitVideo : EncoderBase
{
public override string Name => string.Empty;
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions => Array.Empty<string>();
public override string[] OutputOptions => Array.Empty<string>();
public override FrameState NextState(FrameState currentState) => currentState;
}

2
ErsatzTV.FFmpeg/Encoder/EncoderLibx265.cs

@ -12,7 +12,7 @@ public class EncoderLibx265 : EncoderBase @@ -12,7 +12,7 @@ public class EncoderLibx265 : EncoderBase
public override string Filter => new HardwareDownloadFilter(_currentState).Filter;
// TODO: is tag:v needed for mpegts?
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-c:v", Name, "-tag:v", "hvc1", "-x265-params", "log-level=error" };
public override string Name => "libx265";

2
ErsatzTV.FFmpeg/Encoder/Nvenc/EncoderHevcNvenc.cs

@ -18,7 +18,7 @@ public class EncoderHevcNvenc : EncoderBase @@ -18,7 +18,7 @@ public class EncoderHevcNvenc : EncoderBase
public override string Name => "hevc_nvenc";
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions =>
public override string[] OutputOptions =>
new[] { "-c:v", "hevc_nvenc", "-tag:v", "hvc1", "-b_ref_mode", _bFrames ? "1" : "0" };
public override FrameState NextState(FrameState currentState) => currentState with

2
ErsatzTV.FFmpeg/Encoder/Qsv/EncoderH264Qsv.cs

@ -7,7 +7,7 @@ public class EncoderH264Qsv : EncoderBase @@ -7,7 +7,7 @@ public class EncoderH264Qsv : EncoderBase
public override string Name => "h264_qsv";
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions =>
public override string[] OutputOptions =>
new[] { "-c:v", "h264_qsv", "-low_power", "0", "-look_ahead", "0" };
public override FrameState NextState(FrameState currentState) => currentState with

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

@ -7,7 +7,7 @@ public class EncoderHevcQsv : EncoderBase @@ -7,7 +7,7 @@ public class EncoderHevcQsv : EncoderBase
public override string Name => "hevc_qsv";
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions =>
public override string[] OutputOptions =>
new[] { "-c:v", "hevc_qsv", "-low_power", "0", "-look_ahead", "0" };
public override FrameState NextState(FrameState currentState) => currentState with

2
ErsatzTV.FFmpeg/Encoder/Qsv/EncoderMpeg2Qsv.cs

@ -7,7 +7,7 @@ public class EncoderMpeg2Qsv : EncoderBase @@ -7,7 +7,7 @@ public class EncoderMpeg2Qsv : EncoderBase
public override string Name => "mpeg2_qsv";
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions =>
public override string[] OutputOptions =>
new[] { "-c:v", "mpeg2_qsv", "-low_power", "0", "-look_ahead", "0" };
public override FrameState NextState(FrameState currentState) => currentState with

6
ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderH264Vaapi.cs

@ -12,11 +12,11 @@ public class EncoderH264Vaapi : EncoderBase @@ -12,11 +12,11 @@ public class EncoderH264Vaapi : EncoderBase
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions
public override string[] OutputOptions
{
get
{
IList<string> result = base.OutputOptions;
var result = new List<string>(base.OutputOptions);
if (_rateControlMode == RateControlMode.CQP)
{
@ -24,7 +24,7 @@ public class EncoderH264Vaapi : EncoderBase @@ -24,7 +24,7 @@ public class EncoderH264Vaapi : EncoderBase
result.Add("1");
}
return result;
return result.ToArray();
}
}

6
ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderHevcVaapi.cs

@ -12,11 +12,11 @@ public class EncoderHevcVaapi : EncoderBase @@ -12,11 +12,11 @@ public class EncoderHevcVaapi : EncoderBase
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions
public override string[] OutputOptions
{
get
{
IList<string> result = base.OutputOptions;
var result = new List<string>(base.OutputOptions);
if (_rateControlMode == RateControlMode.CQP)
{
@ -24,7 +24,7 @@ public class EncoderHevcVaapi : EncoderBase @@ -24,7 +24,7 @@ public class EncoderHevcVaapi : EncoderBase
result.Add("1");
}
return result;
return result.ToArray();
}
}

6
ErsatzTV.FFmpeg/Encoder/Vaapi/EncoderMpeg2Vaapi.cs

@ -12,11 +12,11 @@ public class EncoderMpeg2Vaapi : EncoderBase @@ -12,11 +12,11 @@ public class EncoderMpeg2Vaapi : EncoderBase
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions
public override string[] OutputOptions
{
get
{
IList<string> result = base.OutputOptions;
var result = new List<string>(base.OutputOptions);
if (_rateControlMode == RateControlMode.CQP)
{
@ -24,7 +24,7 @@ public class EncoderMpeg2Vaapi : EncoderBase @@ -24,7 +24,7 @@ public class EncoderMpeg2Vaapi : EncoderBase
result.Add("1");
}
return result;
return result.ToArray();
}
}

6
ErsatzTV.FFmpeg/Encoder/VideoToolbox/EncoderHevcVideoToolbox.cs

@ -11,12 +11,12 @@ public class EncoderHevcVideoToolbox : EncoderBase @@ -11,12 +11,12 @@ public class EncoderHevcVideoToolbox : EncoderBase
public override string Name => "hevc_videotoolbox";
public override StreamKind Kind => StreamKind.Video;
public override IList<string> OutputOptions => base.OutputOptions.Concat(
new List<string>
public override string[] OutputOptions => base.OutputOptions.Concat(
new[]
{
"-profile:v",
_desiredBitDepth == 10 ? "main10" : "main"
}).ToList();
}).ToArray();
public override FrameState NextState(FrameState currentState) => currentState with
{

14
ErsatzTV.FFmpeg/Environment/FFReportVariable.cs

@ -13,7 +13,7 @@ public class FFReportVariable : IPipelineStep @@ -13,7 +13,7 @@ public class FFReportVariable : IPipelineStep
_maybeConcatInputFile = maybeConcatInputFile;
}
public IList<EnvironmentVariable> EnvironmentVariables
public EnvironmentVariable[] EnvironmentVariables
{
get
{
@ -31,16 +31,16 @@ public class FFReportVariable : IPipelineStep @@ -31,16 +31,16 @@ public class FFReportVariable : IPipelineStep
fileName = fileName.Replace(@":/", @"\:/");
}
return new List<EnvironmentVariable>
return new[]
{
new("FFREPORT", $"file={fileName}:level=32")
new EnvironmentVariable("FFREPORT", $"file={fileName}:level=32")
};
}
}
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
}

12
ErsatzTV.FFmpeg/Environment/LibvaDriverNameVariable.cs

@ -6,14 +6,14 @@ public class LibvaDriverNameVariable : IPipelineStep @@ -6,14 +6,14 @@ public class LibvaDriverNameVariable : IPipelineStep
public LibvaDriverNameVariable(string driverName) => _driverName = driverName;
public IList<EnvironmentVariable> EnvironmentVariables => new List<EnvironmentVariable>
public EnvironmentVariable[] EnvironmentVariables => new[]
{
new("LIBVA_DRIVER_NAME", _driverName)
new EnvironmentVariable("LIBVA_DRIVER_NAME", _driverName)
};
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
}

6
ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AnalysisLevel>latest-Recommended</AnalysisLevel>
@ -11,8 +11,8 @@ @@ -11,8 +11,8 @@
<ItemGroup>
<PackageReference Include="CliWrap" Version="3.6.4" />
<PackageReference Include="LanguageExt.Core" Version="4.4.7" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
</ItemGroup>

10
ErsatzTV.FFmpeg/Filter/BaseFilter.cs

@ -4,11 +4,11 @@ namespace ErsatzTV.FFmpeg.Filter; @@ -4,11 +4,11 @@ namespace ErsatzTV.FFmpeg.Filter;
public abstract class BaseFilter : IPipelineFilterStep
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public virtual IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public virtual IList<string> FilterOptions => Array.Empty<string>();
public virtual IList<string> OutputOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public virtual string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public virtual string[] FilterOptions => Array.Empty<string>();
public virtual string[] OutputOptions => Array.Empty<string>();
public abstract FrameState NextState(FrameState currentState);
public abstract string Filter { get; }

23
ErsatzTV.FFmpeg/Filter/ComplexFilter.cs

@ -9,7 +9,6 @@ public class ComplexFilter : IPipelineStep @@ -9,7 +9,6 @@ public class ComplexFilter : IPipelineStep
private readonly Option<SubtitleInputFile> _maybeSubtitleInputFile;
private readonly Option<VideoInputFile> _maybeVideoInputFile;
private readonly Option<WatermarkInputFile> _maybeWatermarkInputFile;
private readonly List<string> _outputOptions;
private readonly PipelineContext _pipelineContext;
public ComplexFilter(
@ -27,24 +26,22 @@ public class ComplexFilter : IPipelineStep @@ -27,24 +26,22 @@ public class ComplexFilter : IPipelineStep
_pipelineContext = pipelineContext;
FilterChain = filterChain;
_outputOptions = new List<string>();
FilterOptions = Arguments();
}
// for testing
public FilterChain FilterChain { get; }
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions { get; }
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions { get; }
public IList<string> OutputOptions => _outputOptions;
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
private List<string> Arguments()
private string[] Arguments()
{
var audioLabel = "0:a";
var videoLabel = "0:v";
@ -162,7 +159,7 @@ public class ComplexFilter : IPipelineStep @@ -162,7 +159,7 @@ public class ComplexFilter : IPipelineStep
}
// overlay subtitle
if (!string.IsNullOrWhiteSpace(subtitleLabel) && FilterChain.SubtitleOverlayFilterSteps.Any())
if (!string.IsNullOrWhiteSpace(subtitleLabel) && FilterChain.SubtitleOverlayFilterSteps.Count != 0)
{
subtitleOverlayFilterComplex += $"{ProperLabel(videoLabel)}{ProperLabel(subtitleLabel)}";
subtitleOverlayFilterComplex += string.Join(
@ -174,7 +171,7 @@ public class ComplexFilter : IPipelineStep @@ -174,7 +171,7 @@ public class ComplexFilter : IPipelineStep
}
// overlay watermark
if (!string.IsNullOrWhiteSpace(watermarkLabel) && FilterChain.WatermarkOverlayFilterSteps.Any())
if (!string.IsNullOrWhiteSpace(watermarkLabel) && FilterChain.WatermarkOverlayFilterSteps.Count != 0)
{
watermarkOverlayFilterComplex += $"{ProperLabel(videoLabel)}{ProperLabel(watermarkLabel)}";
watermarkOverlayFilterComplex += string.Join(
@ -186,7 +183,7 @@ public class ComplexFilter : IPipelineStep @@ -186,7 +183,7 @@ public class ComplexFilter : IPipelineStep
}
// pixel format
if (FilterChain.PixelFormatFilterSteps.Any())
if (FilterChain.PixelFormatFilterSteps.Count != 0)
{
pixelFormatFilterComplex += $"{ProperLabel(videoLabel)}";
pixelFormatFilterComplex += string.Join(
@ -253,7 +250,7 @@ public class ComplexFilter : IPipelineStep @@ -253,7 +250,7 @@ public class ComplexFilter : IPipelineStep
}
}
return result;
return result.ToArray();
}
private static string ProperLabel(string label) =>

14
ErsatzTV.FFmpeg/Filter/VideoFilter.cs

@ -8,15 +8,15 @@ public class VideoFilter : IPipelineStep @@ -8,15 +8,15 @@ public class VideoFilter : IPipelineStep
public VideoFilter(IEnumerable<IPipelineFilterStep> filterSteps) => _filterSteps = filterSteps;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Arguments();
public IList<string> OutputOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Arguments();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
private IList<string> Arguments() =>
new List<string>
private string[] Arguments() =>
new []
{
"-vf",
string.Join(",", _filterSteps.Map(fs => fs.Filter))

10
ErsatzTV.FFmpeg/Format/ConcatInputFormat.cs

@ -5,10 +5,10 @@ namespace ErsatzTV.FFmpeg.Format; @@ -5,10 +5,10 @@ namespace ErsatzTV.FFmpeg.Format;
public class ConcatInputFormat : IInputOption
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => new List<string>
public string[] InputOptions(InputFile inputFile) => new[]
{
"-f", "concat",
"-safe", "0",
@ -16,8 +16,8 @@ public class ConcatInputFormat : IInputOption @@ -16,8 +16,8 @@ public class ConcatInputFormat : IInputOption
"-probesize", "32"
};
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
public bool AppliesTo(AudioInputFile audioInputFile) => false;

10
ErsatzTV.FFmpeg/GlobalOption/GlobalOption.cs

@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.GlobalOption; @@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.GlobalOption;
public abstract class GlobalOption : IPipelineStep
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public abstract IList<string> GlobalOptions { get; }
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public abstract string[] GlobalOptions { get; }
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public virtual FrameState NextState(FrameState currentState) => currentState;
}

2
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/AmfHardwareAccelerationOption.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
public class AmfHardwareAccelerationOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-hwaccel", "dxva2" };
public override string[] GlobalOptions => new[] { "-hwaccel", "dxva2" };
public override FrameState NextState(FrameState currentState) => currentState with
{

2
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class CudaHardwareAccelerationOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-hwaccel", "cuda" };
public override string[] GlobalOptions => new[] { "-hwaccel", "cuda" };
}

4
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs

@ -15,7 +15,7 @@ public class QsvHardwareAccelerationOption : GlobalOption @@ -15,7 +15,7 @@ public class QsvHardwareAccelerationOption : GlobalOption
public QsvHardwareAccelerationOption(Option<string> qsvDevice) => _qsvDevice = qsvDevice;
public override IList<string> GlobalOptions
public override string[] GlobalOptions
{
get
{
@ -42,7 +42,7 @@ public class QsvHardwareAccelerationOption : GlobalOption @@ -42,7 +42,7 @@ public class QsvHardwareAccelerationOption : GlobalOption
result.AddRange(initDevices);
return result;
return result.ToArray();
}
}

17
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/VaapiHardwareAccelerationOption.cs

@ -13,20 +13,9 @@ public class VaapiHardwareAccelerationOption : GlobalOption @@ -13,20 +13,9 @@ public class VaapiHardwareAccelerationOption : GlobalOption
_decodeCapability = decodeCapability;
}
public override IList<string> GlobalOptions
{
get
{
var result = new List<string> { "-vaapi_device", _vaapiDevice };
if (_decodeCapability == FFmpegCapability.Hardware)
{
result.InsertRange(0, new[] { "-hwaccel", "vaapi" });
}
return result;
}
}
public override string[] GlobalOptions => _decodeCapability == FFmpegCapability.Hardware
? new[] { "-hwaccel", "vaapi", "-vaapi_device", _vaapiDevice }
: new[] { "-vaapi_device", _vaapiDevice };
public override FrameState NextState(FrameState currentState) => currentState with
{

2
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/VideoToolboxHardwareAccelerationOption.cs

@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
public class VideoToolboxHardwareAccelerationOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-hwaccel", "videotoolbox" };
public override string[] GlobalOptions => new[] { "-hwaccel", "videotoolbox" };
public override FrameState NextState(FrameState currentState) => currentState with
{

2
ErsatzTV.FFmpeg/GlobalOption/HideBannerOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class HideBannerOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-hide_banner" };
public override string[] GlobalOptions => new[] { "-hide_banner" };
}

2
ErsatzTV.FFmpeg/GlobalOption/LoglevelErrorOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class LoglevelErrorOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-loglevel", "error" };
public override string[] GlobalOptions => new[] { "-loglevel", "error" };
}

2
ErsatzTV.FFmpeg/GlobalOption/NoStatsOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class NoStatsOption : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-nostats" };
public override string[] GlobalOptions => new[] { "-nostats" };
}

2
ErsatzTV.FFmpeg/GlobalOption/StandardFormatFlags.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class StandardFormatFlags : GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-fflags", "+genpts+discardcorrupt+igndts" };
public override string[] GlobalOptions => new[] { "-fflags", "+genpts+discardcorrupt+igndts" };
}

10
ErsatzTV.FFmpeg/GlobalOption/StreamSeekFilterOption.cs

@ -8,11 +8,11 @@ public class StreamSeekFilterOption : IPipelineStep @@ -8,11 +8,11 @@ public class StreamSeekFilterOption : IPipelineStep
public StreamSeekFilterOption(TimeSpan start) => _start = start;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => new List<string> { "-ss", $"{_start:c}" };
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => new[] { "-ss", $"{_start:c}" };
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
}

2
ErsatzTV.FFmpeg/GlobalOption/ThreadCountOption.cs

@ -8,6 +8,6 @@ public class ThreadCountOption : GlobalOption @@ -8,6 +8,6 @@ public class ThreadCountOption : GlobalOption
public ThreadCountOption(int threadCount) => _threadCount = threadCount;
public override IList<string> GlobalOptions => new List<string>
public override string[] GlobalOptions => new[]
{ "-threads", _threadCount.ToString(CultureInfo.InvariantCulture) };
}

10
ErsatzTV.FFmpeg/IPipelineStep.cs

@ -4,11 +4,11 @@ namespace ErsatzTV.FFmpeg; @@ -4,11 +4,11 @@ namespace ErsatzTV.FFmpeg;
public interface IPipelineStep
{
IList<EnvironmentVariable> EnvironmentVariables { get; }
IList<string> GlobalOptions { get; }
IList<string> FilterOptions { get; }
IList<string> OutputOptions { get; }
IList<string> InputOptions(InputFile inputFile);
EnvironmentVariable[] EnvironmentVariables { get; }
string[] GlobalOptions { get; }
string[] FilterOptions { get; }
string[] OutputOptions { get; }
string[] InputOptions(InputFile inputFile);
FrameState NextState(FrameState currentState);
}

10
ErsatzTV.FFmpeg/InputOption/CopyTimestampInputOption.cs

@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption; @@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption;
public class CopyTimestampInputOption : IInputOption
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => new List<string> { "-copyts" };
public string[] InputOptions(InputFile inputFile) => new[] { "-copyts" };
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
public bool AppliesTo(AudioInputFile audioInputFile) => false;

10
ErsatzTV.FFmpeg/InputOption/DoNotIgnoreLoopInputOption.cs

@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption; @@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption;
public class DoNotIgnoreLoopInputOption : IInputOption
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => new List<string> { "-ignore_loop", "0" };
public string[] InputOptions(InputFile inputFile) => new[] { "-ignore_loop", "0" };
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
public bool AppliesTo(AudioInputFile audioInputFile) => false;

16
ErsatzTV.FFmpeg/InputOption/InfiniteLoopInputOption.cs

@ -9,26 +9,26 @@ public class InfiniteLoopInputOption : IInputOption @@ -9,26 +9,26 @@ public class InfiniteLoopInputOption : IInputOption
public InfiniteLoopInputOption(HardwareAccelerationMode hardwareAccelerationMode) =>
_hardwareAccelerationMode = hardwareAccelerationMode;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile)
public string[] InputOptions(InputFile inputFile)
{
// loop 1 for still images
if (inputFile.Streams.OfType<VideoStream>().Any(s => s.StillImage))
{
return new List<string> { "-loop", "1" };
return new[] { "-loop", "1" };
}
// stream_loop for looped video i.e. filler
return new List<string> { "-stream_loop", "-1" };
return new[] { "-stream_loop", "-1" };
}
public IList<string> FilterOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions =>
public string[] OutputOptions =>
_hardwareAccelerationMode is HardwareAccelerationMode.Qsv or HardwareAccelerationMode.Vaapi
? new List<string> { "-noautoscale" }
? new[] { "-noautoscale" }
: Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState with { Realtime = true };

10
ErsatzTV.FFmpeg/InputOption/LavfiInputOption.cs

@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption; @@ -4,13 +4,13 @@ namespace ErsatzTV.FFmpeg.InputOption;
public class LavfiInputOption : IInputOption
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => new List<string> { "-f", "lavfi" };
public string[] InputOptions(InputFile inputFile) => new[] { "-f", "lavfi" };
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
public bool AppliesTo(AudioInputFile audioInputFile) => true;

2
ErsatzTV.FFmpeg/InputOption/NoStandardInputOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class NoStandardInputOption : GlobalOption.GlobalOption
{
public override IList<string> GlobalOptions => new List<string> { "-nostdin" };
public override string[] GlobalOptions => new[] { "-nostdin" };
}

14
ErsatzTV.FFmpeg/InputOption/ReadrateInputOption.cs

@ -21,11 +21,11 @@ public class ReadrateInputOption : IInputOption @@ -21,11 +21,11 @@ public class ReadrateInputOption : IInputOption
_logger = logger;
}
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public string[] GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile)
public string[] InputOptions(InputFile inputFile)
{
var result = new List<string> { "-readrate", "1.0" };
@ -37,7 +37,7 @@ public class ReadrateInputOption : IInputOption @@ -37,7 +37,7 @@ public class ReadrateInputOption : IInputOption
"FFmpeg is missing {Option} option; unable to transcode faster than realtime",
FFmpegKnownOption.ReadrateInitialBurst.Name);
return result;
return result.ToArray();
}
result.AddRange(
@ -48,11 +48,11 @@ public class ReadrateInputOption : IInputOption @@ -48,11 +48,11 @@ public class ReadrateInputOption : IInputOption
});
}
return result;
return result.ToArray();
}
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState with { Realtime = true };
public bool AppliesTo(AudioInputFile audioInputFile) => true;

10
ErsatzTV.FFmpeg/InputOption/StreamSeekInputOption.cs

@ -8,11 +8,11 @@ public class StreamSeekInputOption : IInputOption @@ -8,11 +8,11 @@ public class StreamSeekInputOption : IInputOption
public StreamSeekInputOption(TimeSpan start) => _start = start;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => new List<string> { "-ss", $"{_start:c}" };
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => new[] { "-ss", $"{_start:c}" };
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => Array.Empty<string>();
public FrameState NextState(FrameState currentState) => currentState;
public bool AppliesTo(AudioInputFile audioInputFile) => true;

12
ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs

@ -24,12 +24,12 @@ public class OutputFormatHls : IPipelineStep @@ -24,12 +24,12 @@ public class OutputFormatHls : IPipelineStep
_oneSecondGop = oneSecondGop;
}
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions
public string[] OutputOptions
{
get
{
@ -38,7 +38,7 @@ public class OutputFormatHls : IPipelineStep @@ -38,7 +38,7 @@ public class OutputFormatHls : IPipelineStep
int gop = _oneSecondGop ? frameRate : frameRate * SEGMENT_SECONDS;
return new List<string>
return new[]
{
"-g", $"{gop}",
"-keyint_min", $"{frameRate * SEGMENT_SECONDS}",

10
ErsatzTV.FFmpeg/OutputFormat/OutputFormatMkv.cs

@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.OutputFormat; @@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.OutputFormat;
public class OutputFormatMkv : IPipelineStep
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => new List<string> { "-f", "matroska" };
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => new[] { "-f", "matroska" };
public FrameState NextState(FrameState currentState) => currentState;
}

10
ErsatzTV.FFmpeg/OutputFormat/OutputFormatMp4.cs

@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.OutputFormat; @@ -4,10 +4,10 @@ namespace ErsatzTV.FFmpeg.OutputFormat;
public class OutputFormatMp4 : IPipelineStep
{
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => new List<string> { "-f", "mp4" };
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public string[] OutputOptions => new[] { "-f", "mp4" };
public FrameState NextState(FrameState currentState) => currentState;
}

14
ErsatzTV.FFmpeg/OutputFormat/OutputFormatMpegTs.cs

@ -8,14 +8,14 @@ public class OutputFormatMpegTs : IPipelineStep @@ -8,14 +8,14 @@ public class OutputFormatMpegTs : IPipelineStep
public OutputFormatMpegTs(bool initialDiscontinuity = true) => _initialDiscontinuity = initialDiscontinuity;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => _initialDiscontinuity
? new List<string> { "-f", "mpegts", "-mpegts_flags", "+initial_discontinuity" }
: new List<string> { "-f", "mpegts" };
public string[] OutputOptions => _initialDiscontinuity
? new[] { "-f", "mpegts", "-mpegts_flags", "+initial_discontinuity" }
: new[] { "-f", "mpegts" };
public FrameState NextState(FrameState currentState) => currentState;
}

2
ErsatzTV.FFmpeg/OutputOption/AudioBitrateOutputOption.cs

@ -6,7 +6,7 @@ public class AudioBitrateOutputOption : OutputOption @@ -6,7 +6,7 @@ public class AudioBitrateOutputOption : OutputOption
public AudioBitrateOutputOption(int bitrate) => _bitrate = bitrate;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{
"-b:a", $"{_bitrate}k",
"-maxrate:a", $"{_bitrate}k"

2
ErsatzTV.FFmpeg/OutputOption/AudioBufferSizeOutputOption.cs

@ -6,7 +6,7 @@ public class AudioBufferSizeOutputOption : OutputOption @@ -6,7 +6,7 @@ public class AudioBufferSizeOutputOption : OutputOption
public AudioBufferSizeOutputOption(int decoderBufferSize) => _decoderBufferSize = decoderBufferSize;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{
"-bufsize:a", $"{_decoderBufferSize}k"
};

4
ErsatzTV.FFmpeg/OutputOption/AudioChannelsOutputOption.cs

@ -16,13 +16,13 @@ public class AudioChannelsOutputOption : OutputOption @@ -16,13 +16,13 @@ public class AudioChannelsOutputOption : OutputOption
_desiredChannels = desiredChannels;
}
public override IList<string> OutputOptions
public override string[] OutputOptions
{
get
{
if (_sourceChannels != _desiredChannels || _audioFormat == Some(AudioFormat.Aac) && _desiredChannels > 2)
{
return new List<string>
return new[]
{
"-ac", _desiredChannels.ToString(CultureInfo.InvariantCulture)
};

2
ErsatzTV.FFmpeg/OutputOption/AudioSampleRateOutputOption.cs

@ -6,5 +6,5 @@ public class AudioSampleRateOutputOption : OutputOption @@ -6,5 +6,5 @@ public class AudioSampleRateOutputOption : OutputOption
public AudioSampleRateOutputOption(int sampleRate) => _sampleRate = sampleRate;
public override IList<string> OutputOptions => new List<string> { "-ar", $"{_sampleRate}k" };
public override string[] OutputOptions => new[] { "-ar", $"{_sampleRate}k" };
}

2
ErsatzTV.FFmpeg/OutputOption/ClosedGopOutputOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class ClosedGopOutputOption : OutputOption
{
public override IList<string> OutputOptions => new List<string> { "-flags", "cgop" };
public override string[] OutputOptions => new[] { "-flags", "cgop" };
}

2
ErsatzTV.FFmpeg/OutputOption/FastStartOutputOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class FastStartOutputOption : OutputOption
{
public override IList<string> OutputOptions => new List<string> { "-movflags", "+faststart" };
public override string[] OutputOptions => new[] { "-movflags", "+faststart" };
}

2
ErsatzTV.FFmpeg/OutputOption/FileNameOutputOption.cs

@ -6,5 +6,5 @@ public class FileNameOutputOption : OutputOption @@ -6,5 +6,5 @@ public class FileNameOutputOption : OutputOption
public FileNameOutputOption(string outputFile) => _outputFile = outputFile;
public override IList<string> OutputOptions => new List<string> { _outputFile };
public override string[] OutputOptions => new[] { _outputFile };
}

10
ErsatzTV.FFmpeg/OutputOption/FrameRateOutputOption.cs

@ -9,12 +9,12 @@ public class FrameRateOutputOption : IPipelineStep @@ -9,12 +9,12 @@ public class FrameRateOutputOption : IPipelineStep
public FrameRateOutputOption(int frameRate) => _frameRate = frameRate;
public IList<EnvironmentVariable> EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public IList<string> GlobalOptions => Array.Empty<string>();
public IList<string> InputOptions(InputFile inputFile) => Array.Empty<string>();
public IList<string> FilterOptions => Array.Empty<string>();
public EnvironmentVariable[] EnvironmentVariables => Array.Empty<EnvironmentVariable>();
public string[] GlobalOptions => Array.Empty<string>();
public string[] InputOptions(InputFile inputFile) => Array.Empty<string>();
public string[] FilterOptions => Array.Empty<string>();
public IList<string> OutputOptions => new List<string>
public string[] OutputOptions => new[]
{ "-r", _frameRate.ToString(CultureInfo.InvariantCulture), "-vsync", "cfr" };
public FrameState NextState(FrameState currentState) => currentState with

2
ErsatzTV.FFmpeg/OutputOption/MapAllStreamsOutputOption.cs

@ -2,5 +2,5 @@ namespace ErsatzTV.FFmpeg.OutputOption; @@ -2,5 +2,5 @@ namespace ErsatzTV.FFmpeg.OutputOption;
public class MapAllStreamsOutputOption : OutputOption
{
public override IList<string> OutputOptions => new[] { "-map", "0" };
public override string[] OutputOptions => new[] { "-map", "0" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/DoNotMapMetadataOutputOption.cs

@ -2,5 +2,5 @@ @@ -2,5 +2,5 @@
public class DoNotMapMetadataOutputOption : OutputOption
{
public override IList<string> OutputOptions => new List<string> { "-map_metadata", "-1" };
public override string[] OutputOptions => new[] { "-map_metadata", "-1" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataAudioLanguageOutputOption.cs

@ -6,6 +6,6 @@ public class MetadataAudioLanguageOutputOption : OutputOption @@ -6,6 +6,6 @@ public class MetadataAudioLanguageOutputOption : OutputOption
public MetadataAudioLanguageOutputOption(string audioLanguage) => _audioLanguage = audioLanguage;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-metadata:s:a:0", $"language={_audioLanguage}" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataServiceNameOutputOption.cs

@ -6,6 +6,6 @@ public class MetadataServiceNameOutputOption : OutputOption @@ -6,6 +6,6 @@ public class MetadataServiceNameOutputOption : OutputOption
public MetadataServiceNameOutputOption(string serviceName) => _serviceName = serviceName;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-metadata", $"service_name=\"{_serviceName}\"" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataServiceProviderOutputOption.cs

@ -6,6 +6,6 @@ public class MetadataServiceProviderOutputOption : OutputOption @@ -6,6 +6,6 @@ public class MetadataServiceProviderOutputOption : OutputOption
public MetadataServiceProviderOutputOption(string serviceProvider) => _serviceProvider = serviceProvider;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-metadata", $"service_provider=\"{_serviceProvider}\"" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataSubtitleLanguageOutputOption.cs

@ -6,6 +6,6 @@ public class MetadataSubtitleLanguageOutputOption : OutputOption @@ -6,6 +6,6 @@ public class MetadataSubtitleLanguageOutputOption : OutputOption
public MetadataSubtitleLanguageOutputOption(string subtitleLanguage) => _subtitleLanguage = subtitleLanguage;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-metadata:s:s:0", $"language={_subtitleLanguage}" };
}

2
ErsatzTV.FFmpeg/OutputOption/Metadata/MetadataSubtitleTitleOutputOption.cs

@ -6,6 +6,6 @@ public class MetadataSubtitleTitleOutputOption : OutputOption @@ -6,6 +6,6 @@ public class MetadataSubtitleTitleOutputOption : OutputOption
public MetadataSubtitleTitleOutputOption(string subtitleTitle) => _subtitleTitle = subtitleTitle;
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-metadata:s:s:0", $"title={_subtitleTitle}" };
}

2
ErsatzTV.FFmpeg/OutputOption/Mp4OutputOptions.cs

@ -2,6 +2,6 @@ @@ -2,6 +2,6 @@
public class Mp4OutputOptions : OutputOption
{
public override IList<string> OutputOptions => new List<string>
public override string[] OutputOptions => new[]
{ "-movflags", "+faststart+frag_keyframe+separate_moof+omit_tfhd_offset+empty_moov+delay_moov" };
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save