English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Di recente, ho utilizzato il pacchetto FFmpeg di javaCV per sincronizzare la riproduzione di frame audio e video catturati con il catturatore di frame FFmpegFrameGrabber. Il metodo di sincronizzazione utilizzato è la sincronizzazione video-audio.
Il pensiero specifico è il seguente:
(1) Prima di tutto, presentiamo come FFmpeg cattura immagini e suono da file video
FFmpegFrameGrabber fg = new FFmpegFrameGrabber("path del file video o url");
Dopo aver ottenuto l'oggetto FrameGrabber, chiamando il suo metodo grab() si ottiene l'oggetto Frame catturato. Questo Frame può essere un fotogramma video o audio, poiché i fotogrammi audio e video sono disposti in ordine temporale in base al timestamp del tempo di riproduzione. Naturalmente, i fotogrammi catturati sono già decodificati e archiviati nell'oggetto java.nio.Buffer, per i fotogrammi video, il Buffer contiene i dati dei pixel dell'immagine come RGB, e poi attraverso
BufferedImage bi = (new Java2DFrameConverter()).getBufferedImage(f);
Si può ottenere un'immagine, che può essere elaborata in vari modi o visualizzata direttamente nel componente Swing senza elaborazione. Per i fotogrammi audio, il Buffer è il luogo di archiviazione dei dati PCM audio, che possono essere float o short, poi è possibile scrivere questi dati PCM audio nel altoparlante utilizzando il metodo write della classe java.sounds.sample.sourceDataLine.
(2) Proseguiamo con come riprodurre continuamente i fotogrammi ottenuti. Prima di tutto, è possibile riprodurre video singolarmente:
while(true) { Frame f = fg.grab(); if(f.image!=null) label.setIcon(new ImageIcon((new Java2DFrameConverter()).getBufferedImage(f))); Thread.sleep(1000/帧率_video); }
La riproduzione audio singola è analoga, è sufficiente scrivere i dati nel sound card. Esempio
(3) Modello di produttore-consumatore.
L'immagine sopra mostra il metodo implementato dal programma, che utilizza il modello di produttore-consumatore per giudicare i fotogrammi catturati. Se è un fotogramma video, viene prodotto nel FIFO video; se è un fotogramma audio, viene prodotto nel FIFO audio. Poi, la thread di riproduzione audio e la thread di riproduzione video consumano rispettivamente i fotogrammi dai loro magazzini. Il motivo per cui si utilizza il modello di produttore-consumatore è che la velocità di cattura dei fotogrammi è maggiore della velocità di consumo, quindi preferiamo catturare i fotogrammi per buffering o ulteriormente pre-elaborare i fotogrammi catturati, mentre le thread di riproduzione video e audio devono solo riprodurre direttamente i fotogrammi elaborati.
(4) Metodi di implementazione della sincronizzazione audio-video: riprodurre tutti i frame video nei due frame audio.
Per realizzare la sincronizzazione audio-video, è necessario avere il timestamp del frame. I frame capturati qui hanno solo il timestamp di riproduzione PTS, non il timestamp di decodifica DTS, quindi possiamo decidere di riprodurre solo in base al timestamp di riproduzione.
L'esecuzione del programma è basata sull'immagine sopra menzionata. Quando il thread audio inizia a riprodurre il frame audio A1, chiama il metodo setRun del thread video e passing il timestamp del frame audio corrente curTime e il timestamp del prossimo frame audio A2 al thread video in stato di wait, quindi il thread video viene avviato e inizia a prendere il frame video G1 dal FIFO video, quindi calcola la differenza di tempo tra G1 e A1 come ritardo di riproduzione, Thread.sleep(t1) dopo, il thread video mostra l'immagine sul componente Swing, ad esempio JLabel.setIcon(image). Poi il thread video prende un altro frame di immagine G2, confronta il timestamp di G2 con il timestamp di A2, se il timestamp di G2 è inferiore a A2, il thread video continua a ritardare t2 e riproduce l'immagine G2, quindi G3 è analogo, fino a ottenere G4, confronta il timestamp di G4 con A2, se il timestamp di G4 è maggiore di A2, allora il thread video entra in stato di wait, aspettando il prossimo avvio. Dopo che il thread audio ha riprodotto il frame audio A1, prende il frame audio A3 dal magazzino e passa il timestamp di A2 e A3 al thread video, quindi inizia a riprodurre A2, il thread video bloccato procede allo stesso modo per continuare a riprodurre.
(5) Regolazione dinamica del tempo di attesa
Poiché i PC personali non sono sistemi operativi in tempo reale, quindi Thread.sleep non è accurato e è limitato dalla riproduzione del suono della scheda audio, la logica di implementazione di base menzionata richiede un miglioramento. Prima di tutto, il metodo sourceDataLine di Java estrae dati dal buffer interno in un determinato ritmo, scrivendo dati di thread audio. Se i dati audio scritti vengono esauriti, la riproduzione audio potrebbe interrompersi, ma se viene scritto troppo dati audio in una volta, potrebbe verificarsi una disallineamento tra audio e video. Pertanto, è necessario garantire che il buffer interno di sourceDataLine contenga una certa quantità di dati, altrimenti potrebbe verificarsi un blocco, ma la quantità di dati non può essere troppo elevata. Pertanto, durante il periodo da G3 a A2, regoliamo la riproduzione del suono. A causa dell'incertezza dell'attesa, i dati del frame A1 scritti potrebbero essere esauriti dalla scheda audio prima di raggiungere il tempo t6. Pertanto, dopo la riproduzione dell'immagine G3, il thread audio giudica in base al quantità di dati restanti restituiti da sourceDataLine.available(). Se la quantità di dati è quasi esaurita, riduce il tempo di attesa t4 da G3 a A2. In questo modo si può garantire che la quantità di dati non diventi 0 e causi un blocco dell'audio.
(6)以下是程序在window64下测试和ubuntu14下测试的结果图:播放非常流畅,同步效果也不错,但是开启播放时,如果在使用IDE如IDEA中编写代码,可能会出现卡顿,因为IDEA也是用Java开发的,所以IDEA的运行可能会影响其他Java程序,但其他进程不会受到影响。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持呐喊教程。
声明:本文内容来源于互联网,版权属于原作者。内容由互联网用户自发贡献并自行上传,本网站不拥有所有权,未进行人工编辑处理,也不承担相关法律责任。如果您发现涉嫌版权的内容,请发送邮件至:notice#oldtoolbag.com(发邮件时,请将#更换为@)进行举报,并提供相关证据。一经查实,本站将立即删除涉嫌侵权内容。