최근 JAVACV의 FFMPEG 패키지를 사용하는 FFMPEGFRAMEGRABBER 프레임 캡처는 캡처 된 오디오 프레임 및 비디오 프레임을 동기화했습니다. 사용 된 동기화 방법은 비디오를 오디오에 동기화하는 것입니다.
프로그램 및 소스 코드
특정 아이디어는 다음과 같습니다.
(1) 먼저 FFMPEG가 비디오 파일의 이미지와 사운드를 캡처하는 방법을 소개합니다.
FFMPEGFRAMEGRABBER FG = NEW FFMPEGFRAMEGRABBER ( "비디오 파일 경로 또는 URL);
프레임 캡처 객체를 얻은 후 grab () 메소드를 호출하면 캡처 된 프레임 객체를 반환합니다. 오디오 및 비디오 프레임은 타임 스탬프에 따라 재생 시간에 먼저 배열되기 때문에이 프레임은 비디오 프레임 또는 오디오 프레임 일 수 있습니다. 물론 캡처 된 프레임은 모두 java.nio.buffer 객체에 디코딩되어 저장됩니다. 비디오 프레임의 경우 버퍼는 RGB와 같은 이미지의 픽셀 데이터를 저장 한 다음 통과하는 것입니다.
BufferedImage bi = (새로운 java2dframeconverter ()). getbufferedimage (f);
사진을 얻을 수 있으며 얻은 그림은 처리없이 일련의 프로세스로 처리하거나 스윙 구성 요소에 직접 표시 될 수 있습니다. 오디오 프레임에 해당하는 버퍼는 오디오를 저장하는 PCM 데이터입니다. 이 PCM은 플로트 또는 짧을 수 있으며 outcedataline.write 메소드에서 java.sounds.sample을 사용하여 이러한 오디오 PCM 데이터를 스피커에 작성할 수 있습니다.
(2) 그런 다음 얻은 프레임을 지속적으로 재생하는 방법을 소개합니다. 먼저 비디오를 별도로 재생하십시오.
while (true) {frame f = fg.grab (); if (f.image! = null) label.seticon (new imageicon ((new java2dframeconverter ()). getBufferedImage (f)); Thread.Sleep (1000/비디오 프레임 속도); } 오디오를 별도로 재생하는 것도 마찬가지입니다. 데이터를 사운드 카드에 작성하십시오. 예
(3) 생산 및 소비자 모델.
위의 그림은 프로그램에서 구현 한 메소드입니다. 캡처 된 프레임은 생산자 모드를 사용하여 판단됩니다. 비디오 프레임 인 경우 비디오 FIFO로 제작됩니다. 오디오 프레임 인 경우 오디오 FIFO로 생성됩니다. 그런 다음 오디오 재생 스레드와 비디오 재생 스레드는 각각 해당 프레임 창고에서 프레임을 소비합니다. 프레임 캡처 속도가 프레임 소비보다 크기 때문에 생산 소비자 모드가 채택되므로 버퍼링을위한 프레임을 캡처하거나 캡처 된 프레임을 추가로 전처리하는 것이 좋습니다. 비디오 및 오디오 재생 스레드는 처리 된 프레임을 직접 재생하고 표시하면됩니다.
(4) 오디오 및 비디오 동기화를 실현하는 방법 : 오디오의 두 프레임에서 모든 비디오 프레임을 재생합니다.
오디오 및 비디오 동기화를 달성하려면 프레임 타임 스탬프가 있어야합니다. 여기에 캡처 된 프레임은 재생 타임 스탬프 PTS 만 있으며 디코딩 된 타임 스탬프 DTS는 없으므로 재생 타임 스탬프를 기반으로 재생 타임 스탬프 만 결정하면됩니다.
프로그램의 구현은 위의 그림을 기반으로합니다. 오디오 스레드가 오디오 프레임 A1을 재생하기 시작하면 비디오 스레드의 SetRun 메소드가 호출되고 현재 오디오 프레임의 타임 스탬프 곡선이 재생되고 다음 프레임 프레임 A2의 다음 타임 스탬프가 대기 상태의 비디오 스레드로 전달됩니다. 그런 다음 비디오 스레드가 시작하여 비디오 FIFO에서 비디오 프레임 G1을 꺼내기 시작한 다음 재생 지연으로 G1과 A1의 시차를 계산합니다. Thread.Sleep (T1) 후 비디오 스레드는 Jlabel.seticon (이미지)과 같은 스윙 구성 요소에 그림을 표시합니다. 그런 다음 비디오 스레드는 이미지 G2의 다른 프레임을 가져 와서 G2의 타임 스탬프를 A2의 타임 스탬프와 비교합니다. G2의 타임 스탬프가 A2 미만인 경우 비디오 스레드는 계속 T2를 지연시키고 G2 이미지를 재생합니다. 그런 다음 G3은 G4가 얻어지고 A2가 A2와 비교 될 때까지 G4의 타임 스탬프가 A2보다 크다는 것을 발견하고 비디오 스레드가 대기 상태로 들어가 다음 시작을 기다립니다. 그런 다음 오디오 스레드가 A1 오디오 프레임을 재생하면 창고에서 오디오 프레임 A3을 가져온 다음 A2의 타임 스탬프와 A3의 타임 스탬프를 비디오 스레드로 전달 한 다음 A2 재생을 시작한 다음 차단 된 비디오 스레드가 계속 재생됩니다.
(5) 지연 시간을 동적으로 조정하십시오
개인 PC는 실시간 운영 체제가 아니기 때문에 Sleep.sleep는 부정확하고 사운드 카드에 의해 제한되어 사운드를 재생하기 위해서는 위의 기본 구현 아이디어를 개선해야합니다. 우선, Java Sourcedataline 방법은 내부 버퍼에서 오디오 스레드가 작성한 데이터를 특정 속도로 추출하는 것입니다. 오디오가 작성한 데이터가 꺼지면 오디오 재생이 더러워집니다. 그러나 오디오 데이터가 너무 많으면 한 번에 오디오와 비디오가 동기화되지 않을 수 있습니다. 따라서, 소스진다 라인의 내부 완충액에 특정 데이터가 있는지 확인해야합니다. 그렇지 않으면 지연이 발생하지만 데이터의 양은 너무 많을 수 없습니다. 따라서 사운드 재생을 G3에서 A2로 조정합니다. 지연의 부정확성으로 인해 A1 프레임으로 작성된 데이터는 시간이 T6에 도달하기 전에 사운드 카드에 의해 제거 될 수 있습니다. 따라서 G3 이미지를 재생 한 후 사운드 스레드는 SourcedAtaline.available ()에 의해 반환 된 데이터의 양을 기준으로 판단 할 것입니다. 데이터 양이 완료 되려면 G3에서 A2로 지연 시간 T4가 줄어 듭니다. 이를 통해 데이터 볼륨이 0으로 변경되지 않고 사운드 말더듬을 유발할 수 있습니다.
(6) 다음은 Windows 64 및 Ubuntu14에서 프로그램 테스트의 결과 다이어그램입니다. 재생은 비교적 매끄럽고 동기화도 가능하지만 재생이 켜지면 펭귄이 아이디어와 같은 IDE에 코드를 작성하면 고정됩니다. 결국, 아이디어는 Java에서도 개발되므로 아이디어 운영은 다른 Java 프로그램에 영향을 미치지 만 다른 프로세스는 그렇지 않습니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.