Recientemente, el FFMPEGFrameGrabber Frame Capturer utilizando el paquete FFMPEG de Javacv ha sincronizado los marcos de audio capturados y los marcos de video. El método de sincronización utilizado es sincronizar el video al audio.
Programas y códigos de origen
Las ideas específicas son las siguientes:
(1) Primero presente cómo FFMPEG captura las imágenes y los sonidos de los archivos de video
FfmpegframeGrabber fg = new ffmpegframeGrabber ("una ruta del archivo de video o una URL); Después de obtener el objeto de captura de cuadro, llamar a su método Grab () devolverá el objeto de cuadro capturado. Este marco puede ser un marco de video o un marco de audio, porque los marcos de audio y video están organizados primero en el momento de la reproducción de acuerdo con la marca de tiempo. Por supuesto, los marcos capturados están decodificados y almacenados en el objeto java.nio.buffer. Para los marcos de video, el búfer es almacenar datos de píxeles de la imagen, como RGB, y luego pasar
BufferedImage bi = (nuevo Java2DFrameconverter ()). GetBufferedImage (f);
Puede obtener la imagen y la imagen obtenida se puede procesar en una serie de procesos o mostrarse directamente en el componente Swing sin procesamiento. En correspondencia con el marco de audio, el búfer son los datos de PCM que almacena el audio. Este PCM puede ser flotante o corto, y luego el método SourCedataline.Write en Java.Sounds.sample se puede usar para escribir estos datos de Audio PCM en el altavoz.
(2) Luego introduzca cómo jugar continuamente los marcos obtenidos. Primero, reproduce el video por separado:
while (true) {frame f = fg.grab (); if (F.Image! = NULL) Etiqueta. Thread.sleep (1000/velocidad de cuadro de video); } Lo mismo es cierto para reproducir audio por separado, simplemente escriba los datos en la tarjeta de sonido. ejemplo
(3) Modelo de producción y consumidor.
La imagen de arriba es un método implementado por el programa. Los marcos capturados se juzgan utilizando el modo productor. Si es un marco de video, se producirá en el video FIFO. Si es un marco de audio, se producirá en el Audio FIFO. Luego, el hilo de reproducción de audio y el hilo de reproducción de video consumen los marcos de sus respectivos almacenes de cuadros respectivamente. El modo de consumo de producción se adopta porque la velocidad de la captura de cuadros es mayor que el consumo de marcos, por lo que preferimos capturar marcos para el búfer, o preprocesar aún más los marcos capturados, mientras que los hilos de reproducción de video y audio solo necesitan reproducir y mostrar directamente los marcos procesados.
(4) Métodos para realizar sincronización de audio y video: reproducir todos los marcos de video en dos marcos de audio.
Para lograr la sincronización de audio y video, debe tener una marca de tiempo de cuadro. Los marcos capturados aquí son solo la marca de tiempo de reproducción PTS, y no hay DT de marca de tiempo decodificadas, por lo que solo necesitamos decidir sobre la marca de tiempo de reproducción basada en la marca de tiempo de reproducción.
La implementación del programa se basa en la figura anterior. Cuando el hilo de audio comienza a reproducir el marco de audio A1, se llama el método SetRun del hilo de video, y la marca de tiempo de marco de audio Curtime y la siguiente marca de tiempo del siguiente cuadro de audio A2 se pasa al hilo de video en el estado de espera. Luego, el hilo de video comienza y comienza a eliminar el marco de video G1 del video FIFO, y luego calcula la diferencia de tiempo entre G1 y A1 como retraso de reproducción. Después de Thread.sleep (T1), el hilo de video muestra la imagen en el componente Swing, como jlabel.Seticon (imagen). Luego, el hilo de video saca otro marco de la imagen G2 y compara la marca de tiempo de G2 con la marca de tiempo de A2. Si la marca de tiempo de G2 es menor que A2, el hilo de video continúa retrasando T2 y reproduce la imagen G2. Entonces, G3 es lo mismo que debería, hasta que se obtenga G4 y A2 se compara con A2 y descubre que la marca de tiempo de G4 es mayor que A2, luego el hilo de video ingresa al estado de espera y espera la próxima inicio. Luego, después de que el hilo de audio reproduce el marco de audio A1, elimina el marco de audio A3 del almacén, luego pasa la marca de tiempo de A2 y las marcas de tiempo de A3 al hilo de video, y luego comienza a reproducir A2, y luego el hilo de video bloqueado continúa reproduciéndose.
(5) Ajuste dinámicamente el tiempo de retraso
Dado que las PC personales no son sistemas operativos en tiempo real, es decir, Thread.sleep es inexacto y está restringido por la tarjeta de sonido para reproducir el sonido, las ideas de implementación básicas anteriores deben mejorarse. En primer lugar, el método Java Sourcedataline es extraer los datos escritos por el hilo de audio del búfer interno a cierta velocidad. Si se retiran los datos escritos por el audio, la reproducción de audio estará tartamudeada. Sin embargo, si se escriben demasiados datos de audio al mismo tiempo, el audio y el video pueden no sincronizar. Por lo tanto, es necesario asegurarse de que el búfer interno de la fuente tenga ciertos datos, de lo contrario causará retraso, pero la cantidad de datos no puede ser demasiado. Por lo tanto, ajustamos la reproducción de sonido de G3 a A2. Debido a la inexactitud de la demora, la tarjeta de sonido puede eliminar los datos escritos en el marco A1 antes de que el tiempo haya alcanzado T6. Por lo tanto, después de reproducir la imagen G3, el hilo de sonido juzgará a juzgar en función de la cantidad de datos devueltos por SourCedataline.available (). Si la cantidad de datos está a punto de finalizarse, el tiempo de retraso T4 de G3 a A2 se reduce. Esto asegura que el volumen de datos no cambie a 0 y cause tartamudeo de sonido.
(6) El siguiente es el diagrama de resultados de la prueba del programa en Windows 64 y Ubuntu14: la reproducción es relativamente suave, y la sincronización también es posible, pero si la reproducción está activada, se atascará si Penguin escribe código en IDE como IDE como IDE. Después de todo, la idea también se desarrolla en Java, por lo que el funcionamiento de la idea afectará a otros programas de Java, pero otros procesos no lo harán.
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.