AndroidのFFmpeg


207

AndroidでFFmpegをコンパイルしました(libffmpeg.so)。次に、RockPlayerのようなアプリケーションを構築するか、既存のAndroidマルチメディアフレームワークを使用してFFmpegを呼び出す必要があります。

  1. Android / StageFrightにFFmpegを統合する手順/手順/コード/例はありますか?

  2. このライブラリをマルチメディア再生に使用するにはどうすればよいですか?

  3. 私はすでにオーディオとビデオのトランスポートストリームを持っているという要件があります。それをFFmpegにフィードしてデコード/レンダリングする必要があります。IOMX APIはOMXベースであり、ここでFFmpegをプラグインできないため、Androidでこれを行うにはどうすればよいですか?

  4. また、再生に使用する必要があるFFmpeg APIに関するドキュメントも見つかりませんでした。


7
これは興味深いです。私も
知り

5
どのように.soファイルを取得するためにffmpegをコンパイルしましたか?従った手順を教えてください。私はcygwin-1.7.9とndk r5を使用してWindowsで作業しています。私を助けてください。
Swathi EP 2011

ここでは、Android向けの比較的新しいのFFmpegだ:sourceforge.net/projects/ffmpeg4android
slhck

@slhck上記のリンクからffmpegコードをダウンロードしてコンパイルしようとしましたが、.soファイルを取得できません。それは多くの問題を示しています..
RAJESH

私を助けてください:stackoverflow.com/questions/14157030/…、私はこの関数をどこに含めて実行するかわからない!.....
TharakaNirmana

回答:


109

以下は、ffmpegをAndroidで動作させるために行った手順です。

  1. Android用のffmpegの静的ライブラリーをビルドします。これは、Androidビルドシステムを使用して、olvaffeのffmpeg androidポート(libffmpeg)をビルドすることで実現されました。/ externalの下にソースを配置するだけmakeです。Androidビルドからbionic(libc)とzlib(libz)も抽出する必要があります。ffmpegライブラリはこれらに依存しているためです。
  2. Android NDKを使用して、ffmpeg機能をラップする動的ライブラリを作成します。NDKの操作方法に関するドキュメントはたくさんあります。基本的に、ffmpegから必要な機能をJavaがJNIを介して対話できるライブラリにエクスポートするために、いくつかのC / C ++コードを記述する必要があります。NDKを使用すると、手順1で生成した静的ライブラリに簡単にリンクできます。これと同じような行をAndroid.mkに追加するだけです。LOCAL_STATIC_LIBRARIES := libavcodec libavformat libavutil libc libz

  3. Javaソースからのffmpeg-wrapping動的ライブラリーを使用します。JNIに関するドキュメントは十分ありますが、大丈夫です。

再生にffmpegを使用することに関しては、多くの例があります(ffmpegバイナリ自体が良い例です)。ここに基本的なチュートリアルがあります。最良のドキュメントはヘッダーにあります。

幸運を :)


7
Android用のffmpegを構築するためのこの回答へのリンクはかなりあります。これはまだ最良の解決策ですか?Androidビルドシステムのリンクが壊れています-それは何ですか?NDKでのビルドに役立つツールキットがたくさんあります。しかし、それらはすべて私にとってさまざまなビルドエラーで失敗し、少し古いようです。誰かがビルドされた静的ffmpeg libを投稿できない理由はありますか?
Rob Lourens

7
私自身の質問に答えるために、私はこのレポがffmpegとJNIラッパーを構築するために最も有用であることを発見しました-github.com/andynicholson/android-ffmpeg-x264
Rob Lourens

68

さまざまな理由により、マルチメディアは、効率性を犠牲にすることなく、タスクを達成するという点でかつてないほど簡単になりました。ffmpegは、日々改善するための取り組みです。コーデックとコンテナのさまざまな形式をサポートしています。

このライブラリの使用方法についての質問に答えるなら、ここに書くのはそれほど簡単ではないと思います。しかし、私は以下の方法であなたを導くことができます

