FFmpeg sur Android

207

J'ai compilé FFmpeg (libffmpeg.so) sur Android. Maintenant, je dois créer une application comme RockPlayer ou utiliser le cadre multimédia Android existant pour appeler FFmpeg.

  1. Avez-vous des étapes / procédures / code / exemple sur l'intégration de FFmpeg sur Android / StageFright?

  2. Pouvez-vous me guider sur la façon d'utiliser cette bibliothèque pour la lecture multimédia?

  3. J'ai une exigence où j'ai déjà des flux de transport audio et vidéo, que je dois alimenter à FFmpeg et le décoder / rendre. Comment puis-je le faire sur Android, car les API IOMX sont basées sur OMX et ne peuvent pas plug-in FFmpeg ici?

  4. De plus, je n'ai pas pu trouver de documentation sur les API FFmpeg qui doivent être utilisées pour la lecture.

Pointe
la source
7
c'est intéressant, je suis aussi curieux
Axarydax
5
comment avez-vous compilé ffmpeg pour obtenir des fichiers .so? pouvez-vous s'il vous plaît partager les étapes que vous avez suivies. Je travaille sur windows avec cygwin-1.7.9 et ndk r5. Aidez-moi, s'il vous plaît.
Swathi EP
Voici un FFmpeg relativement nouveau pour Android: sourceforge.net/projects/ffmpeg4android
slhck
@slhck j'ai téléchargé le code ffmpeg à partir du lien ci-dessus et j'ai essayé de le compiler mais je ne suis pas en mesure d'obtenir les fichiers .so. cela montre beaucoup de problèmes ..
RAJESH
s'il vous plaît aidez-moi avec: stackoverflow.com/questions/14157030/… , je ne sais pas où inclure cette fonction et exécuter! .....
TharakaNirmana

Réponses:

110

Voici les étapes que j'ai suivies pour que ffmpeg fonctionne sur Android:

  1. Créez des bibliothèques statiques de ffmpeg pour Android. Ceci a été réalisé en construisant le port Android ffmpeg d' Olvaffe ( libffmpeg ) en utilisant le système de construction Android . Placez simplement les sources sous / externe et makeloin. Vous devrez également extraire bionic (libc) et zlib (libz) de la version Android, car les bibliothèques ffmpeg en dépendent.
  2. Créez une bibliothèque dynamique encapsulant la fonctionnalité ffmpeg à l'aide du NDK Android . Il y a beaucoup de documentation sur la façon de travailler avec le NDK. Fondamentalement, vous devrez écrire du code C / C ++ pour exporter les fonctionnalités dont vous avez besoin de ffmpeg dans une bibliothèque avec laquelle Java peut interagir via JNI. Le NDK vous permet de vous lier facilement aux bibliothèques statiques que vous avez générées à l'étape 1, il suffit d'ajouter une ligne similaire à celle d'Android.mk:LOCAL_STATIC_LIBRARIES := libavcodec libavformat libavutil libc libz

  3. Utilisez la bibliothèque dynamique ffmpeg-wrapping de vos sources java. Il y a suffisamment de documentation sur JNI, ça devrait aller.

Concernant l'utilisation de ffmpeg pour la lecture, il existe de nombreux exemples (le binaire ffmpeg lui-même en est un bon exemple), voici un tutoriel de base. La meilleure documentation se trouve dans les en-têtes.

Bonne chance :)

yonilevy
la source
7
Il y a pas mal de liens vers cette réponse pour construire ffmpeg pour Android. Est-ce toujours la meilleure solution? Le lien Android Build System est rompu - qu'est-ce que c'est censé être? Il existe un tas de boîtes à outils pour aider à construire avec le NDK. Cependant, ils échouent tous avec diverses erreurs de construction pour moi et semblent un peu vieux. Y a-t-il une raison pour laquelle quelqu'un ne peut pas simplement publier une lib ffmpeg statique construite?
Rob Lourens
7
Pour répondre à ma propre question, j'ai trouvé que ce dépôt était le plus utile pour construire des wrappers ffmpeg et JNI - github.com/andynicholson/android-ffmpeg-x264
Rob Lourens
68

