using System; using System.Globalization; using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.IO; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Entities; using Microsoft.Extensions.Configuration; using Moq; using Xunit; using IConfigurationManager = MediaBrowser.Common.Configuration.IConfigurationManager; namespace Jellyfin.Controller.Tests.MediaEncoding { public class EncodingHelperAudioBitStreamTests { private const string BothFilters = " -bsf:a noise=drop='lt(pts*tb\\,63.063)',aac_adtstoasc"; private const string NoiseOnly = " -bsf:a noise=drop='lt(pts*tb\\,63.063)'"; private const string AdtsOnly = " -bsf:a aac_adtstoasc"; private const long DefaultSeekTicks = 630_630_000L; private const string DefaultFfmpegVersion = "5.0"; private static EncodingHelper CreateHelper(string ffmpegVersion) { var mediaEncoder = new Mock(); mediaEncoder .Setup(e => e.GetTimeParameter(It.IsAny())) .Returns((long ticks) => TimeSpan.FromTicks(ticks).ToString(@"hh\:mm\:ss\.fff", CultureInfo.InvariantCulture)); mediaEncoder .SetupGet(e => e.EncoderVersion) .Returns(Version.Parse(ffmpegVersion)); return new EncodingHelper( Mock.Of(), mediaEncoder.Object, Mock.Of(), Mock.Of(), Mock.Of(), Mock.Of()); } private static EncodingJobInfo CreateState( TranscodingJobType jobType, string outputVideoCodec, string outputAudioCodec, string audioStreamCodec, string inputContainer, long startTimeTicks) { return new EncodingJobInfo(jobType) { IsVideoRequest = true, OutputVideoCodec = outputVideoCodec, OutputAudioCodec = outputAudioCodec, InputContainer = inputContainer, RunTimeTicks = TimeSpan.FromMinutes(10).Ticks, AudioStream = new MediaStream { Type = MediaStreamType.Audio, Codec = audioStreamCodec }, BaseRequest = new BaseEncodingJobOptions { StartTimeTicks = startTimeTicks } }; } [Theory] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", BothFilters)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "aac", BothFilters)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "hls", BothFilters)] [InlineData(TranscodingJobType.Progressive, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "copy", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "aac", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "wtv", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", 0L, DefaultFfmpegVersion, "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, "4.4.6", "mp4", "ts", AdtsOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "ts", "ts", NoiseOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "aac", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "mkv", NoiseOnly)] [InlineData(TranscodingJobType.Hls, "libx264", "copy", "ac3", "ts", DefaultSeekTicks, DefaultFfmpegVersion, "mp4", "ts", NoiseOnly)] public void AudioBitStreamArguments_AppliesGates( TranscodingJobType jobType, string outputVideoCodec, string outputAudioCodec, string audioStreamCodec, string inputContainer, long startTicks, string ffmpegVersion, string segmentContainer, string mediaSourceContainer, string expected) { var state = CreateState(jobType, outputVideoCodec, outputAudioCodec, audioStreamCodec, inputContainer, startTicks); var result = CreateHelper(ffmpegVersion).GetAudioBitStreamArguments(state, segmentContainer, mediaSourceContainer); Assert.Equal(expected, result); } } }