Android 将一系列图像编码成视频

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3688993/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:22:36  来源:igfitidea点击:

Encode a series of Images into a Video

androidvideo-encoding

提问by Rad The Mad

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?

如何从 Android 上的一系列图像/照片创建视频文件?这可以用当前的 SDK 完成吗?还是我需要一个编解码器库?

采纳答案by John J Smith

I agree with Mark. Among the C/C++ libraries are ffmpeg hereor 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 herebut 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:

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

  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.
  1. 视频格式数量有限。
  2. 不制作可在大多数(如果不是全部)Android 手机(例如 H264 或 MPEG4)上播放的视频。
  3. JMF 代码现在很旧,很长时间没有进展,臃肿且结构不合理,因此可能存在未打包在 Android 中的其他 Java 依赖项。

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

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

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

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

Good luck with the project.

祝项目顺利。

回答by Gaurav Vaish

ffmpegis your rescue ranger. You can download the FFMPEG port for android. Refer to the question FFmpeg on Androidfor more details.

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

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.

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

回答by CommonsWare

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.

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

回答by Stanislav Vitvitskyy

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 CORRECTEDclass below that utilizes JCodec low-level API:

您可以使用名为 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();
    }
}