Pour diverses raisons, le multimédia n'a pas été et n'est jamais facile à réaliser sans compromettre l'efficacité. ffmpeg est un effort pour l'améliorer de jour en jour. Il prend en charge différents formats de codecs et de conteneurs.

Maintenant, pour répondre à la question de l'utilisation de cette bibliothèque , je dirais que ce n'est pas si simple de l'écrire ici. Mais je peux vous guider de différentes manières .

1) Dans le répertoire ffmpeg du code source, vous avez output_example.c ou api_example.c . Ici, vous pouvez voir le code où l'encodage / décodage est effectué. Vous aurez une idée des API à l'intérieur de ffmpeg que vous devez appeler. Ce serait votre première étape.

2) Dolphin player est un projet open source pour Android. Actuellement, il a des bugs mais les développeurs travaillent en permanence. Dans ce projet, vous avez toute la configuration prête que vous pouvez utiliser pour poursuivre votre enquête. Voici un lien vers le projet à partir de code.google.com ou exécutez la commande " git clone https://code.google.com/p/dolphin-player/ " dans un terminal. Vous pouvez voir deux projets nommés P et P86. Vous pouvez utiliser l'un ou l'autre.

Un conseil supplémentaire que je voudrais offrir est que lorsque vous construisez le code ffmpeg, à l'intérieur de build.sh, vous devez activer les muxers / demuxers / encoders / decoders des formats que vous souhaitez utiliser. Sinon, le code correspondant ne sera pas inclus dans les bibliothèques. Il m'a fallu beaucoup de temps pour réaliser cela. Alors j'ai pensé à le partager avec vous.

Quelques notions de base: quand on dit un fichier vidéo, ex: avi, c'est une combinaison à la fois audio et vidéo

Fichier vidéo = vidéo + audio


Vidéo = Codec + Muxer + Demuxer

codec = encodeur + décodeur

=> Vidéo = encodeur + décodeur + Muxer + Demuxer (Mpeg4 + Mpeg4 + avi + avi - Exemple pour conteneur avi)


Audio = Codec + Muxer + Demuxer

codec = encodeur + décodeur

=> Audio = encodeur + décodeur + Muxer + Demuxer (mp2 + mp2 + avi + avi - Exemple pour conteneur avi)


