English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Recientemente, he utilizado el paquete FFmpegFrameGrabber del javaCV para sincronizar la reproducción de fotogramas de audio y video capturados.
La idea específica es la siguiente:
(1Primero, se presentará cómo FFmpeg captura imágenes y sonido de archivos de video.
FFmpegFrameGrabber fg = new FFmpegFrameGrabber("ruta de archivo de video o una URL");
Después de obtener el objeto del capturador de fotogramas, al llamar su método grab() se devuelve el objeto Frame capturado. Este Frame puede ser un fotograma de video o de audio, ya que los fotogramas de audio y video se ordenan en el tiempo de reproducción en función de la marca de tiempo. Por supuesto, los fotogramas capturados ya están decodificados y almacenados en el objeto java.nio.Buffer, y para los fotogramas de video, el Buffer almacena los datos de píxeles de la imagen, como RGB, y luego a través de
BufferedImage bi = (new Java2DFrameConverter()).getBufferedImage(f);
Se puede obtener la imagen, y la imagen obtenida se puede procesar de manera serie o no procesar y mostrar directamente en el componente Swing. Para los fotogramas de audio, el Buffer es donde se almacenan los datos PCM de audio, que pueden ser float o short, y luego se pueden escribir estos datos PCM de audio en el altavoz utilizando el método write de sourceDataLine en java.sounds.sample.
(2)A continuación, se explica cómo se reproduce continuamente las tramas obtenidas. Primero, se reproduce el video solo:
while(true) { Frame f = fg.grab(); if(f.image!=null) label.setIcon(new ImageIcon((new Java2DFrameConverter()).getBufferedImage(f))); Thread.sleep(1000/La tasa de frames de video); }
La reproducción de audio en solitario es similar, escribe los datos en la tarjeta de sonido. Ejemplo
(3)Patrón de productor-consumidor.
La imagen superior es el método de implementación del programa, utiliza el patrón de productor para juzgar las tramas capturadas, si es una trama de video se produce al FIFO de video, si es una trama de audio se produce al FIFO de audio, luego los hilos de reproducción de audio y video consumen las tramas de sus respectivos almacenes. La razón por la que se utiliza el patrón de productor-consumidor es porque la velocidad de captura de las tramas es mayor que la velocidad de consumo, por lo que se prioriza la captura de tramas para almacenar, o para preprocesar las tramas capturadas, y los hilos de reproducción de video y audio solo necesitan reproducir y mostrar las tramas procesadas.
(4)Métodos para lograr la sincronización de audio y video: reproducir todos los frames de video en dos tramas de audio.
Para lograr la sincronización de audio y video, se debe tener el timestamp de la trama, aquí se captura la trama solo con el timestamp de reproducción PTS, sin el timestamp de decodificación DTS, por lo que solo se necesita decidir la reproducción según el timestamp de reproducción.
la implementación del programa se basa en la imagen superior, cuando el hilo de audio comienza a reproducir la trama de audio A1al llamar al método setRun del hilo de video, y se pasa el timestamp del trama de audio actual a reproducir curTime y la próxima trama de audio A2el timestamp nextTime se pasa al hilo de video en estado de espera, luego el hilo de video se inicia y comienza a tomar tramas de video G del FIFO de video1Luego, se calcula G1y A1la diferencia de tiempo, como demora de reproducción, Thread.sleep(t1Después de ), el hilo de video muestra la imagen en el componente Swing, por ejemplo JLabel.setIcon(image). Luego, el hilo de video toma otra imagen G2Se compara G2el timestamp y A2Se pasa el timestamp al hilo de video, si G2el timestamp es menor que A2Luego, el hilo de video continúa demorando t2Luego, se reproduce esta G2la imagen, luego G3Del mismo modo, hasta obtener G4, y A2Se compara y se encuentra G4el timestamp es mayor que A2Luego, el hilo de video entra en estado de espera, esperando el siguiente inicio. Luego, el hilo de audio reproduce A1después de la trama de audio, se toma la trama de audio A desde el almacén3Luego, se toma A2el timestamp y A3se pasa el timestamp al hilo de video, luego comienza a reproducir A2Luego, el hilo de video que se bloquea continúa reproduciendo.
(5)Ajuste dinámico del tiempo de demora
Dado que los PC personales no son sistemas operativos en tiempo real, es decir, Thread.sleep no es preciso y está sujeto a la restricción de reproducción de sonido de la tarjeta de sonido, la implementación básica anterior necesita ser mejorada. Primero, el método sourceDataLine de Java extrae datos del búfer interno a una velocidad determinada, si los datos de audio escritos se agotan, la reproducción de audio se bloqueará, pero si se escribe demasiado datos de audio a la vez, puede ocurrir que la sincronización de audio y video sea incorrecta, por lo que se debe asegurar que el búfer interno de sourceDataLine tenga un cierto número de datos, de lo contrario se producirá un bloqueo, pero la cantidad de datos no puede ser demasiado grande, por lo que en G3hasta A2durante este tiempo para ajustar la reproducción de sonido, debido a la inexactitud de la demora, la escritura de A1Los datos del cuadro pueden no estar llenos en el tiempo t6podría ser tomado por completo por la tarjeta de sonido, por lo que los datos del cuadro de G3Después de que el hilo de sonido juzgue según la cantidad de datos devuelta por sourceDataLine.available(), si la cantidad de datos está a punto de agotarse, se reducirá G3hasta A2el tiempo de demora t4De esta manera, se puede garantizar que la cantidad de datos no se convertirá en 0 y causará que la reproducción de sonido se bloquee.
(6)A continuación, se muestra el programa en window64A continuación, se prueba con ubuntu14A continuación, se muestra la imagen del resultado de la prueba: La reproducción es fluida, la sincronización también es buena, pero al abrir la reproducción, al escribir código en IDE como IDEA, se bloquea, ya que IDEA también se desarrolla en Java, por lo que la ejecución de IDEA puede afectar a otros programas Java, pero otros procesos no afectarán.
Esto es todo el contenido de este artículo, espero que sea útil para su aprendizaje y que todos apoyen el tutorial de gritos.
Declaración: El contenido de este artículo se ha obtenido de la red, pertenece al propietario original, el contenido ha sido contribuido y subido por usuarios de Internet de manera autónoma. Este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume ninguna responsabilidad legal relacionada. Si encuentra contenido sospechoso de infracción de derechos de autor, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar, y proporcione evidencia relevante. Una vez verificada, este sitio eliminará inmediatamente el contenido sospechoso de infracción.