Browse Source

fix bug with unsupported aac channel layouts (#893)

* fix bug with unsupported aac channel layouts

* update dependencies
pull/895/head
Jason Dove 4 years ago committed by GitHub
parent
commit
b53cfebac1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 13
      ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs
  3. 72
      ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs
  4. 31
      ErsatzTV.FFmpeg/Option/AudioChannelsOutputOption.cs
  5. 11
      ErsatzTV.FFmpeg/PipelineBuilder.cs
  6. 6
      ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj
  7. 8
      ErsatzTV/ErsatzTV.csproj

1
CHANGELOG.md

@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Fixed
- Fix subtitle stream selection when subtitle language is different than audio language
- Fix bug with unsupported AAC channel layouts
## [0.6.3-beta] - 2022-07-04
### Fixed

13
ErsatzTV.Core/FFmpeg/FFmpegPlaybackSettingsCalculator.cs

@ -148,14 +148,11 @@ public class FFmpegPlaybackSettingsCalculator @@ -148,14 +148,11 @@ public class FFmpegPlaybackSettingsCalculator
result.AudioBitrate = ffmpegProfile.AudioBitrate;
result.AudioBufferSize = ffmpegProfile.AudioBufferSize;
audioStream.IfSome(
stream =>
{
if (stream.Channels != ffmpegProfile.AudioChannels)
{
result.AudioChannels = ffmpegProfile.AudioChannels;
}
});
foreach (MediaStream _ in audioStream)
{
// this can be optimized out later, depending on the audio codec
result.AudioChannels = ffmpegProfile.AudioChannels;
}
result.AudioSampleRate = ffmpegProfile.AudioSampleRate;
result.AudioDuration = outPoint - inPoint;

72
ErsatzTV.FFmpeg.Tests/PipelineBuilderTests.cs

@ -86,7 +86,77 @@ public class PipelineGeneratorTests @@ -86,7 +86,77 @@ public class PipelineGeneratorTests
string command = PrintCommand(videoInputFile, audioInputFile, None, None, result);
command.Should().Be(
"-threads 1 -nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -re -i /tmp/whatever.mkv -map 0:1 -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:a aac -ac 2 -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
"-threads 1 -nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -re -i /tmp/whatever.mkv -map 0:1 -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:a aac -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
}
[Test]
public void Aac_6_Channel_Should_Specify_Audio_Channels()
{
var videoInputFile = new VideoInputFile(
"/tmp/whatever.mkv",
new List<VideoStream>
{ new(0, VideoFormat.H264, new PixelFormatYuv420P(), new FrameSize(1920, 1080), "24", false) });
var audioInputFile = new AudioInputFile(
"/tmp/whatever.mkv",
new List<AudioStream> { new(1, AudioFormat.Aac, 6) },
new AudioState(
AudioFormat.Aac,
6,
320,
640,
48,
Option<TimeSpan>.None,
false));
var desiredState = new FrameState(
true,
false,
VideoFormat.Hevc,
new PixelFormatYuv420P(),
new FrameSize(1920, 1080),
new FrameSize(1920, 1080),
Option<int>.None,
2000,
4000,
90_000,
false);
var ffmpegState = new FFmpegState(
false,
HardwareAccelerationMode.None,
HardwareAccelerationMode.None,
Option<string>.None,
Option<string>.None,
TimeSpan.FromSeconds(1),
Option<TimeSpan>.None,
false,
Option<string>.None,
Option<string>.None,
Option<string>.None,
OutputFormatKind.MpegTs,
Option<string>.None,
Option<string>.None,
0,
Option<int>.None);
var builder = new PipelineBuilder(
new DefaultHardwareCapabilities(),
videoInputFile,
audioInputFile,
None,
None,
"",
"",
_logger);
FFmpegPipeline result = builder.Build(ffmpegState, desiredState);
result.PipelineSteps.Should().HaveCountGreaterThan(0);
result.PipelineSteps.Should().Contain(ps => ps is EncoderLibx265);
string command = PrintCommand(videoInputFile, audioInputFile, None, None, result);
command.Should().Be(
"-threads 1 -nostdin -hide_banner -nostats -loglevel error -fflags +genpts+discardcorrupt+igndts -ss 00:00:01 -c:v h264 -re -i /tmp/whatever.mkv -map 0:1 -map 0:0 -muxdelay 0 -muxpreload 0 -movflags +faststart -flags cgop -sc_threshold 0 -video_track_timescale 90000 -b:v 2000k -maxrate:v 2000k -bufsize:v 4000k -c:a aac -ac 6 -b:a 320k -maxrate:a 320k -bufsize:a 640k -ar 48k -c:v libx265 -tag:v hvc1 -x265-params log-level=error -f mpegts -mpegts_flags +initial_discontinuity pipe:1");
}
[Test]

31
ErsatzTV.FFmpeg/Option/AudioChannelsOutputOption.cs

@ -1,10 +1,33 @@ @@ -1,10 +1,33 @@
namespace ErsatzTV.FFmpeg.Option;
using ErsatzTV.FFmpeg.Format;
namespace ErsatzTV.FFmpeg.Option;
public class AudioChannelsOutputOption : OutputOption
{
private readonly int _channels;
private readonly Option<string> _audioFormat;
private readonly int _desiredChannels;
private readonly int _sourceChannels;
public AudioChannelsOutputOption(Option<string> audioFormat, int sourceChannels, int desiredChannels)
{
_audioFormat = audioFormat;
_sourceChannels = sourceChannels;
_desiredChannels = desiredChannels;
}
public AudioChannelsOutputOption(int channels) => _channels = channels;
public override IList<string> OutputOptions
{
get
{
if (_sourceChannels != _desiredChannels || _audioFormat == Some(AudioFormat.Aac) && _desiredChannels > 2)
{
return new List<string>
{
"-ac", _desiredChannels.ToString()
};
}
public override IList<string> OutputOptions => new List<string> { "-ac", _channels.ToString() };
return Array.Empty<string>();
}
}
}

11
ErsatzTV.FFmpeg/PipelineBuilder.cs

@ -538,9 +538,16 @@ public class PipelineBuilder @@ -538,9 +538,16 @@ public class PipelineBuilder
_pipelineSteps.Add(step);
}
foreach (int desiredAudioChannels in audioInputFile.DesiredState.AudioChannels)
foreach (AudioStream audioStream in audioInputFile.AudioStreams.HeadOrNone())
{
_pipelineSteps.Add(new AudioChannelsOutputOption(desiredAudioChannels));
foreach (int desiredAudioChannels in audioInputFile.DesiredState.AudioChannels)
{
_pipelineSteps.Add(
new AudioChannelsOutputOption(
audioInputFile.DesiredState.AudioFormat,
audioStream.Channels,
desiredAudioChannels));
}
}
foreach (int desiredBitrate in audioInputFile.DesiredState.AudioBitrate)

6
ErsatzTV.Infrastructure/ErsatzTV.Infrastructure.csproj

@ -14,12 +14,12 @@ @@ -14,12 +14,12 @@
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00016" />
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00016" />
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00016" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.6">
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.7" />
<PackageReference Include="Microsoft.VisualStudio.Threading.Analyzers" Version="17.2.32">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

8
ErsatzTV/ErsatzTV.csproj

@ -57,14 +57,14 @@ @@ -57,14 +57,14 @@
<PackageReference Include="Bugsnag.AspNet.Core" Version="3.1.0" />
<PackageReference Include="FluentValidation" Version="11.1.0" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.1.2" />
<PackageReference Include="HtmlSanitizer" Version="7.1.512" />
<PackageReference Include="HtmlSanitizer" Version="7.1.542" />
<PackageReference Include="LanguageExt.Core" Version="4.2.9" />
<PackageReference Include="Markdig" Version="0.30.2" />
<PackageReference Include="MediatR.Courier.DependencyInjection" Version="5.0.0" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.6" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.6">
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.SpaServices.Extensions" Version="6.0.7" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="6.0.7">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

Loading…
Cancel
Save