web-dev-qa-db-fra.com

Encoder une série d'images en vidéo

Comment 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
Rad The Mad

Je suis d'accord avec Mark. Parmi les bibliothèques C/C++ se trouvent ffmpeg ici ou X264 ici . Je dois dire que je ne les ai pas trouvés ou le ND Android NDK facile à utiliser, mais c'est probablement parce que je ne connais pas vraiment grand-chose en C/C++ et JNI. Si vous êtes intéressé par cette route, puis l'application gratuite RockPlayer pour Android a les bibliothèques partagées pré-construites de ffmpeg prêtes à être utilisées sur Android. Ils prétendent que ces bibliothèques utilisent uniquement des composants LGPL mais vous devez vous satisfaire à ce sujet, je suppose. En ce qui concerne Java, il existe un port (en quelque sorte) de ffmpeg appelé, sans surprise, jffmpeg auquel vous pouvez accéder ici mais il appelle toujours une grande partie du cadre ffmpeg existant , vous êtes donc de retour au pays NDK. 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 pouvant être lues sur la plupart (sinon la totalité) des téléphones Android, par exemple H264 ou MPEG4).
  3. Le code JMF est maintenant assez ancien, n'a pas progressé depuis longtemps, est gonflé et mal structuré, il peut donc y avoir des dépendances supplémentaires Java qui ne sont pas packagées dans Android.

Une autre option que j'ai vue 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 pour ton projet.

11
John J Smith

Il n'y a pas de support intégré pour cela. Vous devrez 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 demandez au serveur de créer la vidéo.

4
CommonsWare

ffmpeg est votre garde forestier. 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 un beaucoup de codecs.

4
Gaurav Vaish

Vous pouvez utiliser une bibliothèque open source gratuite appelée JCodec ( http://jcodec.org ) qui contient des implémentations Java Java de certains formats vidéo et codecs populaires, notamment: H.264 (AVC), MPEG 1/2, Apple ProRes, JPEG, MP4 (ISO BMF), MPEG PS, MPEG TS, Matroska.
Vous pouvez utiliser la classe [~ # ~] [~ # ~] corrigé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