1)ソースコードのffmpegディレクトリ内に、output_example.cまたはapi_example.cがあります。ここでは、エンコード/デコードが行われたコードを確認できます。呼び出す必要があるffmpeg内のAPIに関するアイデアが得られます。これが最初のステップです。

2)DolphinプレーヤーはAndroid向けのオープンソースプロジェクトです。現在バグがありますが、開発者は継続的に作業しています。そのプロジェクトでは、調査を続行するために使用できるセットアップ全体が準備できています。これがcode.google.com からのプロジェクトへのリンクか、ターミナルでコマンド「git clone https://code.google.com/p/dolphin-player/」を実行します。PとP86という名前の2つのプロジェクトが表示されます。どちらでも使用できます。

私が提供したい追加のヒントは、ffmpegコードをビルドするときに、build.sh内で、使用するフォーマットのマルチプレクサ/デマルチプレクサ/エンコーダ/デコーダを有効にする必要があることです。そうでない場合、対応するコードはライブラリに含まれません。これに気づくのに時間がかかりました。だからあなたとそれを共有することを考えました。

いくつかの基本: ビデオファイルと言う場合、例:avi、それはオーディオとビデオの両方の組み合わせです

ビデオファイル=ビデオ+オーディオ


ビデオ=コーデック+マクサー+デマルチプレクサ

コーデック=エンコーダー+デコーダー

=> ビデオ=エンコーダー+デコーダー+ Muxer + Demuxer(Mpeg4 + Mpeg4 + avi + avi-aviコンテナーの例)


オーディオ=コーデック+マクサー+デマルチプレクサ

コーデック=エンコーダー+デコーダー

=> オーディオ=エンコーダー+デコーダー+マクサー+デマルチプレクサー(mp2 + mp2 + avi + avi-aviコンテナーの例)


コーデック(名前はen * co * der / * dec * oderの組み合わせから派生)は、フレームのエンコード/デコードに使用されるアルゴリズムを定義するフォーマットの一部にすぎません。AVIはコーデックではなく、Mpeg4のビデオコーデックとmp2のオーディオコーデックを使用するコンテナです。

Muxer / demuxerは、エンコード/デコード中に使用されるファイルからフレームを結合/分離するために使用されます。

したがって、avi形式を使用する場合は、ビデオコンポーネント+オーディオコンポーネントを有効にする必要があります。

例:aviの場合、以下を有効にする必要があります。mpeg4エンコーダー、mpeg4デコーダー、mp2エンコーダー、mp2デコーダー、avi muxer、avi demuxer。

ふwwwwwwwwww ...

プログラムでbuild.shには次のコードを含める必要があります。

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

結局これ以上混乱させないでほしい...

ありがとうございます。サポートが必要な場合はお知らせください。


1
ねえ、私はその情報をありがとうございました。あなたは本当に私を助けてくれました。後で何かが必要になった場合、あなたが私を助けることは可能ですか?ありがとうございました!
アイディッシュ2012

skype / MSNまたは他のチャットプラットフォームを介して追加していただけますか?それについていくつか質問があります、ありがとう。
アイディッシュ2012

2
承知しました..!!しかし、私のオンラインプレゼンスは少し低いです。非常に必要でない限り、スカイプにログインしません。重要なことはメールで送ってください。Eメール:mantykuma@gmail.com
mk ..

13

私が見つけた最も簡単で使いやすい実装は、guardianprojectチームによって作成されていますhttps : //github.com/guardianproject/android-ffmpeg


確かではありませんが、そうだと思います。新しいiOSバージョンでは、これを壊す可能性のあるものは何も頭に浮かびません。私がこれを投稿したとき、まだ10.7または10.6でした
Guy

JNI実装を使用して3gpをオーディオに変換するにはどうすればよいですか
Mr.G

11

