fix vaapi pipeline with mpeg4 content (#51)
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Generated
+1497
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+1497
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|||||||
@@ -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>
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user