Encoder une série d'Images dans une Vidéo

Comment puis-je créer un fichier vidéo à partir d'une série d'images/photos sur Android? Cela peut-il être fait avec le SDK actuel? ou Ai-je besoin d'une bibliothèque de codecs?

40

4 réponses

Je suis d'accord avec Marc. Parmi les bibliothèques C/C++ sont ffmpeg ici ou X264 ici. Je dois dire que je ne les ai pas trouvés ou L'Android NDK facile à utiliser, mais c'est probablement parce que je ne sais pas vraiment grand-chose sur C/C++ et JNI. Si vous êtes intéressé par cette route, alors L'application gratuite RockPlayer pour Android a les bibliothèques partagées pré-construites de ffmpeg prêt à être utilisé sur Android. Ils prétendent que ces bibliothèques n'utilisent que des composants LGPL mais vous devrez vous satisfaire à ce sujet, je suppose. En ce qui concerne Java, il existe un port (de toutes sortes) de ffmpeg appelé, sans surprise, jffmpeg auquel vous pouvez accéder ici mais il appelle toujours une grande partie du framework ffmpeg existant, donc vous êtes de retour dans NDK land. Il est possible de convertir une série d'images en vidéo avec le Java Media Framework (JMF) mais il présente les inconvénients suivants:

  1. nombre Limité de formats vidéo.
  2. ne produit pas de vidéos qui peuvent être lues sur la plupart (sinon tous) les téléphones Android, par exemple H264 ou MPEG4.
  3. le code JMF est maintenant assez vieux, n'a pas progressé depuis longtemps, est gonflé et pas bien structuré, donc il peut y avoir des dépendances Java supplémentaires qui ne sont pas empaquetées dans Android.

Une autre option que J'ai vu utilisée est Adobe Air, mais c'est une charge utile de 17 Mo dont certains utilisateurs se plaignent.

Il y a beaucoup d'autres questions ici sur Stack Overflow concernant ffmpeg et Android NDK.

Bonne chance avec le projet.

11
répondu John J Smith 2011-04-14 20:44:59

Il n'y a pas de support intégré pour cela. Vous devez soit trouver du code source Java qui fait ce dont vous avez besoin, soit du code C / C++ que vous pouvez transformer en bibliothèque et utiliser via le NDK. Ou, si l'objectif final est pour que la vidéo soit sur un serveur, téléchargez les images/photos et demander au serveur de créer la vidéo.

4
répondu CommonsWare 2010-09-10 23:40:05

ffmpeg est votre ranger de sauvetage. Vous pouvez télécharger le port FFMPEG pour android. Reportez-vous à la question FFmpeg sur Android pour plus de détails.

Le port prend en charge presque tout ce dont vous aurez besoin, y compris les formats - les formats d'image d'entrée étant GIF, JPG, PNG, BMP, etc. et les formats vidéo de sortie étant AVI, MP4 (conteneurs) avec beaucoup de codecs.

4
répondu Gaurav Vaish 2017-05-23 12:17:46

Vous pouvez utiliser une bibliothèque open source gratuite appelée JCodec ( http://jcodec.org ) qui contient des implémentations java pures de certains formats vidéo et codecs populaires, y compris: H. 264 ( AVC ), MPEG 1/2, Apple ProRes, JPEG, MP4 ( ISO BMF ), MPEG PS, MPEG TS, Matroska.
Vous pouvez utiliser la classecorrigée ci-dessous qui utilise L'API de bas niveau 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
        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();
    }
}
1
répondu Stanislav Vitvitskyy 2013-05-13 18:24:03