将一系列图像编码为视频

发布于 2024-09-19 13:02:38 字数 62 浏览 1 评论 0原文

如何在 Android 上从一系列图像/照片创建视频文件? 现在的SDK可以实现吗?或者我需要一个编解码器库?

How can I create a video file from a series of images/photos on Android?
Can this be done with the current SDK? or do I need a codec library?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

删除→记忆 2024-09-26 13:02:38

我同意马克的观点。 C/C++ 库包括 ffmpeg 此处 或 X264 此处。我不得不说我还没有发现它们或 Android NDK 易于使用,但这可能是因为我对 C/C++ 和 JNI 不太了解。如果您对此路线感兴趣,那么适用于 Android 的 RockPlayer 免费应用程序具有来自 ffmpeg 的预构建共享库,可供在 Android 上使用。他们声称这些库仅使用 LGPL 组件,但我想您必须对此感到满意。对于 Java,有一个 ffmpeg 端口(某种),毫不奇怪地称为 jffmpeg,您可以在 此处 但它仍然调用现有的 ffmpeg 框架的大部分内容,因此您又回到了 NDK 领域。可以使用 Java Media Framework (JMF) 将一系列图像转换为视频,但它具有以下缺点:

  1. 视频格式数量有限。
  2. 不生成可在大多数(如果不是全部)Android 手机(例如 H264 或 MPEG4)上播放的视频。
  3. JMF 代码现在相当旧,很长时间没有进展,臃肿且结构不佳,因此可能存在未打包在 Android 中的额外 Java 依赖项。

我见过的另一个选项是 Adob​​e Air,但它的有效负载为 17Mb,一些用户对此有所抱怨。

Stack Overflow 上还有很多有关 ffmpeg 和 Android NDK 的其他问题。

祝项目顺利。

I agree with Mark. Among the C/C++ libraries are ffmpeg here or X264 here. I have to say I havn't found them or the Android NDK easy to use but that's probably because I don't really know much about C/C++ and JNI. If you're interested in this route, then the RockPlayer free app for Android has the pre-built shared libraries from ffmpeg ready for use on Android. They claim these libraries only use LGPL components but you'd have to satisfy yourself on this, I guess. With regards to Java, there is a port (of sorts) of ffmpeg called, unsurprisingly, jffmpeg which you can access here but it still calls out to much of the existing ffmpeg framework, so you're back in NDK land. It is possible to convert a series of images to video with the Java Media Framework (JMF) but it has the following drawbacks:

  1. Limited number of video formats.
  2. Doesn't produce videos which can be played back on most (if not all) Android phones e.g. H264 or MPEG4.
  3. The JMF code is now quite old, hasn't progressed in a long time, is bloated and not well structured so there may be additional Java dependencies which are not packaged in Android.

Another option I've seen used is Adobe Air, but it's a 17Mb payload which some users complain about.

There are lots of other questions here on Stack Overflow regarding ffmpeg and Android NDK.

Good luck with the project.

自此以后,行同陌路 2024-09-26 13:02:38

对此没有内置支持。您需要找到一些可以满足您需要的 Java 源代码,或者一些可以转换为库并通过 NDK 使用的 C/C++ 代码。或者,如果最终目标是将视频存储在服务器上,请上传图像/照片并让服务器创建视频。

There is no built-in support for this. You would need to either find some Java source code that does what you need, or some C/C++ code you can turn into a library and use via the NDK. Or, if the end goal is for the video to be on a server, upload the images/photos and have the server create the video.

谎言 2024-09-26 13:02:38

ffmpeg 是您的救援护林员。您可以下载适用于 Android 的 FFMPEG 端口。请参阅问题Android 上的 FFmpeg 了解更多详细信息。

该端口支持几乎所有您需要的内容,包括格式 - 输入图像格式为 GIF、JPG、PNG、BMP 等,输出视频格式为 AVI、MP4(容器)以及多种编解码器。

ffmpeg is your rescue ranger. You can download the FFMPEG port for android. Refer to the question FFmpeg on Android for more details.

The port supports almost everything that you'll ever need, including the formats - input image formats being GIF, JPG, PNG, BMP etc and output video formats being AVI, MP4 (containers) with a lot of codecs.

人间不值得 2024-09-26 13:02:38

您可以使用名为 JCodec ( http://jcodec.org ) 的免费开源库,其中包含一些流行的纯 Java 实现视频格式和编解码器,包括:H.264 ( AVC )、MPEG 1/2、Apple ProRes、JPEG、MP4 ( ISO BMF )、MPEG PS、MPEG TS、Matroska。
您可以使用下面利用 JCodec 低级 API 的 CORRECTED 类:

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
        for (int i = 0; i < 3; i++)
            Arrays.fill(toEncode.getData()[i], 0);
        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);
    }

    public static void main(String[] args) throws IOException {
        SequenceEncoder encoder = new SequenceEncoder(new File("video.mp4"));
        for (int i = 1; i < 100; i++) {
            BufferedImage bi = ImageIO.read(new File(String.format("folder/img%08d.png", i)));
            encoder.encodeImage(bi);
        }
        encoder.finish();
    }
}

You can use a free open source library called JCodec ( http://jcodec.org ) that contains pure java implementations of some popular video formats and codecs, including: H.264 ( AVC ), MPEG 1/2, Apple ProRes, JPEG, MP4 ( ISO BMF ), MPEG PS, MPEG TS, Matroska.
You can use the CORRECTED class below that utilizes JCodec low-level API:

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
        for (int i = 0; i < 3; i++)
            Arrays.fill(toEncode.getData()[i], 0);
        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);
    }

    public static void main(String[] args) throws IOException {
        SequenceEncoder encoder = new SequenceEncoder(new File("video.mp4"));
        for (int i = 1; i < 100; i++) {
            BufferedImage bi = ImageIO.read(new File(String.format("folder/img%08d.png", i)));
            encoder.encodeImage(bi);
        }
        encoder.finish();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文