Kürzlich hat der FFMPEGFramegrabber -Frame -Capturer das FFMPEG -Paket von Javacv die erfassten Audio -Frames und Videorahmen synchronisiert. Die verwendete Synchronisationsmethode besteht darin, Video mit Audio zu synchronisieren.
Programme und Quellcodes
Die spezifischen Ideen sind wie folgt:
(1) Stellen Sie zunächst vor, wie FFMPEG die Bilder und Klänge von Videodateien erfasst
Ffmpegframgrabber fg = new ffmpegframgrabber ("Ein Videodateiweg oder eine URL); Nach dem Erhalt des Frame -Capture -Objekts wird das erfasste Frame -Objekt zurückgerufen. Dieser Frame kann ein Videokrahmen oder ein Audio -Frame sein, da die Audio- und Video -Frames zuerst zur Wiedergabezeit gemäß dem Zeitstempel angeordnet sind. Natürlich werden die erfassten Frames alle im Java.nio.Buffer -Objekt aufbewahrt und gespeichert. Für Videorahmen besteht der Puffer darin, Pixeldaten des Bildes wie RGB zu speichern und dann zu bestehen
BufferedImage bi = (new java2dframeConverter ()).
Sie können das Bild abrufen und das erhaltene Bild kann in einer Reihe von Prozessen verarbeitet oder direkt in der Schwungkomponente ohne Verarbeitung angezeigt werden. Entsprechend dem Audio -Frame sind der Puffer die PCM -Daten, die den Audio gespeichert haben. Diese PCM kann schweben oder kurz sein, und dann kann die Socrossataline.Write -Methode in java.Sounds.sample verwendet werden, um diese Audio -PCM -Daten an den Lautsprecher zu schreiben.
(2) Dann stellen Sie vor, wie Sie die erhaltenen Frames kontinuierlich abspielen. Spielen Sie zunächst das Video separat:
while (true) {Frame f = fg.grab (); if (f.image! = null) label.seticon (neues imageicon ((new java2dframeConverter ()). Thread.Sleep (1000/Video -Bildrate); } Gleiches gilt für das separates Spielen von Audio. Schreiben Sie einfach die Daten auf die Soundkarte. Beispiel
(3) Produktions- und Verbrauchermodell.
Das obige Bild ist eine vom Programm implementierte Methode. Die erfassten Frames werden im Herstellungsmodus beurteilt. Wenn es sich um einen Videoprahmen handelt, wird es in das Video FIFO hergestellt. Wenn es sich um einen Audio -Rahmen handelt, wird es in das Audio FIFO hergestellt. Dann verbrauchen der Audio -Wiedergabethread und der Video -Wiedergabethread die Frames aus ihren jeweiligen Rahmenlagern. Der Produktionsverbrauchermodus wird angewendet, da die Geschwindigkeit der Frame -Erfassung größer ist als der Verbrauch von Frames. Daher bevorzugen wir Frames für die Pufferung oder die Vorabverarbeitung der erfassten Frames, während die Video- und Audio -Wiedergabe -Threads die verarbeiteten Frames nur direkt abspielen und anzeigen müssen.
(4) Methoden zur Realisierung von Audio- und Video -Synchronisation: Alle Videorahmen in zwei Audiorahmen abspielen.
Um eine Audio- und Video -Synchronisation zu erreichen, müssen Sie eine Frame -Zeit -Stempel haben. Die hier festgestellten Rahmen sind nur die Wiedergabestempel -PTS, und es gibt keinen dekodierten Zeitstempel -DTS. Daher müssen wir nur über den Zeitstempel der Wiedergabe entscheiden, basierend auf dem Zeitstempel der Wiedergabe.
Die Implementierung des Programms basiert auf der obigen Abbildung. Wenn der Audio -Thread mit dem Abspielen von Audio Frame A1 beginnt, wird die SetRun -Methode des Videophreads aufgerufen und der Audio -Frame -Zeitstempel -Curtime und der nächste Zeitstempel des nächsten Frame -Audio -Rahmens A2 an den Video -Thread im Wartezustand übergeben. Anschließend beginnt der Video -Thread und nimmt den Video -Frame G1 aus dem Video -FIFO heraus und berechnet dann den Zeitunterschied zwischen G1 und A1 als Wiedergabedöglichkeit. Nach dem Thread.Sleep (T1) zeigt der Video -Thread das Bild in der Swing -Komponente wie jLabel.seticon (Bild) an. Dann nimmt der Video -Thread einen weiteren Bild -G2 -Rahmen heraus und vergleicht den Zeitstempel von G2 mit dem Zeitstempel von A2. Wenn der Zeitstempel von G2 kleiner als A2 ist, verzögert der Video -Thread weiterhin T2 und spielt das G2 -Bild ab. Dann ist G3 das gleiche wie es sollte, bis G4 erhalten wird und A2 mit A2 verglichen wird und feststellt, dass der Zeitstempel von G4 größer als A2 ist. Dann tritt der Videophread in den Wartezustand ein und wartet auf das nächste Startup. Nachdem der Audio -Thread den A1 -Audio -Frame abgespielt hat, nimmt er den Audio -Rahmen A3 aus dem Lagerhaus heraus, übergibt dann den Zeitstempel von A2 und Zeitstempel von A3 an den Videophread und spielt dann den Blockd -Video -Thread weiter.
(5) Passen Sie die Verzögerungszeit dynamisch an
Da persönliche PCs keine Echtzeit-Betriebssysteme sind, dh Thread.Sleep ist ungenau und durch die Soundkarte eingeschränkt, um Sound zu spielen, müssen die obigen grundlegenden Implementierungsideen verbessert werden. Erstens besteht die Java -Sourcen -Methode darin, die vom Audio -Thread geschriebenen Daten mit einer bestimmten Geschwindigkeit aus dem internen Puffer zu extrahieren. Wenn die vom Audio geschriebenen Daten herausgenommen werden, wird die Audio -Wiedergabe stottert. Wenn jedoch gleichzeitig zu viel Audiodaten geschrieben werden, können Audio und Video nicht synchronisiert sein. Daher ist es erforderlich, sicherzustellen, dass der interne Puffer des Sourcedatalin bestimmte Daten hat, sonst verursacht er Verzögerungen, aber die Datenmenge kann nicht zu viel sein. Daher passen wir die Soundwiedergabe von G3 auf A2 an. Aufgrund der Ungenauigkeit der Verzögerung können die im A1 -Frame geschriebenen Daten von der Schallkarte entfernt werden, bevor die Zeit T6 erreicht hat. Nach dem Spielen des G3 -Images beurteilt der Sound -Thread daher nach der Menge der Daten, die von Sourcedataline.Available () zurückgegeben wurden. Wenn die Datenmenge abgeschlossen sein soll, wird die Verzögerungszeit T4 von G3 bis A2 reduziert. Dies stellt sicher, dass sich das Datenvolumen nicht auf 0 ändert und ein solides Stottern verursacht.
(6) Das Folgende ist das Ergebnisdiagramm des Programms des Programms unter Windows 64 und Ubuntu14: Die Wiedergabe ist relativ reibungslos und die Synchronisation ist ebenfalls möglich. Wenn die Wiedergabe eingeschaltet ist, bleibt sie fest, wenn Penguin Code in ide wie Idee schreibt. Immerhin wird auch in Java eine Idee entwickelt, sodass der Betrieb der Idee andere Java -Programme beeinflusst, andere Prozesse jedoch nicht.
Das obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, es wird für das Lernen aller hilfreich sein und ich hoffe, jeder wird Wulin.com mehr unterstützen.