diff --git a/docs/ABSPANN-IM-BILD.md b/docs/ABSPANN-IM-BILD.md new file mode 100644 index 0000000..505d90f --- /dev/null +++ b/docs/ABSPANN-IM-BILD.md @@ -0,0 +1,167 @@ +# Den Abspann im Bild finden — Entwurf + +Der Tonabgleich findet Vorspann und Abspann, **weil sie sich wiederholen**: +dieselbe Musik in Folge 1 und Folge 2. Ein Film hat nichts, womit er sich +vergleichen liesse. Sein Abspann kommt genau einmal vor. + +Was bleibt, ist das Bild. Dieser Entwurf sagt, was daran messbar ist, was es +kostet, und wo das Verfahren danebenliegt. + +Kapitelmarken sind hier bewusst **nicht** der Weg: sie sind exakt, wo sie +stehen, aber bei einer gemischten Sammlung stehen sie selten. + +--- + +## 1 · Das Signal, nachgemessen + +Ein Abspann ist dunkel. Das ist keine Vermutung — nachgestellt mit einem +erzeugten Film (90 Sekunden Bild, danach 40 Sekunden weisse Schrift auf +schwarzem Grund), abgetastet mit zwei Bildern je Sekunde: + +| Stelle | mittlere Helligkeit (`YAVG`, 0–255) | +|---|---| +| 0–89,5 s (Handlung) | **125** | +| ab 90,0 s (Abspann) | **18** | + +Der Sprung liegt auf dem Bild genau, an dem der Abspann anfängt. Kein +Übergang, keine Grauzone — und das ist der Punkt: gesucht wird nicht „ein +dunkles Bild", sondern **die Kante**. + +Dieselbe Richtung geht Jellyfins Intro Skipper. Dort heisst es +„Add support for using black frames to locate ending credits"; die Suche +läuft rückwärts vom Ende und hört auf, wenn der Bereich auf vier Sekunden +geschrumpft ist. + +## 2 · Was es kostet + +Das Rechnen ist umsonst, das **Dekodieren** ist der Preis. Gemessen an einer +erzeugten Datei, 1080p, h264, 180 Sekunden: + +| Weg | Zeit | +|---|---| +| Jedes zweite Bild dekodieren (`fps=2`) | **2,89 s** | +| Nur Schlüsselbilder (`-skip_frame nokey`) | **0,24 s** | + +Hochgerechnet auf die letzten 15 Minuten eines Films: der erste Weg kostet +rund anderthalb Minuten je Film, der zweite ein paar Sekunden. *Das ist eine +Hochrechnung, keine Messung an echtem Material.* + +Es geht noch billiger, und so macht es Jellyfin: **nicht am Stück abtasten, +sondern zielen.** Binäre Suche mit Sonden von zwei Sekunden zwischen „sicher +Handlung" und „sicher Abspann" — zehn Sonden genügen für eine Genauigkeit von +vier Sekunden, und zehn mal zwei Sekunden Dekodierung sind nichts. + +**Vorschlag: beides.** Erst eine grobe Reihe von Schlüsselbildern über die +letzten zwanzig Minuten (ein Durchlauf, wenige Sekunden) — die sagt, *ob* es +überhaupt eine dunkle Strecke am Ende gibt und ungefähr wo. Dann eine binäre +Suche mit kurzen Sonden auf die Kante. Der erste Schritt verhindert, dass die +binäre Suche in einem Film ohne dunklen Abspann wild herumspringt; der zweite +macht sie genau. + +## 3 · Der Zuschnitt + +Dieselbe Trennung wie beim Tonabgleich: **das Schwierige rein, das Dreckige +dünn.** + +**`Bildabtaster` (Flaro.Media)** — der einzige Teil, der ffmpeg anfasst. + +``` +helligkeiten(pfad, ab, bis, schritt) -> [(sekunde, helligkeit)] +istDunkel(pfad, ab, dauer) -> bool +``` + +Beides über `signalstats` beziehungsweise `blackdetect`, als eigener Prozess +wie `FfprobeRunner`. Fehlt ffmpeg oder scheitert der Lauf: leere Antwort, +keine Marke, kein Abbruch. + +**`Abspannkante` (Flaro.Core)** — reine Rechnung, ohne Datei: + +``` +Suchen(messpunkte, laufzeit, regeln) -> Kante? +``` + +Nimmt die Reihe aus Schritt eins und gibt zurück, wo die dunkle Strecke +anfängt — oder nichts. Hier liegen alle Schwellen, und hier liegen die +Prüfungen. Dieselbe Rolle wie `Tonabgleich`. + +**`Markenerkennung`** bekommt einen zweiten Zweig: Serien über den Ton, +Filme über das Bild. Die Tabelle, der Vertrag, die Knöpfe in App und Web +stehen schon — ein Abspann ist ein Abspann, egal woher er kommt. + +Dafür braucht `Marke` eine Spalte `MovieId` neben `EpisodeId` (heute nur +Folgen), und `MovieResponse` die Marken, wie `EpisodeResponse` sie schon hat. + +## 4 · Die Schwellen + +Alles hier ist eine Setzung und gehört an **eine** Stelle, damit man sie +gemeinsam verschieben kann: + +| Grösse | Vorschlag | Warum | +|---|---|---| +| Helligkeit „dunkel" | `YAVG < 35` | Gemessen: Abspann 18, Handlung 125. Fünfunddreissig liegt weit von beiden. | +| Anteil dunkler Bilder in einer Sonde | 85 % | Eine Schrifttafel blitzt hell auf; eine einzelne helle Sonde darf die Strecke nicht brechen. | +| Kürzester Abspann | 45 s | Darunter lohnt kein Knopf, und zufällige Dunkelheit ist häufiger. | +| Längster Abspann | 12 min | Darüber ist es kein Abspann, sondern ein Fehlfund. | +| Suchbereich | letzte 20 min | Bei einem Dreistünder wäre „die letzten 10 %" zu viel, bei einem Kurzfilm zu wenig. | +| Genauigkeit | 4 s | Wie bei Jellyfin. Feiner zu suchen kostet Sonden und bringt niemandem etwas. | + +## 5 · Wo es danebenliegt — und was dann passiert + +**Das muss vorher dastehen, nicht hinterher.** + +- **Abspann über laufendem Bild.** Marvel, Pixar, jede zweite Komödie: die + Namen laufen über eine Szene. Keine dunkle Strecke, kein Fund. → Kein + Knopf. Das ist die richtige Antwort; ein geratener Knopf schnitte Handlung + weg. +- **Dunkle Schlussszene.** Ein Film, der im Dunkeln endet, bekommt die Kante + zu früh. Dagegen hilft die Mindestlänge und die Obergrenze — und dass die + Kante die **früheste** dunkle Stelle einer durchgehenden Strecke bis zum + Ende sein muss, nicht irgendeine. +- **Schwarzblende mitten im Film.** Kommt vor, hält aber selten bis zum Ende + durch. Die Forderung „bis zum Dateiende dunkel" fängt das. +- **Szene nach dem Abspann.** Dann ist die Strecke unterbrochen, und der Fund + fällt heraus. Lieber keiner als einer, der über die Szene springt. + +Grobe Erwartung, **ungemessen**: bei Serien greift das Verfahren oft, bei +Kinofilmen vielleicht bei der Hälfte. Mehr lässt sich erst sagen, wenn es an +echtem Material gelaufen ist — und dafür braucht es einen Weg, die Funde +nachzusehen. + +## 6 · Nachsehen können + +Ohne das wird aus dem Verfahren eine Blackbox, die manchmal recht hat. +Vorschlag: auf der Detailseite steht bei einem Film mit Marke, **wo** sie +liegt, mit einem Knopf „stimmt nicht" — der die Marke löscht und den Titel +für weitere Läufe sperrt. Drei Zeilen Oberfläche, und man hat eine Messung +statt eines Gefühls. + +## 7 · Stufen + +| | Schritt | Prüfbar an | +|---|---|---| +| 1 | `Abspannkante` als reine Rechnung samt Prüfungen | erfundenen Messreihen | +| 2 | `Bildabtaster` über ffmpeg | der erzeugten Prüfdatei aus Abschnitt 1 | +| 3 | `Marke.MovieId`, Wanderung, Marken im Filmvertrag | Serverprüfungen | +| 4 | Filme im Lauf nach dem Scan | am Bestand, im Protokoll | +| 5 | „stimmt nicht" auf der Detailseite | von Hand | + +## Prüfliste + +- **V.1** Ein Film mit schwarzem Abspann bekommt eine Marke, und sie liegt + innerhalb von fünf Sekunden an der richtigen Stelle. +- **V.2** Ein Film mit Abspann über laufendem Bild bekommt **keine** Marke. +- **V.3** Ein Film, der im Dunkeln endet, ohne Abspann, bekommt keine Marke. +- **V.4** Der Lauf über hundert Filme belastet die Platte nicht länger als + der Scan selbst. +- **V.5** Der Überspringen-Knopf erscheint bei einem Film genauso wie bei + einer Folge. +- **V.6** Mit erkanntem Abspann gilt ein Film als gesehen, sobald er anfängt + — dieselbe Regel wie bei Folgen, sie steht schon. + +--- + +## Quellen + +- [intro-skipper auf GitHub](https://github.com/intro-skipper/intro-skipper) +- [Intro Skipper, README](https://cdn.jsdelivr.net/gh/intro-skipper/intro-skipper@10.11/README.md) +- [Forenbeitrag zu Abspann-Erkennung](https://forum.jellyfin.org/t-how-to-skip-ending-credits-with-confusedpolarbear-intro-skipper)