簡體   English   中英

JAVA-Xuggler-在組合MP3音頻文件和MP4電影的同時播放視頻

[英]JAVA - Xuggler - Play video while combining an MP3 audio file and a MP4 movie

使用JAVA和Xuggler-以下代碼組合了一個MP3音頻文件和一個MP4電影文件,並輸出了一個組合的mp4文件。

我希望outputVideo文件在組合音頻和視頻文件時應自動播放。

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();

如果有人知道在使用java xuggler組合音頻和視頻文件時會自動播放視頻文件,請幫助我。

這是完整的代碼。 我還做了一些更改:如果音頻較長,則分別編寫其余部分,並在標題欄中添加音頻和視頻的進度。 您可能需要檢查文件中是否確實有視頻或音頻流,以防止出錯。

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) + "%");
    }
}

如果您需要基於視頻幀速率顯示幀,則在每次閱讀視頻數據包后添加以下代碼,否則將其保留以進行快速合並。

try {
    Thread.sleep((long) (1000 / coderVideo.getFrameRate().getDouble()));
} catch (InterruptedException ex) {
    ex.printStackTrace();
}

它可能很舊,但是您要做的就是在jpanel上繪制圖片。 像這樣:

//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
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM