172 lines
6.4 KiB
C#
172 lines
6.4 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Paca.Core.Media;
|
|
using Xunit;
|
|
|
|
namespace Paca.Tests.Media;
|
|
|
|
public class HardwareTranscoderAndCastingExtremeRedTests
|
|
{
|
|
[Fact]
|
|
public void BuildFfmpegTranscodeCommand_NullSpec_ThrowsArgumentNullException()
|
|
{
|
|
Assert.Throws<ArgumentNullException>(() =>
|
|
HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("input.mp4", "output.mp4", null!));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void BuildFfmpegTranscodeCommand_NullOrWhitespaceInput_ThrowsArgumentException(string? invalidInput)
|
|
{
|
|
var spec = new TranscodePresetSpec();
|
|
Assert.Throws<ArgumentException>(() =>
|
|
HardwareTranscoderStudio.BuildFfmpegTranscodeCommand(invalidInput!, "output.mp4", spec));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void BuildFfmpegTranscodeCommand_NullOrWhitespaceOutput_ThrowsArgumentException(string? invalidOutput)
|
|
{
|
|
var spec = new TranscodePresetSpec();
|
|
Assert.Throws<ArgumentException>(() =>
|
|
HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("input.mp4", invalidOutput!, spec));
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildFfmpegTranscodeCommand_SameInputAndOutput_ThrowsInvalidOperationException()
|
|
{
|
|
var tempFile = Path.GetTempFileName();
|
|
try
|
|
{
|
|
var spec = new TranscodePresetSpec();
|
|
Assert.Throws<InvalidOperationException>(() =>
|
|
HardwareTranscoderStudio.BuildFfmpegTranscodeCommand(tempFile, tempFile, spec));
|
|
}
|
|
finally
|
|
{
|
|
if (File.Exists(tempFile)) File.Delete(tempFile);
|
|
}
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildFfmpegTranscodeCommand_QuotedPaths_StripsQuotesAndProducesValidArgs()
|
|
{
|
|
var spec = new TranscodePresetSpec { Backend = HardwareEncoderBackend.SoftwareCpu, Codec = VideoCodecTarget.H264 };
|
|
var args = HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("\"C:\\input video.mp4\"", "\"C:\\out.mp4\"", spec);
|
|
|
|
Assert.Equal("C:\\input video.mp4", args[1]);
|
|
Assert.Equal("C:\\out.mp4", args.Last());
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildFfmpegTranscodeCommand_NullOrEmptyAudioCodec_DefaultsToAac()
|
|
{
|
|
var spec = new TranscodePresetSpec { AudioCodec = " " };
|
|
var args = HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("in.mkv", "out.mp4", spec);
|
|
|
|
var aIndex = args.IndexOf("-c:a");
|
|
Assert.True(aIndex >= 0);
|
|
Assert.Equal("aac", args[aIndex + 1]);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(HardwareEncoderBackend.NvidiaNvenc, VideoCodecTarget.AV1, "av1_nvenc")]
|
|
[InlineData(HardwareEncoderBackend.NvidiaNvenc, VideoCodecTarget.HEVC_H265, "hevc_nvenc")]
|
|
[InlineData(HardwareEncoderBackend.NvidiaNvenc, VideoCodecTarget.H264, "h264_nvenc")]
|
|
[InlineData(HardwareEncoderBackend.IntelQsv, VideoCodecTarget.AV1, "av1_qsv")]
|
|
[InlineData(HardwareEncoderBackend.IntelQsv, VideoCodecTarget.HEVC_H265, "hevc_qsv")]
|
|
[InlineData(HardwareEncoderBackend.AmdAmf, VideoCodecTarget.AV1, "av1_amf")]
|
|
[InlineData(HardwareEncoderBackend.AmdAmf, VideoCodecTarget.HEVC_H265, "hevc_amf")]
|
|
[InlineData(HardwareEncoderBackend.SoftwareCpu, VideoCodecTarget.AV1, "libsvtav1")]
|
|
[InlineData(HardwareEncoderBackend.SoftwareCpu, VideoCodecTarget.HEVC_H265, "libx265")]
|
|
public void BuildFfmpegTranscodeCommand_Backends_ProducesCorrectVideoCodec(
|
|
HardwareEncoderBackend backend, VideoCodecTarget codec, string expectedCodec)
|
|
{
|
|
var spec = new TranscodePresetSpec { Backend = backend, Codec = codec };
|
|
var args = HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("in.mp4", "out.mp4", spec);
|
|
|
|
var vIndex = args.IndexOf("-c:v");
|
|
Assert.True(vIndex >= 0);
|
|
Assert.Equal(expectedCodec, args[vIndex + 1]);
|
|
}
|
|
|
|
[Fact]
|
|
public void BuildFfmpegTranscodeCommand_NegativeBitrate_DoesNotEmitBitrateFlag()
|
|
{
|
|
var spec = new TranscodePresetSpec { TargetBitrateKbps = -100 };
|
|
var args = HardwareTranscoderStudio.BuildFfmpegTranscodeCommand("in.mp4", "out.mp4", spec);
|
|
|
|
Assert.DoesNotContain("-b:v", args);
|
|
}
|
|
|
|
[Fact]
|
|
public void WebRtcCastingEngine_TerminateSession_NullSessionId_ReturnsFalseWithoutThrowing()
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
var result = engine.TerminateSession(null!);
|
|
Assert.False(result);
|
|
}
|
|
|
|
[Fact]
|
|
public void WebRtcCastingEngine_TerminateSession_UnknownSessionId_ReturnsFalse()
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
var result = engine.TerminateSession("non-existent-uuid");
|
|
Assert.False(result);
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(null)]
|
|
[InlineData("")]
|
|
[InlineData(" ")]
|
|
public void WebRtcCastingEngine_CreateCastSession_NullOrWhitespaceDevice_DefaultsToDefaultDisplay(string? deviceName)
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
var session = engine.CreateCastSession(deviceName!);
|
|
Assert.Equal("Default Display", session.TargetDeviceName);
|
|
}
|
|
|
|
[Fact]
|
|
public void WebRtcCastingEngine_GetSession_WorksCorrectly()
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
Assert.Null(engine.GetSession(null!));
|
|
Assert.Null(engine.GetSession("unknown-id"));
|
|
|
|
var created = engine.CreateCastSession("Living Room TV");
|
|
var found = engine.GetSession(created.SessionId);
|
|
Assert.NotNull(found);
|
|
Assert.Equal("Living Room TV", found.TargetDeviceName);
|
|
}
|
|
|
|
[Fact]
|
|
public void WebRtcCastingEngine_GenerateOffer_InvalidDimensions_NormalizesDimensions()
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
var desc = engine.GenerateOffer(null!, width: -50, height: 0, fps: -1);
|
|
Assert.Equal("offer", desc.Type);
|
|
Assert.Contains("v=0", desc.Sdp);
|
|
Assert.Contains("H264", desc.Sdp);
|
|
}
|
|
|
|
[Fact]
|
|
public void WebRtcCastingEngine_ThreadSafety_ConcurrentCreateAndTerminate()
|
|
{
|
|
var engine = new WebRtcCastingEngine();
|
|
Parallel.For(0, 50, i =>
|
|
{
|
|
var session = engine.CreateCastSession($"Device {i}");
|
|
Assert.NotNull(engine.GetSession(session.SessionId));
|
|
var terminated = engine.TerminateSession(session.SessionId);
|
|
Assert.True(terminated);
|
|
Assert.Null(engine.GetSession(session.SessionId));
|
|
});
|
|
Assert.Equal(0, engine.ActiveSessionsCount);
|
|
}
|
|
}
|