Le codec (le nom est dérivé d'une combinaison de en * co * der / * dec * oder) n'est qu'une partie du format qui définit les algorithmes utilisés pour coder / décoder une trame. AVI n'est pas un codec, c'est un conteneur qui utilise le codec vidéo de Mpeg4 et le codec audio de mp2.

Muxer / demuxer est utilisé pour combiner / séparer les trames d'un fichier utilisé lors de l'encodage / décodage.

Donc, si vous souhaitez utiliser le format avi, vous devez activer les composants vidéo + composants audio.

Par exemple, pour avi, vous devez activer les éléments suivants. Encodeur mpeg4, décodeur mpeg4, encodeur mp2, décodeur mp2, avi muxer, avi demuxer.

phewwwwwww ...

Build.sh par programme doit contenir le code suivant:

--enable-muxer=avi --enable-demuxer=avi (Generic for both audio/video. generally Specific to a container)
--enable-encoder=mpeg4 --enable-decoder=mpeg4(For video support)
--enable-encoder=mp2 --enable-decoder=mp2 (For Audio support)

J'espère que je ne vous ai plus confondu après tout cela ...

Merci, toute aide nécessaire, veuillez me le faire savoir.

mk ..
la source
1
Hé, je voudrais vous remercier beaucoup pour ces informations, vous m'avez vraiment beaucoup aidé, est-ce possible pour vous de m'aider si j'en aurai besoin plus tard? Je vous remercie!
idish
Puis-je vous ajouter s'il vous plaît via skype / MSN ou toute autre plateforme de chat s'il vous plaît? J'ai quelques questions à ce sujet, merci.
idish
2
Sûr..!! Mais ma présence en ligne est un peu faible .. Sauf si c'est très nécessaire je ne me connecte pas à skype. Vous pouvez m'envoyer un mail pour toute chose importante. Courriel: [email protected]
mk ..
13

L'implémentation la plus facile à construire et à utiliser que j'ai trouvée est faite par l'équipe de gardianproject: https://github.com/guardianproject/android-ffmpeg

Gars
la source
Je ne suis pas sûr, je suppose que c'est le cas, rien dans la nouvelle version iOS ne me vient à l'esprit qui pourrait casser cela. Quand j'ai posté ça, j'avais encore 10,7 ou 10,6
Guy
savez-vous, comment puis-je convertir 3gp en audio, en utilisant l'implémentation JNI
Mr.G
11

J'ai fait un petit projet pour configurer et construire X264 et FFMPEG en utilisant le NDK Android. La principale chose qui manque est une interface JNI décente pour la rendre accessible via Java, mais c'est la partie facile (relativement). Quand j'arriverai à rendre l'interface JNI bonne pour mes propres utilisations, je l'enfoncerai.

L'avantage par rapport au système de construction d'Olvaffe est qu'il ne nécessite pas de fichiers Android.mk pour construire les bibliothèques, il utilise simplement les makefiles réguliers et la chaîne d'outils. Cela le rend beaucoup moins susceptible de cesser de fonctionner lorsque vous tirez un nouveau changement de FFMPEG ou X264.

https://github.com/halfninja/android-ffmpeg-x264

pseudo
la source
Nick, votre projet ne se compile pas sur OS X 10.7 libx264.a (common.o): Dans la fonction x264_param_parse': common.c:(.text+0x2864): undefined reference to _DefaultRuneLocale 'collect2: ld a renvoyé 1 état de sortie make: *** [x264] Erreur 1
Yuriy Solovyov
6

Pour créer mon application FFMPEG, j'ai utilisé ce projet ( https://github.com/hiteshsondhi88/ffmpeg-android-java ) donc, je n'ai rien à compiler. Je pense que c'est le moyen facile d'utiliser FFMPEG dans nos applications Android.

Plus d'informations sur http://hiteshsondhi88.github.io/ffmpeg-android-java/

jmartinalonso
la source
3
Cette enveloppe est très très très très très très lente. 200 images à la vidéo prennent 50-60 secondes. . . mais normalement ffmpeg gère cette tâche en 4-5 secondes.
Arsen Sench
Ce projet ne fonctionne plus. Avez-vous d'autres ressources?
Ajeet
@ArsenSench avez-vous une autre solution?
Akash Dubey
3

Inspiré par de nombreux autres FFmpeg sur les implémentations Android (principalement le projet guadian ), j'ai trouvé une solution (avec le support de Lame également).

(lame et FFmpeg: https://github.com/intervigilium/liblame et http://bambuser.com/opensource )

pour appeler FFmpeg:

new Thread(new Runnable() {

    @Override
    public void run() {

        Looper.prepare();

        FfmpegController ffmpeg = null;

        try {
            ffmpeg = new FfmpegController(context);
        } catch (IOException ioe) {
            Log.e(DEBUG_TAG, "Error loading ffmpeg. " + ioe.getMessage());
        }

        ShellDummy shell = new ShellDummy();
        String mp3BitRate = "192";

        try {
            ffmpeg.extractAudio(in, out, audio, mp3BitRate, shell);
        } catch (IOException e) {
            Log.e(DEBUG_TAG, "IOException running ffmpeg" + e.getMessage());
        } catch (InterruptedException e) {
            Log.e(DEBUG_TAG, "InterruptedException running ffmpeg" + e.getMessage());
        }

        Looper.loop();

    }

}).start();

et pour gérer la sortie de la console:

private class ShellDummy implements ShellCallback {

    @Override
    public void shellOut(String shellLine) {
        if (someCondition) {
            doSomething(shellLine);
        }
        Utils.logger("d", shellLine, DEBUG_TAG);
    }

    @Override
    public void processComplete(int exitValue) {
        if (exitValue == 0) {
            // Audio job OK, do your stuff: 

                            // i.e.             
                            // write id3 tags,
                            // calls the media scanner,
                            // etc.
        }
    }

    @Override
    public void processNotStartedCheck(boolean started) {
        if (!started) {
                            // Audio job error, as above.
        }
    }
}
dentex
la source
Quelle est votre expérience avec guardianproject?
XY
3

Étrange que ce projet n'ait pas été mentionné: AndroidFFmpeg d'Appunite

Il a des instructions pas à pas assez détaillées pour copier / coller sur la ligne de commande, pour les paresseux comme moi))

