使用bufferedimages将视频编码为h264 ?

时间:2022-05-07 21:22:03

Im attempting to translate a large set of bufferedimages (pre-saved images created on the fly by my application) into a video using java and hopefully a library that can help with the process.

我正在尝试使用java将一组大型的bufferedimage(由我的应用程序动态创建的预先保存的图像)转换成一个视频,希望有一个库可以帮助这个过程。

I've explored a number of different options, such as jcodec (there was no documentation on how to use it). Xuggler (couldn't get it to run due to compatibility issues with jdk5 and its related libraries). and a number of other libraries that had very poor documentation.

我已经研究了许多不同的选项,例如jcodec(没有关于如何使用它的文档)。Xuggler(由于与jdk5及其相关库的兼容性问题,无法运行它)。还有很多其他的图书馆,它们的文档都很糟糕。

I'm trying to find a library that I can use that uses java to (1) create h264 videos by writing bufferedimages frame by frame and (2) has documentation so that I can actually figure out how to use the dam thing.

我正在尝试找到一个可以使用java(1)通过编写bufferedimages逐帧创建h264视频的库,(2)有文档,这样我就可以知道如何使用dam之类的东西。

Any ideas on what I should be looking into?

你知道我应该研究什么吗?

If pure java source code exists somewhere that can achieve this I would be VERY interested in seeing it. Because I would love to see how the person has achieved the functionality and how I could use it!

如果纯java源代码存在于可以实现这一点的地方,我将非常有兴趣看到它。因为我想看看这个人是如何实现这个功能的,以及我如何使用它!

Thanks in advance...

提前谢谢…

2 个解决方案

#1


1  

Here's how you can do it with JCodec:

下面是如何使用JCodec:

public class SequenceEncoder {
    private SeekableByteChannel ch;
    private Picture toEncode;
    private RgbToYuv420 transform;
    private H264Encoder encoder;
    private ArrayList<ByteBuffer> spsList;
    private ArrayList<ByteBuffer> ppsList;
    private CompressedTrack outTrack;
    private ByteBuffer _out;
    private int frameNo;
    private MP4Muxer muxer;

    public SequenceEncoder(File out) throws IOException {
        this.ch = NIOUtils.writableFileChannel(out);

        // Transform to convert between RGB and YUV
        transform = new RgbToYuv420(0, 0);

        // Muxer that will store the encoded frames
        muxer = new MP4Muxer(ch, Brand.MP4);

        // Add video track to muxer
        outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25);

        // Allocate a buffer big enough to hold output frames
        _out = ByteBuffer.allocate(1920 * 1080 * 6);

        // Create an instance of encoder
        encoder = new H264Encoder();

        // Encoder extra data ( SPS, PPS ) to be stored in a special place of
        // MP4
        spsList = new ArrayList<ByteBuffer>();
        ppsList = new ArrayList<ByteBuffer>();

    }

    public void encodeImage(BufferedImage bi) throws IOException {
        if (toEncode == null) {
            toEncode = Picture.create(bi.getWidth(), bi.getHeight(), ColorSpace.YUV420);
        }

        // Perform conversion
        transform.transform(AWTUtil.fromBufferedImage(bi), toEncode);

        // Encode image into H.264 frame, the result is stored in '_out' buffer
        _out.clear();
        ByteBuffer result = encoder.encodeFrame(_out, toEncode);

        // Based on the frame above form correct MP4 packet
        spsList.clear();
        ppsList.clear();
        H264Utils.encodeMOVPacket(result, spsList, ppsList);

        // Add packet to video track
        outTrack.addFrame(new MP4Packet(result, frameNo, 25, 1, frameNo, true, null, frameNo, 0));

        frameNo++;
    }

    public void finish() throws IOException {
        // Push saved SPS/PPS to a special storage in MP4
        outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));

        // Write MP4 header and finalize recording
        muxer.writeHeader();
        NIOUtils.closeQuietly(ch);
    }
}

#2


1  

jcodec now (jcodec-0.1.9.jar) includes SequenceEncoder that directly permits writing of BufferedImages to a video stream.

jcodec now (jcodec0.1.9 .jar)包括SequenceEncoder,它可以直接将缓冲编辑写入到视频流中。

I spent a while fixing the default import of this new class into Eclipse. After removing the first import, attempting (as I said above, I could not locate some of the classes) to create my own using Stanislav's code and reimporting I spotted the mistake:

我花了一段时间将这个新类的默认导入修改为Eclipse。删除第一个导入后,尝试(如我上面所说,我无法找到一些类)使用Stanislav的代码创建我自己的导入,然后重新导入,我发现了错误:

