FFmpeg auf Android

207

Ich habe FFmpeg auf Android kompiliert (libffmpeg.so). Jetzt muss ich entweder eine Anwendung wie RockPlayer erstellen oder ein vorhandenes Android-Multimedia-Framework verwenden, um FFmpeg aufzurufen.

  1. Haben Sie Schritte / Prozeduren / Code / Beispiele zur Integration von FFmpeg in Android / StageFright?

  2. Können Sie mir bitte eine Anleitung geben, wie ich diese Bibliothek für die Multimedia-Wiedergabe verwenden kann?

  3. Ich habe eine Anforderung, bei der ich bereits Audio- und Videotransport-Streams habe, die ich an FFmpeg weiterleiten und dekodieren / rendern muss. Wie kann ich dies auf Android tun, da IOMX-APIs OMX-basiert sind und FFmpeg hier nicht einstecken können?

  4. Außerdem konnte ich keine Dokumentation zu den FFmpeg-APIs finden, die für die Wiedergabe verwendet werden müssen.

Jag
quelle
6
das ist interessant, ich bin auch neugierig
Axarydax
5
Wie haben Sie ffmpeg kompiliert, um .so-Dateien zu erhalten? Können Sie uns bitte die Schritte mitteilen, die Sie befolgt haben? Ich arbeite an Windows mit cygwin-1.7.9 und ndk r5. Bitte hilf mir.
Swathi EP
Hier ist ein relativ neues FFmpeg für Android: sourceforge.net/projects/ffmpeg4android
slhck
@slhck Ich habe den ffmpeg-Code über den obigen Link heruntergeladen und versucht, ihn zu kompilieren, aber ich kann die .so-Dateien nicht abrufen. es zeigt viele Probleme ..
RAJESH
Bitte helfen Sie mir bei: stackoverflow.com/questions/14157030/… , ich weiß nicht, wo ich diese Funktion
einbinden

Antworten:

109

Hier sind die Schritte, die ich durchlaufen habe, um ffmpeg für Android zum Laufen zu bringen:

  1. Erstellen Sie statische Bibliotheken von ffmpeg für Android. Dies wurde erreicht, indem der ffmpeg-Android-Port ( libffmpeg ) von olvaffe mit dem Android Build System erstellt wurde . Platzieren Sie die Quellen einfach unter / extern und makeweg. Sie müssen auch bionic (libc) und zlib (libz) aus dem Android-Build extrahieren, da ffmpeg-Bibliotheken davon abhängen.
  2. Erstellen Sie mit dem Android NDK eine dynamische Bibliothek, die die ffmpeg-Funktionalität einschließt . Es gibt eine Menge Dokumentation darüber, wie man mit dem NDK arbeitet. Grundsätzlich müssen Sie C / C ++ - Code schreiben, um die benötigten Funktionen aus ffmpeg in eine Bibliothek zu exportieren, mit der Java über JNI interagieren kann. Mit dem NDK können Sie problemlos Verknüpfungen zu den statischen Bibliotheken herstellen, die Sie in Schritt 1 generiert haben. Fügen Sie einfach eine ähnliche Zeile zu Android.mk hinzu:LOCAL_STATIC_LIBRARIES := libavcodec libavformat libavutil libc libz

  3. Verwenden Sie die dynamische Bibliothek ffmpeg-wrapping aus Ihren Java-Quellen. Es gibt genug Dokumentation zu JNI da draußen, es sollte dir gut gehen.

In Bezug auf die Verwendung von ffmpeg für die Wiedergabe gibt es viele Beispiele (die ffmpeg-Binärdatei selbst ist ein gutes Beispiel). Hier ist ein grundlegendes Tutorial. Die beste Dokumentation finden Sie in den Headern.

Viel Glück :)

yonilevy
quelle
7
Es gibt einige Links zu dieser Antwort, um ffmpeg für Android zu erstellen. Ist das immer noch die beste Lösung? Die Verbindung zum Android Build System ist unterbrochen - was soll das sein? Es gibt eine Reihe von Toolkits, die beim Erstellen mit dem NDK helfen. Allerdings scheitern alle mit verschiedenen Build-Fehlern für mich und scheinen ein wenig alt zu sein. Gibt es einen Grund, warum jemand nicht einfach eine erstellte statische ffmpeg-Bibliothek veröffentlichen kann?
Rob Lourens
7
Um meine eigene Frage zu beantworten, fand ich dieses Repo am nützlichsten, um ffmpeg- und JNI-Wrapper zu erstellen - github.com/andynicholson/android-ffmpeg-x264
Rob Lourens
67