Mixaz
la source
3

J'ai eu le même problème, j'ai trouvé la plupart des réponses ici datées. J'ai fini par écrire un wrapper sur FFMPEG pour accéder à partir d'Android avec une seule ligne de code.

https://github.com/madhavanmalolan/ffmpegandroidlibrary

Madhavan Malolan
la source
1
Il semble que vous ayez compilé FFmpeg v2.8.4, est-il prévu de mettre à jour FFmpeg? Nous recherchons la solution Android ayant la dernière version (peut être 3.2 ou 3.4) de FFmpeg.
sappu
Oui. J'ai l'intention de le déplacer vers 3.x github.com/madhavanmalolan/ffmpegandroidlibrary/milestone/1 Vous pouvez essayer de modifier le script de construction ici et compiler pour 3.4 github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/…
Madhavan Malolan
Merci @Madhvan. Je construis la bibliothèque ffmpeg sur windows. Vous vous demandez simplement ce que tout doit être changé dans github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/… afin de construire?
2018 à 7h57
1

Tout d'abord, ajoutez la dépendance de la bibliothèque FFmpeg

implementation 'com.writingminds:FFmpegAndroid:0.3.2'

Chargez ensuite en activité

FFmpeg ffmpeg;
    private void trimVideo(ProgressDialog progressDialog) {

    outputAudioMux = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath()
            + "/VidEffectsFilter" + "/" + new SimpleDateFormat("ddMMyyyy_HHmmss").format(new Date())
            + "filter_apply.mp4";

    if (startTrim.equals("")) {
        startTrim = "00:00:00";
    }

    if (endTrim.equals("")) {
        endTrim = timeTrim(player.getDuration());
    }

    String[] cmd = new String[]{"-ss", startTrim + ".00", "-t", endTrim + ".00", "-noaccurate_seek", "-i", videoPath, "-codec", "copy", "-avoid_negative_ts", "1", outputAudioMux};


    execFFmpegBinary1(cmd, progressDialog);
    }



    private void execFFmpegBinary1(final String[] command, ProgressDialog prpg) {

    ProgressDialog progressDialog = prpg;

    try {
        ffmpeg.execute(command, new ExecuteBinaryResponseHandler() {
            @Override
            public void onFailure(String s) {
                progressDialog.dismiss();
                Toast.makeText(PlayerTestActivity.this, "Fail to generate video", Toast.LENGTH_SHORT).show();
                Log.d(TAG, "FAILED with output : " + s);
            }

            @Override
            public void onSuccess(String s) {
                Log.d(TAG, "SUCCESS wgith output : " + s);

//                    pathVideo = outputAudioMux;
                String finalPath = outputAudioMux;
                videoPath = outputAudioMux;
                Toast.makeText(PlayerTestActivity.this, "Storage Path =" + finalPath, Toast.LENGTH_SHORT).show();

                Intent intent = new Intent(PlayerTestActivity.this, ShareVideoActivity.class);
                intent.putExtra("pathGPU", finalPath);
                startActivity(intent);
                finish();
                MediaScannerConnection.scanFile(PlayerTestActivity.this, new String[]{finalPath}, new String[]{"mp4"}, null);

            }

            @Override
            public void onProgress(String s) {
                Log.d(TAG, "Started gcommand : ffmpeg " + command);
                progressDialog.setMessage("Please Wait video triming...");
            }

            @Override
            public void onStart() {
                Log.d(TAG, "Startedf command : ffmpeg " + command);

            }

            @Override
            public void onFinish() {
                Log.d(TAG, "Finished f command : ffmpeg " + command);
                progressDialog.dismiss();
            }
        });
    } catch (FFmpegCommandAlreadyRunningException e) {
        // do nothing for now
    }
}

  private void loadFFMpegBinary() {
    try {
        if (ffmpeg == null) {
            ffmpeg = FFmpeg.getInstance(this);
        }
        ffmpeg.loadBinary(new LoadBinaryResponseHandler() {
            @Override
            public void onFailure() {
                showUnsupportedExceptionDialog();
            }

            @Override
            public void onSuccess() {
                Log.d("dd", "ffmpeg : correct Loaded");
            }
        });
    } catch (FFmpegNotSupportedException e) {
        showUnsupportedExceptionDialog();
    } catch (Exception e) {
        Log.d("dd", "EXception no controlada : " + e);
    }
}

