using Flaro.Core.Library; using Microsoft.Extensions.Logging.Abstractions; namespace Flaro.Media.Tests; public class FfprobeRunnerTests { private string _ordner = ""; private FfprobeRunner _ffprobe = null!; [SetUp] public void Anlegen() { if (!Testdateien.FfmpegVorhanden) Assert.Ignore("ffmpeg ist auf diesem Rechner nicht installiert."); _ordner = Directory.CreateDirectory( Path.Combine(Path.GetTempPath(), "flaro-probe-" + Guid.CreateVersion7().ToString("N"))).FullName; _ffprobe = new FfprobeRunner( new FfmpegOptions(Testdateien.Suchen("ffmpeg")!, Testdateien.Suchen("ffprobe")!), NullLogger.Instance); } [TearDown] public void Aufraeumen() { try { if (_ordner.Length > 0) Directory.Delete(_ordner, recursive: true); } catch (IOException) { } } /// Die Frage, um die es im ganzen Projekt geht. /// /// /// Zwei Tonspuren, beide deutsch, eine davon Audiodeskription. Genau /// diese Datei hat die Sache ausgelöst: die Sprachkennung ist bei beiden /// „deu", und nur der Name unterscheidet sie. Wer hier nur die Sprache /// liest, kann die Frage „welche willst du?" gar nicht stellen. /// [Test] public async Task Zwei_Tonspuren_werden_mit_Sprache_und_Namen_gelesen() { var datei = Path.Combine(_ordner, "zwei-tonspuren.mkv"); Testdateien.MitZweiTonspuren(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis, Is.Not.Null); var ton = ergebnis!.Streams.Where(s => s.Kind == MediaStreamKind.Audio).ToList(); Assert.That(ton, Has.Count.EqualTo(2)); Assert.That(ton.Select(t => t.Language), Is.EqualTo(new[] { "deu", "deu" })); Assert.That(ton.Select(t => t.Title), Is.EqualTo(new[] { "Deutsch", "Audiodeskription" })); Assert.That(ton[0].Codec, Is.EqualTo("aac")); } [Test] public async Task Bild_Ton_und_Untertitel_werden_auseinandergehalten() { var datei = Path.Combine(_ordner, "alles.mkv"); Testdateien.MitZweiTonspuren(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis!.Streams.Count(s => s.Kind == MediaStreamKind.Video), Is.EqualTo(1)); Assert.That(ergebnis.Streams.Count(s => s.Kind == MediaStreamKind.Audio), Is.EqualTo(2)); Assert.That(ergebnis.Streams.Count(s => s.Kind == MediaStreamKind.Subtitle), Is.EqualTo(1)); } /// Die Nummern müssen die von ffmpeg sein, nicht eine eigene Zählung. /// /// /// An ihnen hängt später das Umpacken: -map 0:2 spricht die dritte /// Spur an. Eine eigene Zählung je Art wäre dort eine Falle. /// [Test] public async Task Die_Spurnummern_sind_die_von_ffmpeg() { var datei = Path.Combine(_ordner, "nummern.mkv"); Testdateien.MitZweiTonspuren(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis!.Streams.Select(s => s.Index), Is.EqualTo(new[] { 0, 1, 2, 3 })); } [Test] public async Task Schachtel_Dauer_und_Bildgroesse_kommen_mit() { var datei = Path.Combine(_ordner, "angaben.mkv"); Testdateien.MitZweiTonspuren(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis!.Container, Is.EqualTo("mkv")); Assert.That(ergebnis.Duration, Is.Not.Null); Assert.That(ergebnis.Duration!.Value.TotalSeconds, Is.EqualTo(1).Within(0.5)); var bild = ergebnis.Streams.Single(s => s.Kind == MediaStreamKind.Video); Assert.That((bild.Width, bild.Height), Is.EqualTo((160, 120))); } /// Die MP4-Familie meldet sechs Namen auf einmal. [Test] public async Task Eine_MP4_heisst_mp4_und_nicht_mov_mp4_m4a_3gp_3g2_mj2() { var datei = Path.Combine(_ordner, "einfach.mp4"); Testdateien.Einfach(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis!.Container, Is.EqualTo("mp4")); } [Test] public async Task Eine_Datei_die_es_nicht_gibt_ergibt_nichts() { Assert.That(await _ffprobe.ProbeAsync(Path.Combine(_ordner, "gibtesnicht.mkv")), Is.Null); } [Test] public async Task Eine_Datei_die_kein_Video_ist_ergibt_nichts() { var datei = Path.Combine(_ordner, "kaputt.mkv"); await File.WriteAllTextAsync(datei, "das ist kein Film"); Assert.That(await _ffprobe.ProbeAsync(datei), Is.Null); } /// Ein Dateiname mit Anführungszeichen darf nichts ausführen. /// /// /// Die Argumente gehen als Liste an den Prozess, nicht als zusammengesetzte /// Zeile. Sonst bestimmte der Dateiname mit, was ausgeführt wird. /// [Test] public async Task Ein_Dateiname_mit_Anfuehrungszeichen_wird_gelesen() { var datei = Path.Combine(_ordner, "Der \"echte\" Film; echo nein.mkv"); Testdateien.Einfach(datei); var ergebnis = await _ffprobe.ProbeAsync(datei); Assert.That(ergebnis, Is.Not.Null); Assert.That(ergebnis!.Streams, Is.Not.Empty); } [Test] public async Task Ein_fehlendes_ffprobe_wirft_nicht() { var ohne = new FfprobeRunner( new FfmpegOptions("ffmpeg", "/gibt/es/nicht/ffprobe"), NullLogger.Instance); var datei = Path.Combine(_ordner, "egal.mp4"); Testdateien.Einfach(datei); Assert.That(await ohne.ProbeAsync(datei), Is.Null); } }