我正在构建一个小程序来捕获屏幕和麦克风输入(音频)。我可以单独录制这些文件,但找不到将这些文件组合起来制作带音频的新视频的方法。
视频文件是.mov
格式,音频是.wav
格式。它们的长度完全相同。
有没有办法合并这些文件?我尝试过 Java,但找不到合并两个文件的方法。
我也必须这样做,ffmpeg
因为它需要安装在客户端。
private void mergeFiles() {
try {
DataSource videoDataSource = javax.media.Manager.createDataSource(oml.getURL()); //your video file
DataSource audioDataSource = javax.media.Manager.createDataSource(realAudioFile.toURI().toURL()); // your audio file
DataSource mixedDataSource = null; // data source to combine video with audio
DataSource arrayDataSource[] = new DataSource[2]; //data source array
DataSource outputDataSource = null; // file to output
DataSink outputDataSink = null; // datasink for output file
MediaLocator videoLocator = new MediaLocator(oml.getURL()); //media locator for video
MediaLocator audioLocator = new MediaLocator(realAudioFile.toURI().toURL()); //media locator for audio
FileTypeDescriptor outputType = new FileTypeDescriptor(FileTypeDescriptor.QUICKTIME); //output video format type
Format outputFormat[] = new Format[2]; //format array
VideoFormat videoFormat = new VideoFormat(VideoFormat.JPEG); // output video codec MPEG does not work on windows
javax.media.format.AudioFormat audioMediaFormat = new javax.media.format.AudioFormat(
javax.media.format.AudioFormat.LINEAR, 44100, 16, 1); //audio format
outputFormat[0] = videoFormat;
outputFormat[1] = audioMediaFormat;
//create processors for each file
Processor videoProcessor = Manager.createProcessor(videoDataSource);
Processor audioProcessor = Manager.createProcessor(audioDataSource);
Processor processor = null;
//start video and audio processors
videoProcessor.realize();
audioProcessor.realize();
//wait till they are realized
while(videoProcessor.getState() != 300 && audioProcessor.getState() != 300) {
Thread.sleep(100);
}
//get processors dataoutputs to merge
arrayDataSource[0] = videoProcessor.getDataOutput();
arrayDataSource[1] = audioProcessor.getDataOutput();
videoProcessor.start();
audioProcessor.start();
//create merging data source
mixedDataSource = javax.media.Manager.createMergingDataSource(arrayDataSource);
mixedDataSource.connect();
mixedDataSource.start();
//init final processor to create merged file
ProcessorModel processorModel = new ProcessorModel(mixedDataSource, outputFormat, outputType);
processor = Manager.createRealizedProcessor(processorModel);
processor.addControllerListener(this);
processor.configure();
//wait till configured
while(processor.getState() < 180) {
Thread.sleep(20);
}
processor.setContentDescriptor(new ContentDescriptor(FileTypeDescriptor.QUICKTIME));
TrackControl tcs[] = processor.getTrackControls();
Format f[] = tcs[0].getSupportedFormats();
tcs[0].setFormat(f[0]);
processor.realize();
//wait till realized
while(processor.getState() < 300) {
Thread.sleep(20);
}
//create merged file and start writing media to it
outputDataSource = processor.getDataOutput();
MediaLocator outputLocator = new MediaLocator("file:/"+directory.getAbsolutePath()+"/yourmovfile.mov");
outputDataSink = Manager.createDataSink(outputDataSource, outputLocator);
outputDataSink.open();
outputDataSink.addDataSinkListener(this);
outputDataSink.start();
processor.start();
while(processor.getState() < 500) {
Thread.sleep(100);
}
//wait until writing is done
waitForFileDone();
//dispose processor and datasink
outputDataSink.stop();
processor.stop();
outputDataSink.close();
processor.close();
} catch (NoDataSourceException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IncompatibleSourceException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoDataSinkException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoProcessorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (CannotRealizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Object waitFileSync = new Object();
boolean fileDone = false;
boolean fileSuccess = true;
Object waitSync = new Object();
boolean stateTransitionOK = true;
/**
* Block until file writing is done.
*/
boolean waitForFileDone() {
synchronized (waitFileSync) {
try {
while (!fileDone)
waitFileSync.wait();
} catch (Exception e) {
}
}
return fileSuccess;
}
/**
* Event handler for the file writer.
*/
public void dataSinkUpdate(DataSinkEvent evt) {
if (evt instanceof EndOfStreamEvent) {
synchronized (waitFileSync) {
fileDone = true;
waitFileSync.notifyAll();
}
} else if (evt instanceof DataSinkErrorEvent) {
synchronized (waitFileSync) {
fileDone = true;
fileSuccess = false;
waitFileSync.notifyAll();
}
}
}
@Override
public void controllerUpdate(ControllerEvent evt) {
if (evt instanceof ConfigureCompleteEvent
|| evt instanceof RealizeCompleteEvent
|| evt instanceof PrefetchCompleteEvent) {
synchronized (waitSync) {
stateTransitionOK = true;
waitSync.notifyAll();
}
} else if (evt instanceof ResourceUnavailableEvent) {
synchronized (waitSync) {
stateTransitionOK = false;
waitSync.notifyAll();
}
} else if (evt instanceof EndOfMediaEvent) {
evt.getSourceController().stop();
evt.getSourceController().close();
}
}
你的类必须实现 ControllerListener、DataSinkListener。对我来说非常适合良好的视频和音频同步(音频转换半秒,但对我来说不是问题)。
导入上述代码可能对某人有所帮助:
import java.io.IOException;
import javax.media.CannotRealizeException;
import javax.media.ConfigureCompleteEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.EndOfMediaEvent;
import javax.media.Format;
import javax.media.IncompatibleSourceException;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.NoDataSinkException;
import javax.media.NoDataSourceException;
import javax.media.NoProcessorException;
import javax.media.PrefetchCompleteEvent;
import javax.media.Processor;
import javax.media.ProcessorModel;
import javax.media.RealizeCompleteEvent;
import javax.media.ResourceUnavailableEvent;
import javax.media.control.TrackControl;
import javax.media.datasink.DataSinkErrorEvent;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.format.VideoFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;