Aus verschiedenen Gründen war und ist Multimedia im Hinblick auf die Erreichung der Aufgabe ohne Kompromisse bei der Effizienz nie einfach. ffmpeg ist eine Anstrengung, es Tag für Tag zu verbessern. Es unterstützt verschiedene Formate von Codecs und Containern.

Um nun die Frage zu beantworten, wie diese Bibliothek verwendet werden soll , würde ich sagen, dass es nicht so einfach ist, sie hier zu schreiben. Aber ich kann Sie auf folgende Weise führen .

1) Im ffmpeg-Verzeichnis des Quellcodes haben Sie output_example.c oder api_example.c . Hier sehen Sie den Code, in dem die Codierung / Decodierung erfolgt. Sie erhalten eine Vorstellung davon, welche APIs in ffmpeg Sie aufrufen sollten. Dies wäre Ihr erster Schritt.

2) Dolphin Player ist ein Open Source Projekt für Android. Derzeit gibt es Fehler, aber die Entwickler arbeiten kontinuierlich. In diesem Projekt haben Sie das gesamte Setup bereit, mit dem Sie Ihre Untersuchung fortsetzen können. Hier ist ein Link zum Projekt von code.google.com oder führen Sie den Befehl " git clone https://code.google.com/p/dolphin-player/ " in einem Terminal aus. Sie können zwei Projekte mit den Namen P und P86 sehen. Sie können beide verwenden.

Ein zusätzlicher Tipp, den ich anbieten möchte, ist, dass Sie beim Erstellen des ffmpeg-Codes in build.sh die Muxer / Demuxer / Encoder / Decoder der Formate aktivieren müssen, die Sie verwenden möchten. Andernfalls wird der entsprechende Code nicht in die Bibliotheken aufgenommen. Ich habe viel Zeit gebraucht, um das zu realisieren. Also dachte ich daran, es mit dir zu teilen.

Einige Grundlagen: Wenn wir eine Videodatei sagen, z. B. avi, ist dies eine Kombination aus Audio und Video

Videodatei = Video + Audio


Video = Codec + Muxer + Demuxer

Codec = Encoder + Decoder

=> Video = Encoder + Decoder + Muxer + Demuxer (Mpeg4 + Mpeg4 + avi + avi - Beispiel für avi container)


Audio = Codec + Muxer + Demuxer

Codec = Encoder + Decoder

=> Audio = Encoder + Decoder + Muxer + Demuxer (mp2 + mp2 + avi + avi - Beispiel für avi container)


Codec (Name leitet sich von einer Kombination aus en * co * der / * dec * oder ab) ist nur ein Teil des Formats, das die Algorithmen definiert, die zum Codieren / Decodieren eines Frames verwendet werden. AVI ist kein Codec, sondern ein Container, der den Video-Codec von Mpeg4 und den Audio-Codec von mp2 verwendet.

Muxer / Demuxer wird verwendet, um die Frames von einer Datei zu kombinieren / zu trennen, die beim Codieren / Decodieren verwendet wird.

Wenn Sie also das AVI-Format verwenden möchten, müssen Sie Videokomponenten + Audiokomponenten aktivieren.

Beispiel: Für avi müssen Sie Folgendes aktivieren. mpeg4 Encoder, mpeg4 Decoder, mp2 Encoder, mp2 Decoder, AVI Muxer, AVI Demuxer.

phewwwwwww ...

Programmatisch sollte build.sh den folgenden Code enthalten:

--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)

Hoffe, ich habe dich nach all dem nicht mehr verwirrt ...

Vielen Dank. Wenn Sie Hilfe benötigen, lassen Sie es mich bitte wissen.

mk ..
quelle
1
Hey, ich möchte mich sehr für diese Informationen bedanken. Du hast mir wirklich sehr geholfen. Kannst du mir helfen, wenn ich später welche brauche? Danke dir!
idish
Kann ich Sie bitte über Skype / MSN oder eine andere Chat-Plattform hinzufügen? Ich habe ein paar Fragen dazu, danke.
idish
2
Sicher..!! Aber meine Online-Präsenz ist etwas gering. Sofern dies nicht unbedingt erforderlich ist, melde ich mich nicht bei Skype an. Sie können mich für alle wichtigen Dinge mailen. E-Mail: [email protected]
mk ..
13

Die einfachste und benutzerfreundlichste Implementierung, die ich gefunden habe, wurde vom Team von guardianproject erstellt: https://github.com/guardianproject/android-ffmpeg

