问题
Using JAVA and Xuggler - the following code combines an MP3 audio file and a MP4 movie file and outputs a combined mp4 file.
I want outputVideo file should be play automatically while combining audio and video file.
String inputVideoFilePath = "in.mp4";
String inputAudioFilePath = "in.mp3";
String outputVideoFilePath = "out.mp4";
IMediaWriter mWriter = ToolFactory.makeWriter(outputVideoFilePath);
IContainer containerVideo = IContainer.make();
IContainer containerAudio = IContainer.make();
// check files are readable
if (containerVideo.open(inputVideoFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputVideoFilePath);
if (containerAudio.open(inputAudioFilePath, IContainer.Type.READ, null) < 0)
throw new IllegalArgumentException("Cant find " + inputAudioFilePath);
// read video file and create stream
IStreamCoder coderVideo = containerVideo.getStream(0).getStreamCoder();
if (coderVideo.open(null, null) < 0)
throw new RuntimeException("Cant open video coder");
IPacket packetvideo = IPacket.make();
int width = coderVideo.getWidth();
int height = coderVideo.getHeight();
// read audio file and create stream
IStreamCoder coderAudio = containerAudio.getStream(0).getStreamCoder();
if (coderAudio.open(null, null) < 0)
throw new RuntimeException("Cant open audio coder");
IPacket packetaudio = IPacket.make();
mWriter.addAudioStream(1, 0, coderAudio.getChannels(), coderAudio.getSampleRate());
mWriter.addVideoStream(0, 0, width, height);
while (containerVideo.readNextPacket(packetvideo) >= 0) {
containerAudio.readNextPacket(packetaudio);
// video packet
IVideoPicture picture = IVideoPicture.make(coderVideo.getPixelType(), width, height);
coderVideo.decodeVideo(picture, packetvideo, 0);
if (picture.isComplete())
mWriter.encodeVideo(0, picture);
// audio packet
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packetaudio, 0);
if (samples.isComplete())
mWriter.encodeAudio(1, samples);
}
coderAudio.close();
coderVideo.close();
containerAudio.close();
containerVideo.close();
mWriter.close();
If anybody knows play video file automatically when combining audio and video file using java xuggler.. please please help me..It would be really appreciable..
回答1:
Here is the complete code. I also did some changes: if audio is longer, then write the rest separately, and added progress of audio and video in title bar. You may need to check if there is really video or audio stream in your files to prevent errors.
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.Global;
import com.xuggle.xuggler.IAudioSamples;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IPacket;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.IVideoPicture;
import com.xuggle.xuggler.video.ConverterFactory;
import com.xuggle.xuggler.video.IConverter;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
/**
*
* @author Pasban
*/
public class MergeVideoAudio extends JDialog {
Image image;
private double video_duration = 0.00001, video_read = 0, audio_duration = 0.00001, audio_read = 0;
public static void main(String[] args) {
final MergeVideoAudio merge = new MergeVideoAudio();
Thread thread = new Thread() {
@Override
public void run() {
merge.perform("y:/a.mp4", "y:/b.mp3", "y:/c.mp4");
merge.setVisible(false);
System.exit(0);
}
};
thread.run();
}
public void perform(String path_video, String path_audio, String path_output) {
IMediaWriter mWriter = ToolFactory.makeWriter(path_output);
IContainer containerVideo = IContainer.make();
IContainer containerAudio = IContainer.make();
// check files are readable
if (containerVideo.open(path_video, IContainer.Type.READ, null) < 0) {
throw new IllegalArgumentException("Cant find " + path_video);
}
if (containerAudio.open(path_audio, IContainer.Type.READ, null) < 0) {
throw new IllegalArgumentException("Cant find " + path_audio);
}
// read video file and create stream
IStreamCoder coderVideo = containerVideo.getStream(0).getStreamCoder();
if (coderVideo.open(null, null) < 0) {
throw new RuntimeException("Cant open video coder");
}
int width = coderVideo.getWidth();
int height = coderVideo.getHeight();
this.setSize(width, height);
this.setLocationRelativeTo(null);
this.setVisible(true);
// read audio file and create stream
IStreamCoder coderAudio = containerAudio.getStream(0).getStreamCoder();
if (coderAudio.open(null, null) < 0) {
throw new RuntimeException("Cant open audio coder");
}
IPacket packet = IPacket.make();
mWriter.addAudioStream(1, 0, coderAudio.getChannels(), coderAudio.getSampleRate());
mWriter.addVideoStream(0, 0, width, height);
video_duration = 0.000001 + (containerVideo.getDuration() == Global.NO_PTS ? 0 : (containerVideo.getDuration() / 1000.0));
audio_duration = 0.000001 + (containerAudio.getDuration() == Global.NO_PTS ? 0 : (containerAudio.getDuration() / 1000.0));
while (containerVideo.readNextPacket(packet) >= 0) {
video_read = (packet.getTimeStamp() * packet.getTimeBase().getDouble() * 1000);
// video packet
IVideoPicture picture = IVideoPicture.make(coderVideo.getPixelType(), width, height);
coderVideo.decodeVideo(picture, packet, 0);
if (picture.isComplete()) {
mWriter.encodeVideo(0, picture);
IConverter converter = ConverterFactory.createConverter(ConverterFactory.XUGGLER_BGR_24, picture);
this.setImage(converter.toImage(picture));
this.setProgress(video_duration, video_read, audio_duration, audio_read);
}
// audio packet
containerAudio.readNextPacket(packet);
audio_read = (packet.getTimeStamp() * packet.getTimeBase().getDouble() * 1000);
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packet, 0);
if (samples.isComplete()) {
mWriter.encodeAudio(1, samples);
this.setProgress(video_duration, video_read, audio_duration, audio_read);
}
}
//write the remaining audio, if your audio is longer than your video
while (containerAudio.readNextPacket(packet) >= 0) {
audio_read = (packet.getTimeStamp() * packet.getTimeBase().getDouble() * 1000);
IAudioSamples samples = IAudioSamples.make(512, coderAudio.getChannels(), IAudioSamples.Format.FMT_S32);
coderAudio.decodeAudio(samples, packet, 0);
if (samples.isComplete()) {
mWriter.encodeAudio(1, samples);
this.setProgress(video_duration, video_read, audio_duration, audio_read);
}
}
coderAudio.close();
coderVideo.close();
containerAudio.close();
containerVideo.close();
mWriter.close();
}
public MergeVideoAudio() {
this.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public void setImage(final Image image) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MergeVideoAudio.this.image = image;
repaint();
}
});
}
@Override
public synchronized void paint(Graphics g) {
if (image != null) {
g.drawImage(image, 0, 0, null);
}
}
public static String convertDurationHMSm(double time) {
long elapsed = (long) (time * 1000);
long duration = elapsed / 1000;
long ms = elapsed % 1000;
return String.format("%02d:%02d:%02d.%02d", duration / 3600, (duration % 3600) / 60, (duration % 60), ms / 10);
}
private void setProgress(double video_duration, double video_read, double audio_duration, double audio_read) {
this.setTitle("Video: " + (int) (100 * video_read / video_duration) + "%, Audio " + (int) (100 * audio_read / audio_duration) + "%");
}
}
If you need to show frames based on video frame rate, then add the following code after every time you read your video packet, or else leave it for fast merging.
try {
Thread.sleep((long) (1000 / coderVideo.getFrameRate().getDouble()));
} catch (InterruptedException ex) {
ex.printStackTrace();
}
回答2:
It might be old, but all you need to do is to paint your picture on a jpanel. Something like this:
//Instead of
if (picture.isComplete()){
mWriter.encodeVideo(0, picture);
}
//Use
if (picture.isComplete()) {
mWriter.encodeVideo(0, picture);
IConverter converter = ConverterFactory.createConverter(ConverterFactory.XUGGLER_BGR_24, picture);
repaint_on_jpanel_thread(converter.toImage(picture));
//this is a function to paint the buffered image on your jpanel
}
来源:https://stackoverflow.com/questions/23784422/java-xuggler-play-video-while-combining-an-mp3-audio-file-and-a-mp4-movie