private void showUnsupportedExceptionDialog() {
    new AlertDialog.Builder(this)
            .setIcon(android.R.drawable.ic_dialog_alert)
            .setTitle("Not Supported")
            .setMessage("Device Not Supported")
            .setCancelable(false)
            .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            })
            .create()
            .show();

}

Utilisez également une autre fonctionnalité de FFmpeg

===> merge audio to video
String[] cmd = new String[]{"-i", yourRealPath, "-i", arrayList.get(posmusic).getPath(), "-map", "1:a", "-map", "0:v", "-codec", "copy", "-shortest", outputcrop};


===> Flip vertical :
String[] cm = new String[]{"-i", yourRealPath, "-vf", "vflip", "-codec:v", "libx264", "-preset", "ultrafast", "-codec:a", "copy", outputcrop1};


===> Flip horizontally :  
String[] cm = new String[]{"-i", yourRealPath, "-vf", "hflip", "-codec:v", "libx264", "-preset", "ultrafast", "-codec:a", "copy", outputcrop1};


===> Rotate 90 degrees clockwise:
String[] cm=new String[]{"-i", yourRealPath, "-c", "copy", "-metadata:s:v:0", "rotate=90", outputcrop1};


===> Compress Video
String[] complexCommand = {"-y", "-i", yourRealPath, "-strict", "experimental", "-vcodec", "libx264", "-preset", "ultrafast", "-crf", "24", "-acodec", "aac", "-ar", "22050", "-ac", "2", "-b", "360k", "-s", "1280x720", outputcrop1};


===> Speed up down video
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=2.0*PTS[v];[0:a]atempo=0.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=1.0*PTS[v];[0:a]atempo=1.0[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=0.75*PTS[v];[0:a]atempo=1.5[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};
String[] complexCommand = {"-y", "-i", yourRealPath, "-filter_complex", "[0:v]setpts=0.5*PTS[v];[0:a]atempo=2.0[a]", "-map", "[v]", "-map", "[a]", "-b:v", "2097k", "-r", "60", "-vcodec", "mpeg4", outputcrop1};



===> Add two mp3 files 

StringBuilder sb = new StringBuilder();
sb.append("-i ");
sb.append(textSngname);
sb.append(" -i ");
sb.append(mAudioFilename);
sb.append(" -filter_complex [0:0][1:0]concat=n=2:v=0:a=1[out] -map [out] ");
sb.append(finalfile);
---> ffmpeg.execute(sb.toString().split(" "), new ExecuteBinaryResponseHandler()




===> Add three mp3 files

StringBuilder sb = new StringBuilder();
sb.append("-i ");
sb.append(firstSngname);
sb.append(" -i ");
sb.append(textSngname);
sb.append(" -i ");
sb.append(mAudioFilename);
sb.append(" -filter_complex [0:0][1:0][2:0]concat=n=3:v=0:a=1[out] -map [out] ");
sb.append(finalfile);
---> ffmpeg.execute(sb.toString().split(" "), new ExecuteBinaryResponseHandler()
Jay patoliya
la source