Recentemente, o capturador FFMPEGFramegrabber usando o pacote FFMPEG do JAVACV sincronizou os quadros de áudio e quadros de vídeo capturados. O método de sincronização usado é sincronizar o vídeo com o áudio.
Programas e códigos de origem
As idéias específicas são as seguintes:
(1) Primeiro introduza como o FFMPEG captura as imagens e sons de arquivos de vídeo
Ffmpegframegrabber fg = new ffmpegFramegrabber ("Um caminho de arquivo de vídeo ou um URL); Depois de obter o objeto de captura de quadros, chamando seu método Grab () retornará o objeto de quadro capturado. Esse quadro pode ser um quadro de vídeo ou um quadro de áudio, porque os quadros de áudio e vídeo são organizados primeiro no momento da reprodução de acordo com o registro de data e hora. Obviamente, os quadros capturados são todos decodificados e armazenados no objeto java.nio.buffer. Para quadros de vídeo, o buffer é armazenar dados de pixel da imagem, como RGB, e depois passar
BufedImage bi = (novo java2dframeconverter ()). GetBufferedImage (f);
Você pode obter a imagem e a imagem obtida pode ser processada em uma série de processos ou exibida diretamente no componente de giro sem processamento. Correspondente ao quadro de áudio, o buffer são os dados do PCM que armazenam o áudio. Este PCM pode ser flutuante ou curto e, em seguida, o método de escrita de redação em java.Sounds.Sample pode ser usado para gravar esses dados de PCM de áudio no alto -falante.
(2) Em seguida, introduza como reproduzir continuamente os quadros obtidos. Primeiro, jogue o vídeo separadamente:
while (true) {quadro f = fg.grab (); if (f.Image! = NULL) LABEL.SETICON (NOVA IMAGEICON ((new Java2DFRameConverter ()). GetBufferedImage (f))); Thread.sleep (taxa de quadros de 1000/vídeo); } O mesmo vale para reproduzir áudio separadamente, basta escrever os dados na placa de som. exemplo
(3) Modelo de produção e consumidor.
A imagem acima é um método implementado pelo programa. Os quadros capturados são julgados usando o modo produtor. Se for um quadro de vídeo, ele será produzido no vídeo FIFO. Se for um quadro de áudio, ele será produzido no Audio FIFO. Em seguida, o tópico de reprodução de áudio e o tópico de reprodução de vídeo consomem os quadros de seus respectivos armazéns de estrutura, respectivamente. O modo de produção do consumidor é adotado porque a velocidade da captura de quadros é maior que o consumo de quadros, por isso preferimos capturar quadros para buffer ou pré -processar ainda mais os quadros capturados, enquanto os threads de reprodução de vídeo e áudio precisam apenas reproduzir diretamente e exibir os quadros processados.
(4) Métodos para realizar a sincronização de áudio e vídeo: reproduza todos os quadros de vídeo em dois quadros de áudio.
Para obter sincronização de áudio e vídeo, você deve ter um carimbo de hora. Os quadros capturados aqui são apenas os PTS de timestamp de reprodução, e não há Timestamp DTS decodificado, por isso precisamos apenas decidir sobre o registro de data e hora de reprodução com base no registro de data e hora de reprodução.
A implementação do programa é baseada na figura acima. Quando o thread de áudio começa a reproduzir o quadro de áudio A1, o método setRun do thread de vídeo é chamado e o timestamp de estrutura de áudio e o próximo carimbo de tempo do próximo quadro quadro de áudio A2 são transmitidos para o tópico de vídeo no estado de espera. Em seguida, o tópico de vídeo começa e começa a tirar o quadro de vídeo G1 do vídeo FIFO e calcula a diferença de tempo entre G1 e A1 como o atraso de reprodução. Após o thread.Sleep (T1), o thread de vídeo exibe a imagem no componente de swing, como Jlabel.seticon (imagem). Em seguida, o tópico de vídeo retira outro quadro da imagem G2 e compara o registro de data e hora do G2 com o registro de data e hora de A2. Se o registro de data e hora do G2 for menor que A2, o tópico de vídeo continuará atrasando o T2 e reproduz a imagem G2. O G3 é o mesmo que deveria, até que o G4 seja obtido e A2 seja comparado ao A2 e constata que o registro de data e hora de G4 é maior que A2, então o thread de vídeo entra no estado de espera e aguarda a próxima startup. Depois que o thread de áudio reproduz o quadro de áudio A1, ele retira o quadro de áudio A3 do armazém e passa o registro de data e hora de A2 e o registro de data e hora do A3 para o tópico de vídeo e depois começa a reproduzir A2 e, em seguida, o tópico de vídeo bloqueado continua a ser reproduzido.
(5) Ajuste dinamicamente o tempo de atraso
Como os PCs pessoais não são sistemas operacionais em tempo real, ou seja, o Thread.Sleep é impreciso e é restrito pela placa de som para reproduzir som, as idéias de implementação básica acima precisam ser aprimoradas. Primeiro de tudo, o método Java SourceDataline é extrair os dados escritos pelo thread de áudio do buffer interno a uma determinada velocidade. Se os dados gravados pelo áudio forem retirados, a reprodução de áudio será gaguejada. No entanto, se muitos dados de áudio forem gravados ao mesmo tempo, o áudio e o vídeo podem estar fora de sincronização. Portanto, é necessário garantir que o buffer interno do fornecimento de dados tenha certos dados, caso contrário, causará atraso, mas a quantidade de dados não pode ser demais. Portanto, ajustamos a reprodução sonora de G3 para A2. Devido à imprecisão do atraso, os dados gravados no quadro A1 podem ser removidos pela placa de som antes que o tempo atinja T6. Portanto, depois de reproduzir a imagem do G3, o Thread Sound julgará a julgar com base na quantidade de dados retornados pela OFERCEDATALINE.AVALEBLE (). Se a quantidade de dados estiver prestes a ser concluída, o tempo de atraso T4 de G3 para A2 será reduzido. Isso garante que o volume de dados não mude para 0 e cause gagueira de som.
(6) A seguir, é apresentado o diagrama de resultados do teste do programa no Windows 64 e Ubuntu14: a reprodução é relativamente suave e a sincronização também será possível, mas se a reprodução estiver ativada, ficará preso se o Penguin gravar código no IDE, como a ideia. Afinal, a idéia também é desenvolvida em Java, portanto a operação da idéia afetará outros programas Java, mas outros processos não.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.