Android NDKを使用してX264とFFMPEGを構成および構築するための小さなプロジェクトを実行しました。欠けている主なものは、Java経由でアクセスできる適切なJNIインターフェースですが、それは(比較的)簡単な部分です。JNIインターフェースを自分の用途に適したものにする準備ができたら、それをプッシュします。

olvaffeのビルドシステムに対する利点は、ライブラリをビルドするためにAndroid.mkファイルを必要とせず、通常のmakefileとツールチェーンを使用することです。これにより、FFMPEGまたはX264から新しい変更をプルしたときに作業が停止する可能性が大幅に減少します。

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


ニックは、あなたのプロジェクトは、OS X 10.7 libx264.a(common.o)でコンパイルされていません:関数の中でx264_param_parse': common.c:(.text+0x2864): undefined reference to _DefaultRuneLocale」collect2は:ldは1つの終了ステータスメイク返さ:*** [x264の]エラー1
ユーリーソロビヨフ

9

多くの調査の結果、これは私が見つけたAndroid向けの最新のコンパイル済みライブラリです。

https://github.com/bravobit/FFmpeg-Android

  • 現時点では使用しています FFmpeg release n4.0-39-gda39990
  • FFmpegとFFProbeが含まれています
  • コマンドを起動するためのJavaインターフェースが含まれています
  • FFprobeまたはFFmpegをAPKから削除できます。Wikiを確認してくださいhttps://github.com/bravobit/FFmpeg-Android/wiki

6

私のFFMPEGアプリケーションを作成するために、このプロジェクトを使用しました(https://github.com/hiteshsondhi88/ffmpeg-android-java)ので、何もコンパイルする必要はありません。これは、FFMPEGをAndroidアプリケーションで使用する簡単な方法だと思います。

http://hiteshsondhi88.github.io/ffmpeg-android-java/に関する詳細情報


3
このラッパーは非常に非常に非常に非常に非常に遅いです。ビデオへの200の画像は50-60秒かかります。。。しかし、通常、ffmpegはそのタスクを4〜5秒で処理します。
Arsen Sench、2016年

このプロジェクトはもう機能していません。他にリソースはありますか?
Ajeet 2017

@ArsenSench他に解決策はありますか?
Akash Dubey 2017年

3

Androidの実装に関する他の多くのFFmpegに触発されました(主にguadianproject)に、解決策を見つけました(Lameもサポートしています)。

(lameおよびFFmpeg:https : //github.com/intervigilium/liblameおよびhttp://bambuser.com/opensource

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

そして、コンソール出力を処理するには:

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.
        }
    }
}

guardianprojectでの経験を教えてください。
XY

3

このプロジェクトが言及されていないのは奇妙です:AppuniteのAndroidFFmpeg

私のような怠惰な人々のために、コマンドラインにコピー/ペーストするための非常に詳細なステップバイステップの説明があります))


3

私は同じ問題を抱えていましたが、ほとんどの答えは古くなっています。FFMPEGにラッパーを作成して、Androidから1行のコードでアクセスしました。

https://github.com/madhavanmalolan/ffmpegandroidlibrary


1
FFmpeg v2.8.4をコンパイルしたようですが、FFmpegをアップグレードする計画はありますか?私たちは、FFmpegの最新バージョン(多分3.2または3.4)を持つAndroidソリューションを探しています。
sappu 2018年

はい。私はそれを3.x github.com/madhavanmalolan/ffmpegandroidlibrary/milestone/1に移動するつもりです。 ビルドスクリプトをここで変更して、3.4github.com/madhavanmalolan/ffmpegandroidlibrary/wiki/…
Madhavan Malolan

@Madhvanに感謝します。Windowsでffmpegライブラリを構築しています。ビルドするためにgithub.com/madhavanmalolan/ffmpegandroidlibrary/wiki/…で何を変更する必要があるのか​​疑問に思いますか?
sappu 2018年

1

まず、FFmpegライブラリの依存関係を追加します

implementation 'com.writingminds:FFmpegAndroid:0.3.2'

次に、アクティビティを読み込みます

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

}

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()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.