157 lines
6.8 KiB
C#
157 lines
6.8 KiB
C#
using FFMpegCore;
|
|
using FFMpegCore.Enums;
|
|
|
|
namespace Encoder;
|
|
|
|
public struct EncodingProgress {
|
|
public TimeSpan progress;
|
|
public TimeSpan duration;
|
|
public float framerate;
|
|
public EncodingJob job;
|
|
public string inputPath;
|
|
public string outputPath;
|
|
}
|
|
|
|
public class EncodingStrategyAttribute(EncoderType encoderType) : Attribute {
|
|
public EncoderType EncoderType { get; } = encoderType;
|
|
}
|
|
|
|
public interface IEncodingStrategy {
|
|
public string InputFilePath { get; set; }
|
|
public string OutputFilePath { get; set; }
|
|
public Task<bool> ExecuteAsync(CancellationToken cancellationToken, Action<EncodingProgress> onProgress);
|
|
}
|
|
|
|
[EncodingStrategy(EncoderType.AV1)]
|
|
public class AV1EncodingStrategy(string inputFilePath, string outputFilePath, EncodingJob job) : IEncodingStrategy {
|
|
public string InputFilePath { get; set; } = inputFilePath;
|
|
public string OutputFilePath { get; set; } = outputFilePath;
|
|
|
|
private static readonly Tuple<int, int>[] QPTable = new Tuple<int, int>[] {
|
|
new(1280*720, 64),
|
|
new(1920*1080, 96),
|
|
new(3840*2160, 128),
|
|
new(5760*2880, 96), //VR6K
|
|
new(8128*4096, 120) //VR8K
|
|
}.OrderBy(t => t.Item1).ToArray();
|
|
|
|
public async Task<bool> ExecuteAsync(CancellationToken cancellationToken, Action<EncodingProgress> onProgress) {
|
|
var mediaInfo = await FFProbe.AnalyseAsync(InputFilePath, cancellationToken: cancellationToken);
|
|
if (mediaInfo.PrimaryVideoStream == null) return false;
|
|
int W = mediaInfo.PrimaryVideoStream.Width;
|
|
int H = mediaInfo.PrimaryVideoStream.Height;
|
|
int qp = Utils.ToQPValue(W, H, QPTable);
|
|
return await FFMpegArguments
|
|
.FromFileInput(InputFilePath, true, args => args.WithHardwareAcceleration())
|
|
.OutputToFile(OutputFilePath, true, args => args
|
|
.CopyChannel(Channel.Audio)
|
|
.CopyChannel(Channel.Subtitle)
|
|
.WithVideoCodec("av1_nvenc")
|
|
.WithArgument(new NvencSpeedPreset(NvencSpeed.p2))
|
|
.WithArgument(new NvencTuneArgument(NvencTune.hq))
|
|
.WithArgument(new NvencHighBitDepthArgument(true))
|
|
.WithArgument(new NvencQPArgument((byte)qp))
|
|
.WithFastStart()
|
|
)
|
|
.NotifyOnProgress(progress => onProgress(new() {
|
|
progress = progress,
|
|
duration = mediaInfo.Duration,
|
|
framerate = (float)mediaInfo.PrimaryVideoStream.FrameRate,
|
|
job = job,
|
|
inputPath = InputFilePath,
|
|
outputPath = OutputFilePath
|
|
}))
|
|
.CancellableThrough(cancellationToken)
|
|
.ProcessAsynchronously();
|
|
}
|
|
}
|
|
|
|
[EncodingStrategy(EncoderType.HEVC)]
|
|
public class HEVCEncodingStrategy(string inputFilePath, string outputFilePath, EncodingJob job) : IEncodingStrategy {
|
|
public string InputFilePath { get; set; } = inputFilePath;
|
|
public string OutputFilePath { get; set; } = outputFilePath;
|
|
|
|
//TODO: needs to be adjusted
|
|
private static readonly Tuple<int, int>[] QPTable = new Tuple<int, int>[] {
|
|
new(1280*720, 0),
|
|
new(1920*1080, 0),
|
|
new(3840*2160, 0),
|
|
new(5760*2880, 0), //VR6K
|
|
new(8128*4096, 0) //VR8K
|
|
}.OrderBy(t => t.Item1).ToArray();
|
|
|
|
public async Task<bool> ExecuteAsync(CancellationToken cancellationToken, Action<EncodingProgress> onProgress) {
|
|
var mediaInfo = await FFProbe.AnalyseAsync(InputFilePath, cancellationToken: cancellationToken);
|
|
if (mediaInfo.PrimaryVideoStream == null) return false;
|
|
int W = mediaInfo.PrimaryVideoStream.Width;
|
|
int H = mediaInfo.PrimaryVideoStream.Height;
|
|
int qp = Utils.ToQPValue(W, H, QPTable);
|
|
return await FFMpegArguments
|
|
.FromFileInput(InputFilePath, true, args => args.WithHardwareAcceleration())
|
|
.OutputToFile(OutputFilePath, true, args => args
|
|
.CopyChannel(Channel.Audio)
|
|
.CopyChannel(Channel.Subtitle)
|
|
.WithVideoCodec("hevc_nvenc")
|
|
.WithArgument(new NvencSpeedPreset(NvencSpeed.p2))
|
|
.WithArgument(new NvencTuneArgument(NvencTune.hq))
|
|
.WithArgument(new NvencHighBitDepthArgument(true))
|
|
.WithArgument(new NvencQPArgument((byte)qp))
|
|
.WithFastStart()
|
|
)
|
|
.NotifyOnProgress(progress => onProgress(new() {
|
|
progress = progress,
|
|
duration = mediaInfo.Duration,
|
|
framerate = (float)mediaInfo.PrimaryVideoStream.FrameRate,
|
|
job = job,
|
|
inputPath = InputFilePath,
|
|
outputPath = OutputFilePath
|
|
}))
|
|
.CancellableThrough(cancellationToken)
|
|
.ProcessAsynchronously();
|
|
}
|
|
}
|
|
|
|
[EncodingStrategy(EncoderType.H264)]
|
|
public class H264EncodingStrategy(string inputFilePath, string outputFilePath, EncodingJob job) : IEncodingStrategy {
|
|
public string InputFilePath { get; set; } = inputFilePath;
|
|
public string OutputFilePath { get; set; } = outputFilePath;
|
|
|
|
//TODO: needs to be adjusted
|
|
private static readonly Tuple<int, int>[] QPTable = new Tuple<int, int>[] {
|
|
new(1280*720, 0),
|
|
new(1920*1080, 0),
|
|
new(3840*2160, 0),
|
|
new(5760*2880, 0), //VR6K
|
|
new(8128*4096, 0) //VR8K
|
|
}.OrderBy(t => t.Item1).ToArray();
|
|
|
|
public async Task<bool> ExecuteAsync(CancellationToken cancellationToken, Action<EncodingProgress> onProgress) {
|
|
var mediaInfo = await FFProbe.AnalyseAsync(InputFilePath, cancellationToken: cancellationToken);
|
|
if (mediaInfo.PrimaryVideoStream == null) return false;
|
|
int W = mediaInfo.PrimaryVideoStream.Width;
|
|
int H = mediaInfo.PrimaryVideoStream.Height;
|
|
int qp = Utils.ToQPValue(W, H, QPTable);
|
|
return await FFMpegArguments
|
|
.FromFileInput(InputFilePath, true, args => args.WithHardwareAcceleration())
|
|
.OutputToFile(OutputFilePath, true, args => args
|
|
.CopyChannel(Channel.Audio)
|
|
.CopyChannel(Channel.Subtitle)
|
|
.WithVideoCodec("h264_nvenc")
|
|
.WithArgument(new NvencSpeedPreset(NvencSpeed.p2))
|
|
.WithArgument(new NvencTuneArgument(NvencTune.hq))
|
|
.WithArgument(new NvencHighBitDepthArgument(true))
|
|
.WithArgument(new NvencQPArgument((byte)qp))
|
|
.WithFastStart()
|
|
)
|
|
.NotifyOnProgress(progress => onProgress(new() {
|
|
progress = progress,
|
|
duration = mediaInfo.Duration,
|
|
framerate = (float)mediaInfo.PrimaryVideoStream.FrameRate,
|
|
job = job,
|
|
inputPath = InputFilePath,
|
|
outputPath = OutputFilePath
|
|
}))
|
|
.CancellableThrough(cancellationToken)
|
|
.ProcessAsynchronously();
|
|
}
|
|
} |