import org.jcodec.api.awt.SequenceEncoder;
//import org.jcodec.api.SequenceEncoder;

The second is completely deprecated with no documentation directing me to the latter.

第二个完全不支持,没有文档指导我使用后者。

The commensurate method is then:

公度法是:

private void saveClip(Trajectory traj) {
    //See www.tutorialspoint.com/androi/android_audio_capture.htm
    //for audio cap ideas.
    SequenceEncoder enc;
    try {
        enc = new SequenceEncoder(new File("C:/Users/WHOAMI/today.mp4"));
        for (int i = 0; i < BUFF_COUNT; ++i) {
            BufferedImage image = buffdFramToBuffdImage(frameBuff.get(i));
            enc.encodeImage(image);
        }
        enc.finish();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

#1


1  

Here's how you can do it with JCodec:

下面是如何使用JCodec:

public class SequenceEncoder {
    private SeekableByteChannel ch;
    private Picture toEncode;
    private RgbToYuv420 transform;
    private H264Encoder encoder;
    private ArrayList<ByteBuffer> spsList;
    private ArrayList<ByteBuffer> ppsList;
    private CompressedTrack outTrack;
    private ByteBuffer _out;
    private int frameNo;
    private MP4Muxer muxer;

    public SequenceEncoder(File out) throws IOException {
        this.ch = NIOUtils.writableFileChannel(out);

        // Transform to convert between RGB and YUV
        transform = new RgbToYuv420(0, 0);

        // Muxer that will store the encoded frames
        muxer = new MP4Muxer(ch, Brand.MP4);

        // Add video track to muxer
        outTrack = muxer.addTrackForCompressed(TrackType.VIDEO, 25);

        // Allocate a buffer big enough to hold output frames
        _out = ByteBuffer.allocate(1920 * 1080 * 6);

        // Create an instance of encoder
        encoder = new H264Encoder();

        // Encoder extra data ( SPS, PPS ) to be stored in a special place of
        // MP4
        spsList = new ArrayList<ByteBuffer>();
        ppsList = new ArrayList<ByteBuffer>();

    }

    public void encodeImage(BufferedImage bi) throws IOException {
        if (toEncode == null) {
            toEncode = Picture.create(bi.getWidth(), bi.getHeight(), ColorSpace.YUV420);
        }

        // Perform conversion
        transform.transform(AWTUtil.fromBufferedImage(bi), toEncode);

        // Encode image into H.264 frame, the result is stored in '_out' buffer
        _out.clear();
        ByteBuffer result = encoder.encodeFrame(_out, toEncode);

        // Based on the frame above form correct MP4 packet
        spsList.clear();
        ppsList.clear();
        H264Utils.encodeMOVPacket(result, spsList, ppsList);

        // Add packet to video track
        outTrack.addFrame(new MP4Packet(result, frameNo, 25, 1, frameNo, true, null, frameNo, 0));

        frameNo++;
    }

    public void finish() throws IOException {
        // Push saved SPS/PPS to a special storage in MP4
        outTrack.addSampleEntry(H264Utils.createMOVSampleEntry(spsList, ppsList));

        // Write MP4 header and finalize recording
        muxer.writeHeader();
        NIOUtils.closeQuietly(ch);
    }
}

#2


1  

jcodec now (jcodec-0.1.9.jar) includes SequenceEncoder that directly permits writing of BufferedImages to a video stream.

jcodec now (jcodec0.1.9 .jar)包括SequenceEncoder,它可以直接将缓冲编辑写入到视频流中。

I spent a while fixing the default import of this new class into Eclipse. After removing the first import, attempting (as I said above, I could not locate some of the classes) to create my own using Stanislav's code and reimporting I spotted the mistake:

我花了一段时间将这个新类的默认导入修改为Eclipse。删除第一个导入后,尝试(如我上面所说,我无法找到一些类)使用Stanislav的代码创建我自己的导入,然后重新导入,我发现了错误:

import org.jcodec.api.awt.SequenceEncoder;
//import org.jcodec.api.SequenceEncoder;

The second is completely deprecated with no documentation directing me to the latter.

第二个完全不支持,没有文档指导我使用后者。

The commensurate method is then:

公度法是:

private void saveClip(Trajectory traj) {
    //See www.tutorialspoint.com/androi/android_audio_capture.htm
    //for audio cap ideas.
    SequenceEncoder enc;
    try {
        enc = new SequenceEncoder(new File("C:/Users/WHOAMI/today.mp4"));
        for (int i = 0; i < BUFF_COUNT; ++i) {
            BufferedImage image = buffdFramToBuffdImage(frameBuff.get(i));
            enc.encodeImage(image);
        }
        enc.finish();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}