| | 1 | | using System.Collections.Generic; |
| | 2 | | using MediaBrowser.Model.Entities; |
| | 3 | |
|
| | 4 | | namespace MediaBrowser.Controller.MediaEncoding; |
| | 5 | |
|
| | 6 | | /// <summary> |
| | 7 | | /// Describes the downmix algorithms capabilities. |
| | 8 | | /// </summary> |
| | 9 | | public static class DownMixAlgorithmsHelper |
| | 10 | | { |
| | 11 | | /// <summary> |
| | 12 | | /// The filter string of the DownMixStereoAlgorithms. |
| | 13 | | /// The index is the tuple of (algorithm, layout). |
| | 14 | | /// </summary> |
| 0 | 15 | | public static readonly Dictionary<(DownMixStereoAlgorithms, string), string> AlgorithmFilterStrings = new() |
| 0 | 16 | | { |
| 0 | 17 | | { (DownMixStereoAlgorithms.Dave750, "5.1"), "pan=stereo|c0=0.5*c2+0.707*c0+0.707*c4+0.5*c3|c1=0.5*c2+0.707*c1+0. |
| 0 | 18 | | // Use AC-4 algorithm to downmix 7.1 inputs to 5.1 first |
| 0 | 19 | | { (DownMixStereoAlgorithms.Dave750, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707 |
| 0 | 20 | | { (DownMixStereoAlgorithms.NightmodeDialogue, "5.1"), "pan=stereo|c0=c2+0.30*c0+0.30*c4|c1=c2+0.30*c1+0.30*c5" } |
| 0 | 21 | | // Use AC-4 algorithm to downmix 7.1 inputs to 5.1 first |
| 0 | 22 | | { (DownMixStereoAlgorithms.NightmodeDialogue, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c |
| 0 | 23 | | { (DownMixStereoAlgorithms.Rfc7845, "3.0"), "pan=stereo|c0=0.414214*c2+0.585786*c0|c1=0.414214*c2+0.585786*c1" } |
| 0 | 24 | | { (DownMixStereoAlgorithms.Rfc7845, "quad"), "pan=stereo|c0=0.422650*c0+0.366025*c2+0.211325*c3|c1=0.422650*c1+0 |
| 0 | 25 | | { (DownMixStereoAlgorithms.Rfc7845, "5.0"), "pan=stereo|c0=0.460186*c2+0.650802*c0+0.563611*c3+0.325401*c4|c1=0. |
| 0 | 26 | | { (DownMixStereoAlgorithms.Rfc7845, "5.1"), "pan=stereo|c0=0.374107*c2+0.529067*c0+0.458186*c4+0.264534*c5+0.374 |
| 0 | 27 | | { (DownMixStereoAlgorithms.Rfc7845, "6.1"), "pan=stereo|c0=0.321953*c2+0.455310*c0+0.394310*c5+0.227655*c6+0.278 |
| 0 | 28 | | { (DownMixStereoAlgorithms.Rfc7845, "7.1"), "pan=stereo|c0=0.274804*c2+0.388631*c0+0.336565*c6+0.194316*c7+0.336 |
| 0 | 29 | | { (DownMixStereoAlgorithms.Ac4, "3.0"), "pan=stereo|c0=c0+0.707*c2|c1=c1+0.707*c2" }, |
| 0 | 30 | | { (DownMixStereoAlgorithms.Ac4, "5.0"), "pan=stereo|c0=c0+0.707*c2+0.707*c3|c1=c1+0.707*c2+0.707*c4" }, |
| 0 | 31 | | { (DownMixStereoAlgorithms.Ac4, "5.1"), "pan=stereo|c0=c0+0.707*c2+0.707*c4|c1=c1+0.707*c2+0.707*c5" }, |
| 0 | 32 | | { (DownMixStereoAlgorithms.Ac4, "7.0"), "pan=5.0(side)|c0=c0|c1=c1|c2=c2|c3=0.707*c3+0.707*c5|c4=0.707*c4+0.707* |
| 0 | 33 | | { (DownMixStereoAlgorithms.Ac4, "7.1"), "pan=5.1(side)|c0=c0|c1=c1|c2=c2|c3=c3|c4=0.707*c4+0.707*c6|c5=0.707*c5+ |
| 0 | 34 | | }; |
| | 35 | |
|
| | 36 | | /// <summary> |
| | 37 | | /// Get the audio channel layout string from the audio stream |
| | 38 | | /// If the input audio string does not have a valid layout string, guess from channel count. |
| | 39 | | /// </summary> |
| | 40 | | /// <param name="audioStream">The audio stream to get layout.</param> |
| | 41 | | /// <returns>Channel Layout string.</returns> |
| | 42 | | public static string InferChannelLayout(MediaStream audioStream) |
| | 43 | | { |
| 0 | 44 | | if (!string.IsNullOrWhiteSpace(audioStream.ChannelLayout)) |
| | 45 | | { |
| | 46 | | // Note: BDMVs do not derive this string from ffmpeg, which would cause ambiguity with 4-channel audio |
| | 47 | | // "quad" => 2 front and 2 rear, "4.0" => 3 front and 1 rear |
| | 48 | | // BDMV will always use "4.0" in this case |
| | 49 | | // Because the quad layout is super rare in BDs, we will use "4.0" as is here |
| 0 | 50 | | return audioStream.ChannelLayout; |
| | 51 | | } |
| | 52 | |
|
| 0 | 53 | | if (audioStream.Channels is null) |
| | 54 | | { |
| 0 | 55 | | return string.Empty; |
| | 56 | | } |
| | 57 | |
|
| | 58 | | // When we don't have definitive channel layout, we have to guess from the channel count |
| | 59 | | // Guessing is not always correct, but for most videos we don't have to guess like this as the definitive layout |
| 0 | 60 | | var inferredLayout = audioStream.Channels.Value switch |
| 0 | 61 | | { |
| 0 | 62 | | 1 => "mono", |
| 0 | 63 | | 2 => "stereo", |
| 0 | 64 | | 3 => "2.1", // Could also be 3.0, prefer 2.1 |
| 0 | 65 | | 4 => "4.0", // Could also be quad (with rear left and rear right) and 3.1 with LFE. prefer 4.0 with front ce |
| 0 | 66 | | 5 => "5.0", |
| 0 | 67 | | 6 => "5.1", // Could also be 6.0 or hexagonal, prefer 5.1 |
| 0 | 68 | | 7 => "6.1", // Could also be 7.0, prefer 6.1 |
| 0 | 69 | | 8 => "7.1", // Could also be 8.0, prefer 7.1 |
| 0 | 70 | | _ => string.Empty // Return empty string for not supported layout |
| 0 | 71 | | }; |
| 0 | 72 | | return inferredLayout; |
| | 73 | | } |
| | 74 | | } |