Alle Jahre wieder – ich pfusche wieder am h264-Code rum - Projekt?

  • Es scheint ja der heilige Gral zu sein Videos ohne Neucodieren zu patchen / zu schneiden / Bildbereiche zu ändern. Das Thema lässt mich seit Jahren nicht los.

    Es geht mir ums Prinzip und will keinen Qualitätsverlust, der in der Digitaltechnik nicht zwingend notwendig ist.

    Jetzt mein Problem. Ich habe HD-Material von restaurierten Filmen. Nur hat der Mitschnittservice sein Senderlogo drin. Das Material ist sogar im Blu-Ray Standard kodiert. Tmpeg Authoring Works (was sehr streng ist) akzeptiert es und will es nicht neucodieren.

    Das Senderlogo könnte man mit dem alten Trick durch eine Untertitelspur abdecken. Aber nicht jeder Player interpretiert so eine Spur gleich. Man hat manchmal Flackern und beim Skippen den Effekt, dass der UT verschwindet und doch das Logo zu sehen ist. Ausserdem, wenn man eine andere Untertitelspur auswählt ist die Logo-Abdeckung weg. Alles nicht das Wahre.

    Das Logo ist komplett im schwarzen Rand und so wie ich das stark vermute, wird das Logo nur in den I-Frames gespeichert. (keine Bewegungsvektoren sind betroffen)

    Jetzt habe ich händisch folgendes gemacht:

    Ich habe das erste I-Frame mit einem Hexeditor aus dem h264-Elementarstream gelöscht.

    Ich habe mir ein I-Frame mit abgedeckten Logo in den gleichen Settings (!) wie der Originalstream codiert.

    Mit dem Hexeditor habe ich das neue I-Frame an die Stelle des alten kopiert.

    Und was soll ich sagen: Es funktioniert! Das Logo ist weg und der Stream heile. Jeder Player (auch die ganz kritischen) zeigen bis zum nächsten I-Frame kein Logo an.

    Händisch geht’s also!

    Nur noch mit dem Makel, dass ich ja das I-frame komplett neu encodiert habe. Man müsste auch das verlustfrei hinkriegen. Also das I-Frame an der Stelle patchen und die Stelle wo das Logo ist schwarz patchen.

    Und das kann ich nicht. Ich werde die 300 Seiten PDF zum h264-Codec in diesem Leben nicht mehr verstehen.

    Es müsste einen Editor geben, der I-Frames verlustfrei patchen kann. Ganz beschränkt auf meinen Sonderfall. (Logo im Rand, nur I-Frames, nur h264, nur schwarz)

    Ich könnte dafür auch etwas Kohle locker machen. Aber ich weiß nicht wieviele Stunden ein Codec-Programmierer bräuchte. Und bei 50 € pro Stunde bin ich bald arm.

    Was haltet ihr von dem Projekt?

    Ja, ich weiß: Der Mensch wird nie fliegen können... oder?

  • Heute habe ich dieses Tool gefunden: "h26forge"

    h26forge/docs/EDITING.md at main · h26forge/h26forge
    Domain-specific infrastructure for analyzing, generating, and manipulating syntactically correct but semantically spec-non-compliant video files. -…
    github.com

    Damit kann man h264 editieren. Man lädt beim Aufruf der exe auch ein py-Script mit dazu. Im Script steht die jeweilige Logik. Mit der Zeile

    h26forge modify --input orgSR.264 --output test1.264 -t transforms/slice_0_all_blue.py

    konnte ich das erste I-Frame komplett blau machen. (und damit das ganze erste GOP)

    Nur müsste ich die Syntax verstehen wie man nun ein paar Macroblöcke schwarz färbt von bestimmten Bildern.

  • Mit Hilfe in einem englischen Forum habe ich erstmal dieses Script angepasst.


    def slice_all_pcm(ds):
       print("\t Setting all frames to all IPCM with increasing color")

       # UT colors converted from RGB 197, 87, 0 to YUV
       # using https://www.mikekohn.net/file_formats/yuv_rgb_converter.php
       # are 109, 65, 190

       y = 109
       u = 65
       v = 190

       from helpers import get_chroma_width_and_height

       (mb_width_c, mb_height_c) = get_chroma_width_and_height(0, ds)
       c_dims = mb_width_c * mb_height_c
       for i in range(0,1):
           for j in range(486,493):
               ds["slices"][i]["sd"]["macroblock_vec"][j]["mb_skip_flag"] = False

               ds["slices"][i]["sd"]["macroblock_vec"][j]["mb_type"] = "IPCM"
               ds["slices"][i]["sd"]["macroblock_vec"][j]["pcm_sample_luma"] = []

               for _ in range(256):
                   ds["slices"][i]["sd"]["macroblock_vec"][j]["pcm_sample_luma"].append((y + 37 * i) % 256)
               ds["slices"][i]["sd"]["macroblock_vec"][j]["pcm_sample_chroma"] = []
               for _ in range(c_dims):
                   ds["slices"][i]["sd"]["macroblock_vec"][j]["pcm_sample_chroma"].append((u + 37 * i) % 256)
               for _ in range(c_dims):
                   ds["slices"][i]["sd"]["macroblock_vec"][j]["pcm_sample_chroma"].append((v + 37 * i) % 256)

       return ds

    def modify_video(ds):
       return slice_all_pcm(ds)


    Ich will erstmal nur bei Slice 0 die Macroblöcke 486 bis 492 orange machen.

    Leider hat das Einfluss auf die nachkommenden Blöcke und nicht nur am Rand auch der eigentliche Bildinhalt in der Mitte wird orange (hier kaschiert wegen "geheim" und so 😉)

    Ich suche jetzt eine Zeile, die mir die Pixel schwarz färbt und nicht den Farbcode der folgenden verändert.

  • Nun, Ernüchterung. Ich habe mich mit dem Code befasst und zum Großteil verstanden. Folgender Code bearbeitet alle I-Frames und setzt die Luma-PCM Werte der Macroblöcke 487 bis 492 auf schwarz. Das sind ein paar Macroblöcke aus der ersten Zeile des Logos.

    Nur leider werden manche Helligkeitsinformationen der Logo-Blöcke später im eigentlichen Bildinhalt wiederverwendet. Also, drehe ich die Helligkeit (Luma) des Logos auf dunkel, wird auch das Bild an manchen Stellen dunkel. Die hängen also manchmal zusammen.


    Hier auf dem Differenz-Bild sieht man, wenn ich Macroblock 486 dunkel mache, dann werden andere Bildinhalte auch dunkler.

    Das Logo lässt sich also schon abgekapselt nur in einem I-Frame nicht patchen.

    Hinzu kommt, dass h26forge das ganze Video serialisiert. Es schreibt also den ganzen Bitcode in "Klarschrift" in eine Json- Datei mit hunderten Gigabyte bei nur 12 Sekunden Video. Und diese Zeilen werden dann einzeln editiert und wieder zurückgeschrieben in Bitcode. Dieser Vorgang ist nicht optimiert.

    Die CPU dümpelt bei 1 % Auslastung rum.

    Der RAM (und virtueller Speicher auf SSD) bemessen sich auf 460 Gigabyte!

    Und 12 Sekunden dauern 15 Stunden!!!

    Vielleicht findet ja jemand noch einen Ansatz aber hier komme ich erstmal nicht weiter. War aber ein interessantes und lehrreiches Experiment. Und bei den 12 Sekunden, die ich erstellt habe, ist das Logo schon fast weg und das Bild zum Großteil intakt und unbeeinflusst.

  • Nun mache ich erstmal doch etwas weiter.

    Dass andere Macroblöcke beeinflusst werden, liegt an der Prediction. Man kann diese mit dem Residualwert für jedes Pixels ausgleichen. So dass man auf 0 (schwarz) kommt im Final Pixel. Angeblich braucht man nur die Predictionwerte negieren. Damit wäre das Pixel schwarz, aber die anderen Macroblöcke werden nicht verändert. Das schau ich mir mal genauer an.

    Auch für die spätere Anwendung auf längere Videos ist mir schon was eingefallen, um die schwache Performance zu überwinden.

    Ich bleibe erstmal dran...

  • Heute endlich ein Durchbruch.🎉🎉🎉 Ich habe mir die Python-Beispiele von 26forge angeschaut und mit etwas Rumprobieren habe ich folgenden Code erstellt.

    Das Logo ist verschwunden und andere Bildteile sind nicht betroffen. Die Grundlage steht. Dann hieß es "skalieren".

    Denn bei 15 Stunden für 12 Sekunden ist mein PC in 5 Jahren noch am Durchrechnen.
    Aber ich brauche ja nur die I-Frames. (und I-Frames an Szenenwechseln) Also kann ich das h264 file in seine Frames aufsplitten (NALs)

    H26forge gebe ich dann nur ein File mit I-Frames. Die I-Frames mache ich dann am Logo schwarz und füge sie wieder zu den anderen NALs.
    Dann alle NALs wieder zusammenkopieren und das h264-File (ohne Logo) ist fertig.

    Ich konnte so heute nachmittag 3 Minuten Film ohne Logo erstellen :D :!:

    Ein Differenzscript (Avisynth) zeigt mir, ob irgendwas sich am Bild verändert hat. Bisher ist mir nur ein Stelle aufgefallen, da wurde das Logo teilweise von einem B-Frame übernommen. Da tauchte es kurz auf. Patche ich aber auch dieses B-Frame ist der Spuk an der Stelle auch weg. Soweit so gut!

    Jetzt will ich ein paar Scripte bauen um die Abschnittweise Berechnungen und Zusammensetzen zu automatisieren. Ich hoffe, es gibt keine Überraschungen mehr. Ich habe es auf 4 Playern und Blu-Ray Programmen gestestet. Bisher scheint alles sauber zu sein. Kann aber sein, dass dunkle Szenen Probleme machen werden...

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!