Kerl
quelle
Ich bin mir nicht sicher, ob dies der Fall ist. In der neuen iOS-Version fällt mir nichts ein, was dies beeinträchtigen könnte. Als ich dies gepostet habe, hatte ich noch 10.7 oder 10.6
Guy
do u wissen, wie ich , um Audio konvertieren 3gp können, JNI Implementierung mit
Mr.G
11

Ich habe ein kleines Projekt durchgeführt, um X264 und FFMPEG mit dem Android NDK zu konfigurieren und zu erstellen. Die Hauptsache, die fehlt, ist eine anständige JNI-Schnittstelle, um sie über Java zugänglich zu machen, aber das ist der einfache Teil (relativ). Wenn ich dazu komme, die JNI-Schnittstelle für meine eigenen Zwecke zu nutzen, werde ich das weiter vorantreiben.

Der Vorteil gegenüber dem Build-System von olvaffe besteht darin, dass zum Erstellen der Bibliotheken keine Android.mk-Dateien erforderlich sind, sondern lediglich die regulären Makefiles und die Toolchain verwendet werden. Dies macht es viel weniger wahrscheinlich, dass Sie nicht mehr funktionieren, wenn Sie neue Änderungen von FFMPEG oder X264 abrufen.

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

Nick
quelle
Nick, dein Projekt wird unter OS X 10.7 libil264.a (common.o) nicht kompiliert: In der Funktion x264_param_parse': common.c:(.text+0x2864): undefined reference to _DefaultRuneLocale 'collect2: ld hat 1 Exit-Status zurückgegeben: *** [x264] Fehler 1
Yuriy Solovyov
6

Für meine FFMPEG-Anwendung habe ich dieses Projekt verwendet ( https://github.com/hiteshsondhi88/ffmpeg-android-java) zu erstellen, habe ), sodass ich nichts kompilieren muss. Ich denke, es ist die einfache Möglichkeit, FFMPEG in unseren Android-Anwendungen zu verwenden.

Weitere Informationen unter http://hiteshsondhi88.github.io/ffmpeg-android-java/

jmartinalonso
quelle
3
Dieser Wrapper ist sehr sehr sehr sehr sehr langsam. 200 Bilder für Videos dauern 50-60 Sekunden. . . Normalerweise erledigt ffmpeg diese Aufgabe in 4-5 Sekunden.
Arsen Sench
Dieses Projekt funktioniert nicht mehr. Haben Sie noch andere Ressourcen?
Ajeet
@ArsenSench hast du eine andere Lösung?
Akash Dubey
3

Inspiriert von vielen anderen FFmpeg-Implementierungen für Android (hauptsächlich dem Guadian-Projekt ), fand ich eine Lösung (auch mit Lame-Unterstützung).

(lahm und FFmpeg: https://github.com/intervigilium/liblame und http://bambuser.com/opensource )

FFmpeg aufrufen:

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();

und um die Konsolenausgabe zu handhaben:

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
quelle
Was ist Ihre Erfahrung mit Guardianprojekt?
XY
3

Seltsam, dass dieses Projekt nicht erwähnt wurde: AndroidFFmpeg von Appunite

Es enthält ziemlich detaillierte Schritt-für-Schritt-Anweisungen zum Kopieren / Einfügen in die Befehlszeile, für faule Leute wie mich))

Mixaz
quelle
3

Ich hatte das gleiche Problem, ich fand die meisten Antworten hier veraltet. Am Ende habe ich einen Wrapper auf FFMPEG geschrieben, um von Android mit einer einzigen Codezeile darauf zuzugreifen.

https://github.com/madhavanmalolan/ffmpegandroidlibrary

Madhavan Malolan
quelle
1
Anscheinend haben Sie FFmpeg v2.8.4 kompiliert. Gibt es Pläne, FFmpeg zu aktualisieren? Wir suchen nach der Android-Lösung mit der neuesten (möglicherweise 3.2 oder 3.4) Version von FFmpeg.
Sappu
Ja. Ich will es 3.x bewegen github.com/madhavanmalolan/ffmpegandroidlibrary/milestone/1 können Sie versuchen , den Build - Skript hier zu modifizieren und kompilieren 3,4 github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/...
Madhavan Malolan
Danke @Madhvan. Ich baue eine ffmpeg-Bibliothek unter Windows. Sie fragen sich nur, was in github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/… geändert werden muss, um etwas zu erstellen?
Sappu
0

Fügen Sie zunächst die Abhängigkeit der FFmpeg-Bibliothek hinzu

implementation 'com.writingminds:FFmpegAndroid:0.3.2'

Laden Sie dann die Aktivität ein

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();

}

Verwenden Sie auch eine andere Funktion von 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
quelle