Browse Source

fix vaapi pipeline with mpeg4 content (#51)

pull/52/head
Jason Dove 5 years ago committed by GitHub
parent
commit
bd231d57a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 53
      ErsatzTV.Core.Tests/FFmpeg/FFmpegComplexFilterBuilderTests.cs
  2. 1
      ErsatzTV.Core/Domain/MediaItem/MediaVersion.cs
  3. 23
      ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs
  4. 2
      ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs
  5. 3
      ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs
  6. 1497
      ErsatzTV.Infrastructure/Migrations/20210308215756_Add_MediaVersionVideoProfile.Designer.cs
  7. 19
      ErsatzTV.Infrastructure/Migrations/20210308215756_Add_MediaVersionVideoProfile.cs
  8. 1497
      ErsatzTV.Infrastructure/Migrations/20210308215926_Reset_MediaVersionDateUpdated.Designer.cs
  9. 14
      ErsatzTV.Infrastructure/Migrations/20210308215926_Reset_MediaVersionDateUpdated.cs
  10. 3
      ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs
  11. 1
      ErsatzTV.Infrastructure/Plex/Models/PlexMediaResponse.cs
  12. 1
      ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

53
ErsatzTV.Core.Tests/FFmpeg/FFmpegComplexFilterBuilderTests.cs

@ -275,44 +275,94 @@ namespace ErsatzTV.Core.Tests.FFmpeg
} }
[Test] [Test]
[TestCase(true, false, false, "[0:v]deinterlace_vaapi[v]", "[v]")] [TestCase("h264", true, false, false, "[0:v]deinterlace_vaapi[v]", "[v]")]
[TestCase( [TestCase(
"h264",
true, true,
true, true,
false, false,
"[0:v]deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]", "[0:v]deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]",
"[v]")] "[v]")]
[TestCase( [TestCase(
"h264",
true, true,
false, false,
true, true,
"[0:v]deinterlace_vaapi,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]", "[0:v]deinterlace_vaapi,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")] "[v]")]
[TestCase( [TestCase(
"h264",
true, true,
true, true,
true, true,
"[0:v]deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]", "[0:v]deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")] "[v]")]
[TestCase( [TestCase(
"h264",
false, false,
true, true,
false, false,
"[0:v]scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]", "[0:v]scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]",
"[v]")] "[v]")]
[TestCase( [TestCase(
"h264",
false, false,
false, false,
true, true,
"[0:v]hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]", "[0:v]hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")] "[v]")]
[TestCase( [TestCase(
"h264",
false, false,
true, true,
true, true,
"[0:v]scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]", "[0:v]scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")] "[v]")]
[TestCase("mpeg4", true, false, false, "[0:v]hwupload,deinterlace_vaapi[v]", "[v]")]
[TestCase(
"mpeg4",
true,
true,
false,
"[0:v]hwupload,deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]",
"[v]")]
[TestCase(
"mpeg4",
true,
false,
true,
"[0:v]hwupload,deinterlace_vaapi,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")]
[TestCase(
"mpeg4",
true,
true,
true,
"[0:v]hwupload,deinterlace_vaapi,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")]
[TestCase(
"mpeg4",
false,
true,
false,
"[0:v]hwupload,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,hwupload[v]",
"[v]")]
[TestCase(
"mpeg4",
false,
false,
true,
"[0:v]setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")]
[TestCase(
"mpeg4",
false,
true,
true,
"[0:v]hwupload,scale_vaapi=w=1920:h=1000,hwdownload,format=nv12|vaapi,setsar=1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,hwupload[v]",
"[v]")]
public void Should_Return_VAAPI_Video_Filter( public void Should_Return_VAAPI_Video_Filter(
string codec,
bool deinterlace, bool deinterlace,
bool scale, bool scale,
bool pad, bool pad,
@ -321,6 +371,7 @@ namespace ErsatzTV.Core.Tests.FFmpeg
{ {
FFmpegComplexFilterBuilder builder = new FFmpegComplexFilterBuilder() FFmpegComplexFilterBuilder builder = new FFmpegComplexFilterBuilder()
.WithHardwareAcceleration(HardwareAccelerationKind.Vaapi) .WithHardwareAcceleration(HardwareAccelerationKind.Vaapi)
.WithInputCodec(codec)
.WithDeinterlace(deinterlace); .WithDeinterlace(deinterlace);
if (scale) if (scale)

1
ErsatzTV.Core/Domain/MediaItem/MediaVersion.cs

@ -15,6 +15,7 @@ namespace ErsatzTV.Core.Domain
public string SampleAspectRatio { get; set; } public string SampleAspectRatio { get; set; }
public string DisplayAspectRatio { get; set; } public string DisplayAspectRatio { get; set; }
public string VideoCodec { get; set; } public string VideoCodec { get; set; }
public string VideoProfile { get; set; }
public string AudioCodec { get; set; } public string AudioCodec { get; set; }
public VideoScanKind VideoScanKind { get; set; } public VideoScanKind VideoScanKind { get; set; }
public DateTime DateAdded { get; set; } public DateTime DateAdded { get; set; }

23
ErsatzTV.Core/FFmpeg/FFmpegComplexFilterBuilder.cs

@ -14,6 +14,7 @@ namespace ErsatzTV.Core.FFmpeg
private Option<TimeSpan> _audioDuration = None; private Option<TimeSpan> _audioDuration = None;
private bool _deinterlace; private bool _deinterlace;
private Option<HardwareAccelerationKind> _hardwareAccelerationKind = None; private Option<HardwareAccelerationKind> _hardwareAccelerationKind = None;
private string _inputCodec;
private Option<IDisplaySize> _padToSize = None; private Option<IDisplaySize> _padToSize = None;
private Option<IDisplaySize> _scaleToSize = None; private Option<IDisplaySize> _scaleToSize = None;
@ -47,6 +48,12 @@ namespace ErsatzTV.Core.FFmpeg
return this; return this;
} }
public FFmpegComplexFilterBuilder WithInputCodec(string codec)
{
_inputCodec = codec;
return this;
}
public Option<FFmpegComplexFilter> Build() public Option<FFmpegComplexFilter> Build()
{ {
var complexFilter = new StringBuilder(); var complexFilter = new StringBuilder();
@ -55,6 +62,13 @@ namespace ErsatzTV.Core.FFmpeg
var audioLabel = "0:a"; var audioLabel = "0:a";
HardwareAccelerationKind acceleration = _hardwareAccelerationKind.IfNone(HardwareAccelerationKind.None); HardwareAccelerationKind acceleration = _hardwareAccelerationKind.IfNone(HardwareAccelerationKind.None);
bool isHardwareDecode = acceleration switch
{
HardwareAccelerationKind.Vaapi => _inputCodec != "mpeg4",
HardwareAccelerationKind.Nvenc => true,
HardwareAccelerationKind.Qsv => true,
_ => false
};
_audioDuration.IfSome( _audioDuration.IfSome(
audioDuration => audioDuration =>
@ -67,6 +81,13 @@ namespace ErsatzTV.Core.FFmpeg
var filterQueue = new List<string>(); var filterQueue = new List<string>();
bool usesHardwareFilters = acceleration != HardwareAccelerationKind.None && !isHardwareDecode &&
(_deinterlace || _scaleToSize.IsSome);
if (usesHardwareFilters)
{
filterQueue.Add("hwupload");
}
if (_deinterlace) if (_deinterlace)
{ {
string filter = acceleration switch string filter = acceleration switch
@ -102,7 +123,7 @@ namespace ErsatzTV.Core.FFmpeg
if (_scaleToSize.IsSome || _padToSize.IsSome) if (_scaleToSize.IsSome || _padToSize.IsSome)
{ {
if (acceleration != HardwareAccelerationKind.None) if (acceleration != HardwareAccelerationKind.None && (isHardwareDecode || usesHardwareFilters))
{ {
filterQueue.Add("hwdownload"); filterQueue.Add("hwdownload");
string format = acceleration switch string format = acceleration switch

2
ErsatzTV.Core/FFmpeg/FFmpegProcessBuilder.cs

@ -153,6 +153,8 @@ namespace ErsatzTV.Core.FFmpeg
_arguments.Add(qsvCodec); _arguments.Add(qsvCodec);
} }
_complexFilterBuilder = _complexFilterBuilder.WithInputCodec(codec);
_arguments.Add("-i"); _arguments.Add("-i");
_arguments.Add($"{input}"); _arguments.Add($"{input}");
return this; return this;

3
ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs

@ -70,6 +70,7 @@ namespace ErsatzTV.Core.Metadata
mediaItemVersion.Width = version.Width; mediaItemVersion.Width = version.Width;
mediaItemVersion.Height = version.Height; mediaItemVersion.Height = version.Height;
mediaItemVersion.VideoCodec = version.VideoCodec; mediaItemVersion.VideoCodec = version.VideoCodec;
mediaItemVersion.VideoProfile = version.VideoProfile;
mediaItemVersion.VideoScanKind = version.VideoScanKind; mediaItemVersion.VideoScanKind = version.VideoScanKind;
return await _mediaItemRepository.Update(mediaItem) && durationChange; return await _mediaItemRepository.Update(mediaItem) && durationChange;
@ -134,6 +135,7 @@ namespace ErsatzTV.Core.Metadata
version.Width = videoStream.width; version.Width = videoStream.width;
version.Height = videoStream.height; version.Height = videoStream.height;
version.VideoCodec = videoStream.codec_name; version.VideoCodec = videoStream.codec_name;
version.VideoProfile = (videoStream.profile ?? string.Empty).ToLowerInvariant();
version.VideoScanKind = ScanKindFromFieldOrder(videoStream.field_order); version.VideoScanKind = ScanKindFromFieldOrder(videoStream.field_order);
} }
@ -157,6 +159,7 @@ namespace ErsatzTV.Core.Metadata
public record FFprobeStream( public record FFprobeStream(
int index, int index,
string codec_name, string codec_name,
string profile,
string codec_type, string codec_type,
int width, int width,
int height, int height,

1497
ErsatzTV.Infrastructure/Migrations/20210308215756_Add_MediaVersionVideoProfile.Designer.cs generated

File diff suppressed because it is too large Load Diff

19
ErsatzTV.Infrastructure/Migrations/20210308215756_Add_MediaVersionVideoProfile.cs

@ -0,0 +1,19 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Add_MediaVersionVideoProfile : Migration
{
protected override void Up(MigrationBuilder migrationBuilder) =>
migrationBuilder.AddColumn<string>(
"VideoProfile",
"MediaVersion",
"TEXT",
nullable: true);
protected override void Down(MigrationBuilder migrationBuilder) =>
migrationBuilder.DropColumn(
"VideoProfile",
"MediaVersion");
}
}

1497
ErsatzTV.Infrastructure/Migrations/20210308215926_Reset_MediaVersionDateUpdated.Designer.cs generated

File diff suppressed because it is too large Load Diff

14
ErsatzTV.Infrastructure/Migrations/20210308215926_Reset_MediaVersionDateUpdated.cs

@ -0,0 +1,14 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace ErsatzTV.Infrastructure.Migrations
{
public partial class Reset_MediaVersionDateUpdated : Migration
{
protected override void Up(MigrationBuilder migrationBuilder) =>
migrationBuilder.Sql(@"UPDATE MediaVersion SET DateUpdated = '0001-01-01 00:00:00'");
protected override void Down(MigrationBuilder migrationBuilder)
{
}
}
}

3
ErsatzTV.Infrastructure/Migrations/TvContextModelSnapshot.cs

@ -418,6 +418,9 @@ namespace ErsatzTV.Infrastructure.Migrations
b.Property<string>("VideoCodec") b.Property<string>("VideoCodec")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("VideoProfile")
.HasColumnType("TEXT");
b.Property<int>("VideoScanKind") b.Property<int>("VideoScanKind")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");

1
ErsatzTV.Infrastructure/Plex/Models/PlexMediaResponse.cs

@ -13,6 +13,7 @@ namespace ErsatzTV.Infrastructure.Plex.Models
public int AudioChannels { get; set; } public int AudioChannels { get; set; }
public string AudioCodec { get; set; } public string AudioCodec { get; set; }
public string VideoCodec { get; set; } public string VideoCodec { get; set; }
public string VideoProfile { get; set; }
public string Container { get; set; } public string Container { get; set; }
public string VideoFrameRate { get; set; } public string VideoFrameRate { get; set; }
public List<PlexPartResponse> Part { get; set; } public List<PlexPartResponse> Part { get; set; }

1
ErsatzTV.Infrastructure/Plex/PlexServerApiClient.cs

@ -125,6 +125,7 @@ namespace ErsatzTV.Infrastructure.Plex
Height = media.Height, Height = media.Height,
AudioCodec = media.AudioCodec, AudioCodec = media.AudioCodec,
VideoCodec = media.VideoCodec, VideoCodec = media.VideoCodec,
VideoProfile = media.VideoProfile,
SampleAspectRatio = ConvertToSAR(media.AspectRatio), SampleAspectRatio = ConvertToSAR(media.AspectRatio),
MediaFiles = new List<MediaFile> MediaFiles = new List<MediaFile>
{ {

Loading…
Cancel
Save