mencoder h264 smart copy

  • Hi,

    zur Zeit versuche ich mit dem mencoder eine h264-avi zu schneiden ohne sie neu kodieren zu müssen. Das geht recht flott mit
    "mencoder ... -ovc copy -oac copy ..."

    Leider werden an den Schnittstellen Frames übersprungen, da sie ja nicht neu kodiert werden. Gibt es eine Möglichkeit, hier nur die Schnittstellen neu zu kodieren?

    Wenn nein: Ich habe gesehen, dass man mit dem mencoder auch die libavcodecs verwenden kann. ffdshow unter Windows macht das auch. Nutze ich VirtualDub mit den ffdshow-codecs, kann ich diese Videos perfekt mit Smart Copy schneiden. Eigentlich müsste es doch auch dann möglich sein, diese Videos mit mencoder (unter Mac und Linux) ohne VDub zu schneiden, oder?

  • 1. mencoder kann kein smart-encoding, und schneidet immer an Keyframes
    2. das Virtual Dub smart-encoding kann liegt nicht an der libav sondern an Virtal Dub selber -> Rückschlüsse von Virtual Dub über ffdshow und libav zu mencoder sind also i.d.R. unsinnig
    3. AviDemux kann smart-encoding und läuft sowohl auf dem Mac als auch unter Linux. Hab aber bis dato nur versucht MPEG-4 ASP Material mit aktiviertem Smart-Reencoding zu schneiden.

    An sich müsste man das Smart-Reencoding auch mit einem etwas komplizierten Skript (oder einem kleinen Programm) hinbekommen können, wenn man einige Analyseschritte reinpackt und die Längen checkt und je nach dem vorher schneidet usw. -> denke es geht, aber bis dato hab ich noch keinen Nerv gehabt darauf genug Zeit zu investieren und zu testen. Falls jemand etwas dementsprechendes bastelt würde ich mich über entsprechende Infos freuen. :)

    Cu Selur

  • Hi Selur,

    danke für deine Antwort. Leider habe ich vermutet, dass wohl VDub das selbst macht. Was bedeutet denn Smart Encoding genau? Wird jeweils an einem Keyframe geschnitten oder wird einfach die geschnittene Stelle zu einem Keyframe gemacht und dann neu kodiert?
    Wie genau würde dein kleines Programm denn arbeiten? Ich bastel grad an einem Schnittprogramm mit Java und versuch halt momentan noch, das extern ausladen zu können.

    Avidemux habe ich schon getestet, allerdings kann das (noch) kein gutes Smart Copy bei h264, ist dafür also letztlich nicht wirklich zu gebrauchen.

  • Erst mal zum Problemverständnis:
    Auf Grund der durch MPEG eingeführten Struktur hat man es bei einem Video immer mit einer Aneinanderreihung von GOPs (Group of Pictures) zu tun, wobei so eine Gruppe immer mit einem Keyframe anfängt, dass sich dadurch auszeichnet, dass es alleine dekodiert werden kann ohne dass man die Frame in der Umgebung kennen muss. Bei allen anderen Frames in einer GOP kann es eventuell nötig sein alle restlichen Bilder der GOP zu kennen (aber keine Bilder außerhalb der aktuellen GOP!).
    Will man nun an einer beliebigen Stelle eine GOP trennen muss man die komplette GOP kennen und Reencoden damit man sicher geht, dass kein Frame auf ein Frame in der anderen neuen (Teil-)GOP referenziert.

    Jetzt zum Weg wie man vorgehen müsste:
    Ein Trennen einen GOP in zwei GOPs sollte wie folgt gehen:
    (betrachte hier nur den Schnitt am Anfang; Schnitt am Ende geht analog)
    1. den Anfang und das Ende der GOP kennen (bzw. eine Liste erstellen mit allen GOPs im Stream)
    2. diese GOP dem Encoder füttern und ihm aber sagen, dass er bei Frame X (dem Schnittpunkt) ein Keyframe erzeugen muss.
    3. den Reencode der GOP (der nun aus zwei GOPs besteht) trennen, so dass man nur die hintere GOP (A) hat.
    4. den Ausgangsstream schneidet man nun direkt am Anfang der ersten GOP hinter unsterem Schnittpunkt und erhält nun Teil (B).
    5. jetzt muss man noch Teil A und Teil B zusammenfügen.
    Ist an sich nicht so schwer, im westentlichen muss man sich Gedanken machen über:
    a. Wie finde ich die GOP Grenzen? (<- weiß ich spontan auch nicht, ob dafür mplayer/mencoder und deren DebugOutput genutzt werden kann; eventuell gibt es auch einen Java-AVC-Decoder oder ein anderes kleines Tool mit dem man die Informationen ermitteln kann)
    b. Wie schneide ich an GOP Grenzen? (sollte mit mencoder und dem Timestamp der GOP gehen)
    c. Wie erzwinge ich ein Key-Frame? (geht mit x264 über ein qpfile)
    d. Wie füge ich zwei GOP-Ketten zusammen? (sollte mit mp4Box gehen, eventuell müssen sie die gleiche sps haben)

    Cu Selur

  • Hallo Selur!
    Nochmals danke für deine ausführliche Erklärung. Vom Prinzip her leuchtet mir das ein, ich glaube der springende Punkt ist einfach das Auslesen der Keyframes. Alles andere lässt sich glaube ich gut mit mencoder machen!

    Bsp.:
    Ich möchte die ersten fünf Minuten der Datei abschneiden. Bei 25 fps sind das also die ersten 7500 Frames. Ich spule jetzt mal gedanklich da hin und sehe, dass das dort das erste Keyframe bei sagen wir mal 7498 liegt. Das zweite Keyframe liegt vllt. bei 7520. Ich muss also den Bereich zwischen Frame 7500 und 7519 herausschneiden (und zwar durch encoding) und dann den Bereich zwischen 7520 und dem Ende der Datei anhängen.

    Mit mencoder:
    1) mencoder input.avi -o part1_reencode.avi -ss 00:05:00 -endpos 00:00:00.88 -oac copy -ovc lavc
    2) mencoder input.avi -o part1_rest.avi -ss 00:05:00.88 -endpos xxx -oac copy -ovc copy

    Danach kann man das mit mencoder wieder zusammenfügen. Korrigier mich, wenn ich jetzt irgendetwas falsch gemacht habe. Ich werde heute Abend mal googlen, wie man die Keyframes an einer bestimmten Stelle auslesen kann.

    Schöne Grüße,
    Lupurus

  • Okay, also wie ich jetzt feststellen konnte, schneidet mencoder sowieso nur an Keyframes. Da ich sowieso nur Werbung aus Aufnahmen herausschneiden will, wäre das eig. genau, was ich brauche.
    Das Problem: wenn ich den Stream kopiere, erhalte ich ein "skipping frame!". Spiele ich das Video danach ab, habe ich kurze Artefakte zu diesem Zeitpunkt. Schneide ich mit der Option "-mc 0", wird diese geskippte Frame einfach verdoppelt und das Video ruckelt kurz an dieser Stelle... Ich bin irgendwie gerade am verzweifeln oO

  • Hm, hat leider auch keine Auswirkungen. Seltsamerweise wird die Datei unter Quicktime richtig abgespielt, nur der VLC hat damit irgendwie Probleme... :(

    Nachtrag:
    Es hat so halbwegs funktioniert... nur wenn man es weiß, sieht man jetzt ein Ruckeln! Danke!

    2 Mal editiert, zuletzt von Lupurus (4. Dezember 2009 um 20:19)

  • Hi,

    gerade kam mir noch eine Idee, die ich aber noch nicht getestet habe (heute Abend dann mal):
    Ich schneide die erste GOP heraus und zwinge mencoder dazu, an jedem Frame ein Keyframe zu machen. Danach schneide ich an dem gewünschten Frame und voila, habe ich die gewünschten Anfangsframe. Fragt sich nur, ob dann die vielen Keyframes beibehalten werden oder nicht, was aber bei max. ein paar Sekunden (mehr liegen ja i.d.R. nicht zwischen den Keyframes) nicht so viel ausmachen würde.

    Bleibt letztlich nur zu klären, wie ich den Anfangsteil mit exakt demselben Codec herausschneiden kann, denn mencoder bringt beim Zusammenfügen der Dateien einen Fehler, wenn das nicht gleich ist.

  • Ja, man könnte auch jedes Frame der betroffenen GOP zu einem Keyframe machen, aber Achtung, wenn man hierbei aufpassen, dass man nicht gegen eventuelle vbv Beschränkungen verstößt. :) (wie ich es machen würde hab ich ja beschrieben)
    Die meiner Ansicht nach wesentliche Herausforderung der Keyframe-Liste bleibt aber bestehen. :)

  • So... habe etwas herumgespielt und es soweit geschafft, die Keyframes um ein bestimmtes Frame herum herauszulesen. Geht mit dem mplayer.
    Fragt sich jetzt nur noch, wie ich diesen Bereich mit demselben Codec herausschneiden kann und dann einen neuen Keyframe setzen kann. Weißt du da ne Lösung?

  • Okay, weiterer Meilenstein erreicht, das erzwingen von Keyframes war etwas fies, aber habs dann doch noch herausgefunden. Das Problem: Ich wollte ein Keyframe bei Frame 64, er hat es mir aber bei 50 gesetzt. Grund: Automatische Szenenerkennung. Die kann man aber glücklicherweise ausstellen, so dass er dann die Keyframes nach dem bestimmten Intervall setzt.
    Jetzt muss ich nur noch herausfinden, wie ich den Teil in exakt demselben Codec herausschneiden kann, dann sollte die nachgebaute Smart-Copy-Funktion fertig sein. Sobald ich soweit bin, werde ich hier mal eine ausführliche Dokumentation darüber geben.

  • Wie gesagt:
    Wenn er ein Keyframe bei 50 setzt ist doch egal, kannst doch trotzdem eins bei 64 setzten (qpfile).

    Zitat

    Sobald ich soweit bin, werde ich hier mal eine ausführliche Dokumentation darüber geben.


    Yo, dann schreib ich für das Ganze auch mal eine c++ Version. ;)

    Cu Selur

  • Achso... ja, macht ja nichts, der erste Teil wird ja sowieso dann weggeschnitten. Es geht dann nur noch um die Stelle zwischen 64 und Ende.
    Das Problem ist nachwievor, dass ich das mit dem Codec nicht hinbekomme... hab auch schon -ffourcc versucht, aber ich bekomme immer eine Datei, die ich nicht mit der anderen zusammenfügen kann. Weißt du da weiter? Bin echt grad am verzweifeln :(

  • Würde das File vermutlich mal mit MediaInfo (--Full) analysieren, falls es sich um ein mit x264 erstelltest File handelt findet man unter 'Encoder Settings' die kompletten Einstellungen mit denen der Clip erstellt wurde, ansonsten findet man z.B. zumindest folgende Infos (hier von einem arte stream):

    Was an Infos zum Encodingparameter anpassen eigentlich reichen sollte. :)
    (würde wie gesagt auch eher mp4box als mencoder zum Zusammenfügen verwenden, was aber vor allem daran liegt, dass ich so was mit mp4box schon mal gemacht habe und mit mencoder nicht ;))

    Interessant sind vor allem:
    Codec profile : High@L4.0
    Codec settings : CABAC / 2 Ref Frames
    Pixel aspect ratio : 1.000
    Bit rate : 10323990 (müsste man in kBit umrechnen)
    Scan type : Interlaced
    Interlacement : Interlaced

    Cu Selur

  • Hi Selur,

    vielen Dank für den letzten Post und für deine gesamte Mithilfe. Eine Bitte hätte ich noch, denn das mit den genauen Codec-Einstellungen ist nun noch der letzte Clou. Könntest du mir vllt. noch die Bedeutung und Relevanz der genannten Einstellungen erklären?
    Unabhängig davon, funktioniert mein selbst gebautes Smart Copy nun perfekt! :)

    Wie versprochen hier auch die Anleitung:

    • Auslesen der Keyframes
      Das Auslesen funktioniert mit MPlayer. Die Lösung, die ich gewählt habe, ist rein funktional. So mancher wird sich nun zwar die Hände über den Kopf schlagen, aber für mich funktioniert es gut, schnell und zuverlässig.

      Die Tatsache, dass MPlayer beim Spulen direkt an Keyframes springt, habe ich mir hier zunutze gemacht. Ausgangspunkt ist das Vorhanden eines Schneidepunkts, um den ich meine Keyframes auslesen möchte. Nun öffne ich also den MPlayer mit folgenden Command:

      mplayer -vo null -nosound -slave -ss xxx input.avi

      Erläuterung:

      • -vo null: Videooutput wird auf null gesetzt, d.h. es wird kein Video angezeigt. Wir brauchen auch keines
      • -nosound: Wir brauchen auch keinen Sound
      • -slave: Wir starten im Slave-Modus, damit wir den MPlayer vom Programm steuern können
      • -ss xxx: Statt xxx geben wir nun den Zeitpunkt des ersten Schnittpunktes an (Format: hh:mm:ss.ms)

      MPlayer springt nun automatisch zu dem Keyframe, der direkt auf den Schnittpunkt folgt. Von meinem Programm aus lese ich dann die Ausgabe des MPlayers aus und weiß dann, wo sich der Punkt befindet.

      Nun weise ich den MPlayer mit "seek -1" an, zurück zu spulen. Damit springt er an den Keyframe, der sich vor dem Schnittpunkt befindet. Wieder kann ich die Ausgabe auslesen und auswerten.

      Um die restlichen Schnittpunkte zu finden, wiederhole ich das Verfahren, indem ich dann einfach mit "seek xxx 2" (2 bedeutet, dass er nun an diese Position springen soll) an den nächsten Schnittpunkt springe.


    • Herausschneiden der GOP
      Nun kann ich mich der jeweiligen GOP widmen. Anders als bisher gedacht, brauche ich nur die GOP am Anfang des Schnitts. MEncoder schneidet im Copy-Prozess auch bis an Frames, die nicht Keyframes sind. Ist ja eig. auch logisch, denn da muss nichts neu berechnet werden.

      Das Herausschneiden der GOP ist eig. recht simpel, ich schneide ich nun einfach von Keyframe 1 bis Keyframe 2:

      mencoder input.avi -o GOPX.avi -ss Keyframe1inSec -endpos diff -mc 0 -noskip -oac copy -ovc x264 -x264encopts keyint=(FrameSchnittpunkt-Keyframe1):scenecut=0 -ffourcc H264

      Erläuterung:

      • diff: Das ist die Zeit zwischen KeyFrame2 (in Sek.) und KeyFrame1 (in Sek.). Beachte: Hier muss ein Frame abgezogen werden, denn das letzte Keyframe brauchen wir ja nicht, das kommt dann in der nächsten Sequenz.
      • -mc 0 -noskip: Brauche zumindest ich, weil sonst Artefakte beim Überspringen von Frames entstehen (s.o.)
      • keyint: Nun setzen wir an der benötigten Stelle ein Keyframe. Dass evtl. noch weitere Keyframes gesetzt werden, ist eig. nicht sonderlich tragisch.
      • scenecut=0: Szenenerkennung ausstellen, sonst setzt mencoder selbst die Keyframes
      • -ffourcc H264: Damit dann beim Zusammenfügen die Codecs passen

      Weitere Einstellungen bzgl. des Codecs müssen dann noch ergänzt werden.


    • Herausschneiden aus der ersten GOP
      Was wir nun noch brauchen, ist der Teil von dem gesetzen Keyframe bis zum Ende der ersten GOP. Das geht dann mit:

      mencoder GOPX.avi -o cutXStart.avi -ss KF -ovc copy -oac copy -mc 0 -noskip

      Erläuterung:

      • KF: Wir brauchen dann die relative Position des gesetzten Keyframes. Also Schnittpunkt bis Keyframe1 (und zwar in Sek.)

      Bisher haben wir also zwei Dateien: GOPX.avi und cutXStart.avi.


    • Herausschneiden des Restes
      Nun kommt der restliche Teil. Ganz simpel und ganz schnell:

      mencoder input.avi -o cutXRest.avi -ss KF2 -endpos xxx -ovc copy -oac copy -mc 0 -noskip

      Erläuterung:

      • -ss: Hier schneide ich nun von Keyframe2 (in Sekunden)
      • -endpos: Differenz zwischen Keyframe 2 und Schnittpunkt Ende (in Sek.)

      So. Jetzt haben wir alle benötigten Teile. Jetzt müssen wir nur noch...


    • Zusammenfügen der Dateien
      Das Zusammenfügen geht nun eig. relativ simpel. Wir brauchen nur noch die Dateien, die mit cut... anfangen. Also

      mencoder -o output.avi cut1Start.avi cut1Rest.avi cut2Start.avi cut2Rest.avi ...

      Ggf. kann man noch ein -idx als Parameter hinzufügen, so dass gleich ein Index neu aufgebaut wird. Allerdings funktioniert es bei mir auch ohne.

    So, das dürfte es jetzt eigentlich sein. In der Theorie ist das recht verständlich, doch das umsetzen kostet Zeit und Nerven (insb. das Ausrechnen... da muss man erst mal den Überblick behalten). Wenn gewünscht, kann man sich natürlich noch den Output abfangen und eine ProgressBar damit füttern (Allerdings ist das sehr stressig, weil man ja die Prozesse nur einzeln hat. Aber es ist möglich ;))

    Ich hoffe, ich konnte dir verständlich erklären, wie ich das gemacht habe. Falls du irgendwelche Fehler entdeckst oder dir was unerklärlich ist, kannst du ja nochmal fragen.

    Schöne Grüße,
    Lupurus

  • Zitat

    Ist es eigentlich genauso einfach eine GUI dafür zu basteln ?


    Eine MPlayer GUI an sich ist nicht wild, man muss MPlayer im slave Mode starten und kann ihn dann lenken.

    Bin momentan etwas im Stress und erst morgen Abend wieder zuhause guck dann aber drauf und schreib was zum Reencoden. :)

    Cu Selur

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!