Android上的FFmpeg

Android上的FFmpeg,android,ffmpeg,stagefright,android-ffmpeg,Android,Ffmpeg,Stagefright,Android Ffmpeg,我已经在Android上编译了FFmpeg.libffmpeg.so。现在我必须构建一个像RockPlayer这样的应用程序,或者使用现有的Android多媒体框架来调用FFmpeg 您是否有在Android/StageFright上集成FFmpeg的步骤/过程/代码/示例 你能告诉我如何使用这个库进行多媒体播放吗 我有一个要求,即我已经有音频和视频传输流,我需要将其馈送到FFmpeg并对其进行解码/渲染。既然IOMXAPI是基于OMX的,并且不能在这里插入FFmpeg,我怎么能在Android

我已经在Android上编译了FFmpeg.libffmpeg.so。现在我必须构建一个像RockPlayer这样的应用程序,或者使用现有的Android多媒体框架来调用FFmpeg

您是否有在Android/StageFright上集成FFmpeg的步骤/过程/代码/示例

你能告诉我如何使用这个库进行多媒体播放吗

我有一个要求,即我已经有音频和视频传输流,我需要将其馈送到FFmpeg并对其进行解码/渲染。既然IOMXAPI是基于OMX的,并且不能在这里插入FFmpeg,我怎么能在Android上做到这一点呢

此外,我也找不到需要用于播放的FFmpeg API文档


以下是我在让ffmpeg在Android上工作时所经历的步骤:

为Android构建ffmpeg的静态库。这是通过使用构建olvaffe的ffmpeg android端口实现的。只需将源置于/外部,然后离开。您还需要从Android构建中提取bioniclibc和zliblibz,因为ffmpeg库依赖于它们。 使用Android创建动态库包装ffmpeg功能。有很多关于如何使用NDK的文档。基本上,您需要编写一些C/C++代码,将您需要的功能从ffmpeg导出到java可以通过JNI进行交互的库中。NDK允许您轻松链接步骤1中生成的静态库,只需在Android.mk中添加一行类似的内容:LOCAL_static_libraries:=libavcodec libavformat libavutil libc libz

使用来自java源代码的ffmpeg包装动态库。有足够的关于JNI的文档,你应该会没事的

关于使用ffmpeg进行播放,有很多例子ffmpeg二进制文件本身就是一个很好的例子,这是一个基本教程。最好的文档可以在标题中找到


祝你好运:

以下是我让ffmpeg在Android上运行的步骤:

为Android构建ffmpeg的静态库。这是通过使用构建olvaffe的ffmpeg android端口实现的。只需将源置于/外部,然后离开。您还需要从Android构建中提取bioniclibc和zliblibz,因为ffmpeg库依赖于它们。 使用Android创建动态库包装ffmpeg功能。有很多关于如何使用NDK的文档。基本上,您需要编写一些C/C++代码,将您需要的功能从ffmpeg导出到java可以通过JNI进行交互的库中。NDK允许您轻松链接步骤1中生成的静态库,只需在Android.mk中添加一行类似的内容:LOCAL_static_libraries:=libavcodec libavformat libavutil libc libz

使用来自java源代码的ffmpeg包装动态库。有足够的关于JNI的文档,你应该会没事的

关于使用ffmpeg进行播放,有很多例子ffmpeg二进制文件本身就是一个很好的例子,这是一个基本教程。最好的文档可以在标题中找到


祝你好运:

我做了一个小项目,使用Android NDK配置和构建X264和FFMPEG。缺少的主要东西是一个像样的JNI接口,使其能够通过Java访问,但这是相对容易的部分。当我开始着手使JNI接口适合我自己的使用时,我会把它推进去

与olvaffe的构建系统相比,它的优点是不需要Android.mk文件来构建库,它只使用常规的makefile和工具链。这使得从FFMPEG或X264中提取新更改时,停止工作的可能性大大降低


我做了一个小项目,使用Android NDK配置和构建X264和FFMPEG。缺少的主要东西是一个像样的JNI接口,使其能够通过Java访问,但这是相对容易的部分。当我开始着手使JNI接口适合我自己的使用时,我会把它推进去

与olvaffe的构建系统相比,它的优点是不需要Android.mk文件来构建库,它只使用常规的makefile和工具链。这使得从FFMPEG或X264中提取新更改时,停止工作的可能性大大降低


由于各种原因,多媒体在不影响效率的情况下完成任务过去是,现在也从来不是一件容易的事。ffmpeg是一项日臻完善的工作。它支持不同格式的编解码器和容器

现在,为了回答如何使用这个库的问题,我想说,在这里编写它并不是那么简单。但我可以用以下方法指导你

1在源代码的ffmpeg目录中,您有output_example.c或api_example.c。在这里,您可以看到编码/解码完成的代码。您将了解应该调用ffmpeg中的API。这将是你的第一步

Dolphin player是Andro的一个开源项目 目前它有bug,但开发人员仍在继续工作。在该项目中,您已经准备好了整个设置,可以使用它继续您的调查。这里是指向from code.google.com或在终端中运行git clone命令的链接。您可以看到两个名为P和P86的项目。你可以使用它们中的任何一个

我想提供的额外提示是,当您构建ffmpeg代码时,在build.sh中,您需要启用您想要使用的格式的muxer/demuxer/encoder/decoders。否则相应的代码将不包含在库中。我花了很多时间才意识到这一点。所以我想和你分享一下

一些基本知识: 当我们说一个视频文件,例如:avi,它是音频和视频的组合

视频文件=视频+音频

视频=编解码器+多路复用器+解复用器

编解码器=编码器+解码器

=>视频=编码器+解码器+多路复用器+解复用器Mpeg4+Mpeg4+avi+avi-avi容器示例

音频=编解码器+多路复用器+解复用器

编解码器=编码器+解码器

=>音频=编码器+解码器+多路复用器+解复用器mp2+mp2+avi+avi-avi容器示例

codename是由en*co*der/*dec*的组合派生而来的。coder只是格式的一部分,定义了用于编码/解码帧的算法。AVI不是一个编解码器,它是一个使用Mpeg4视频编解码器和mp2音频编解码器的容器

Muxer/demuxer用于将帧与编码/解码时使用的文件合并/分离

所以,如果你想使用avi格式,你需要启用视频组件+音频组件

例如,对于avi,您需要启用以下功能。 mpeg4编码器,mpeg4解码器,mp2编码器,mp2解码器,avi多路复用器,avi解复用器

PHEWWWWWWWW

以编程方式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)
希望在这一切之后我不会让你更困惑


谢谢,如果需要任何帮助,请告诉我。

由于各种原因,多媒体在不影响效率的情况下完成任务从来都不是一件容易的事。ffmpeg是一项日臻完善的工作。它支持不同格式的编解码器和容器

现在,为了回答如何使用这个库的问题,我想说,在这里编写它并不是那么简单。但我可以用以下方法指导你

1在源代码的ffmpeg目录中,您有output_example.c或api_example.c。在这里,您可以看到编码/解码完成的代码。您将了解应该调用ffmpeg中的API。这将是你的第一步

Dolphin player是Android的开源项目。目前它有bug,但开发人员仍在继续工作。在该项目中,您已经准备好了整个设置,可以使用它继续您的调查。这里是指向from code.google.com或在终端中运行git clone命令的链接。您可以看到两个名为P和P86的项目。你可以使用它们中的任何一个

我想提供的额外提示是,当您构建ffmpeg代码时,在build.sh中,您需要启用您想要使用的格式的muxer/demuxer/encoder/decoders。否则相应的代码将不包含在库中。我花了很多时间才意识到这一点。所以我想和你分享一下

一些基本知识: 当我们说一个视频文件,例如:avi,它是音频和视频的组合

视频文件=视频+音频

视频=编解码器+多路复用器+解复用器

编解码器=编码器+解码器

=>视频=编码器+解码器+多路复用器+解复用器Mpeg4+Mpeg4+avi+avi-avi容器示例

音频=编解码器+多路复用器+解复用器

编解码器=编码器+解码器

=>音频=编码器+解码器+多路复用器+解复用器mp2+mp2+avi+avi-avi容器示例

codename是由en*co*der/*dec*的组合派生而来的。coder只是格式的一部分,定义了用于编码/解码帧的算法。AVI不是一个编解码器,它是一个使用Mpeg4视频编解码器和mp2音频编解码器的容器

Muxer/demuxer用于将帧与编码/解码时使用的文件合并/分离

所以,如果你想使用avi格式,你需要启用视频组件+音频组件

例如,对于avi,您需要启用以下功能。 mpeg4编码器,mpeg4解码器,mp2编码器,mp2解码器,avi多路复用器,avi解复用器

PHEWWWWWWWW

以编程方式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)
希望在这一切之后我不会让你更困惑


谢谢,如果需要任何帮助,请告诉我。

我发现的最易于构建、易于使用的实现是由Guardian项目团队完成的:

最易于构建,我发现的易于使用的实现是由Guardian项目团队制作的:

受Android上许多其他FFmpeg实现的启发,主要是,我发现了一个支持Lame的解决方案

lame和FFmpeg:以及

要调用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.
        }
    }
}

受Android上许多其他FFmpeg实现的启发,我发现了一个支持Lame的解决方案

lame和FFmpeg:以及

要调用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.
        }
    }
}

奇怪的是,这个项目没有被提及:


对于像我这样懒惰的人来说,它有相当详细的复制/粘贴到命令行的分步说明,奇怪的是,这个项目没有被提及:


它有非常详细的一步一步的指令来复制/粘贴到命令行,对于像我这样懒惰的人来说

为了制作我的FFMPEG应用程序,我使用了这个项目,所以我不需要编译任何东西。我认为这是在我们的Android应用程序中使用FFMPEG的简单方法


关于

的更多信息为了制作我的FFMPEG应用程序,我使用了这个项目,所以我不需要编译任何东西。我认为这是在我们的Android应用程序中使用FFMPEG的简单方法


关于

的更多信息我也有同样的问题,我发现这里的大多数答案都过时了。 最后,我在FFMPEG上编写了一个包装器,只需一行代码即可从Android访问


我也有同样的问题,我发现这里的大多数答案都过时了。 最后,我在FFMPEG上编写了一个包装器,只需一行代码即可从Android访问


经过大量研究,现在这是我发现的最新的Android编译库:

目前正在使用FFmpeg版本n4.0-39-GDA3990 包括FFmpeg和FFProbe 包含用于启动命令的Java接口 可以从APK中删除FFprobe或FFmpeg,请查看wiki
经过大量研究,现在这是我发现的最新的Android编译库:

目前正在使用FFmpeg版本n4.0-39-GDA3990 包括FFmpeg和FFProbe 包含用于启动命令的Java接口 可以从APK中删除FFprobe或FFmpeg,请查看wiki
首先,添加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();

}
    public String timeTrim(long milliseconds) {
        String finalTimerString = "";
        String minutString = "";
        String secondsString = "";

        // Convert total duration into time
        int hours = (int) (milliseconds / (1000 * 60 * 60));
        int minutes = (int) (milliseconds % (1000 * 60 * 60)) / (1000 * 60);
        int seconds = (int) ((milliseconds % (1000 * 60 * 60)) % (1000 * 60) / 1000);
        // Add hours if there

        if (hours < 10) {
            finalTimerString = "0" + hours + ":";
        } else {
            finalTimerString = hours + ":";
        }


        if (minutes < 10) {
            minutString = "0" + minutes;
        } else {
            minutString = "" + minutes;
        }

        // Prepending 0 to seconds if it is one digit
        if (seconds < 10) {
            secondsString = "0" + seconds;
        } else {
            secondsString = "" + seconds;
        }

        finalTimerString = finalTimerString + minutString + ":" + secondsString;

        // return timer string
        return finalTimerString;
    }

首先,添加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();

}
    public String timeTrim(long milliseconds) {
        String finalTimerString = "";
        String minutString = "";
        String secondsString = "";

        // Convert total duration into time
        int hours = (int) (milliseconds / (1000 * 60 * 60));
        int minutes = (int) (milliseconds % (1000 * 60 * 60)) / (1000 * 60);
        int seconds = (int) ((milliseconds % (1000 * 60 * 60)) % (1000 * 60) / 1000);
        // Add hours if there

        if (hours < 10) {
            finalTimerString = "0" + hours + ":";
        } else {
            finalTimerString = hours + ":";
        }


        if (minutes < 10) {
            minutString = "0" + minutes;
        } else {
            minutString = "" + minutes;
        }

        // Prepending 0 to seconds if it is one digit
        if (seconds < 10) {
            secondsString = "0" + seconds;
        } else {
            secondsString = "" + seconds;
        }

        finalTimerString = finalTimerString + minutString + ":" + secondsString;

        // return timer string
        return finalTimerString;
    }


这很有趣,我很好奇你是如何编译ffmpeg来获取.so文件的?你能分享一下你遵循的步骤吗。我正在使用cygwin-1.7.9和ndk r5在windows上工作。请帮助我。这里有一个相对较新的适用于Android的FFmpeg:@slhck我已经从上面的链接下载了FFmpeg代码,并尝试编译它,但我无法获得.so文件。它显示了很多问题。请帮助我:,我不知道在哪里包含此函数并运行!。。。。。这很有趣,我很好奇你是如何编译ffmpeg来获取.so文件的?你能分享一下你遵循的步骤吗。我正在使用cygwin-1.7.9和ndk r5在windows上工作。请帮助我。这里有一个相对较新的适用于Android的FFmpeg:@slhck我已经从上面的链接下载了FFmpeg代码,并尝试编译它,但我无法获得.so文件。它显示了很多问题。请帮助我:,我不知道在哪里包含此函数并运行!。。。。。Nick,您的项目未在OS X 10.7 libx264.acommon.o:函数x264_param_parse:common.c:.text+0x2864:对_DefaultRuneLocale'collect2:ld的未定义引用返回了1个退出状态make:**[x264]错误1Nick,您的项目未在OS X 10.7 libx264.acommon.o:函数x264_param_parse:common.c:.text+0x2864:对_DefaultRuneLocale'collect2:ld的未定义引用返回1退出状态make:**[x264]错误1构建Android ffmpeg时,有许多链接指向此答案。这仍然是最好的解决方案吗?Android构建系统链接断开了-这应该是什么?有很多工具包可以帮助NDK的构建。然而,对于我来说,它们都失败了,出现了各种各样的构建错误,而且看起来有点陈旧。有什么理由不能发布一个构建的静态ffmpeg库吗?为了回答我自己的问题,我发现这个repo对于构建ffmpeg和JNI包装器是最有用的——有很多链接指向这个为Android构建ffmpeg的答案。这仍然是最好的解决方案吗?Android构建系统链接断开了-这应该是什么?有很多工具包可以帮助NDK的构建。然而,对于我来说,它们都失败了,出现了各种各样的构建错误,而且看起来有点陈旧。有什么理由不能发布一个构建的静态ffmpeg库吗?回答我自己的问题,我发现这个repo对于构建ffmpeg和JNI包装最有用-嘿,我非常感谢你提供的信息,你真的帮了我很多忙,如果我以后需要的话,你能帮我吗?非常感谢。我可以通过skype/MSN或任何其他聊天平台添加您吗?关于这件事我有几个问题,谢谢。当然可以。。!!但是我的在线人数有点少。。除非非常需要,否则我不会登录skype。任何重要的事情你都可以给我发邮件。电邮:mantykuma@gmail.comHey,我非常感谢你提供的信息,你真的帮助了我

非常感谢,如果我以后需要的话,你能帮我吗?非常感谢。我可以通过skype/MSN或任何其他聊天平台添加您吗?关于这件事我有几个问题,谢谢。当然可以。。!!但是我的在线人数有点少。。除非非常需要,否则我不会登录skype。任何重要的事情你都可以给我发邮件。电邮:mantykuma@gmail.comNot当然,我猜是的,在新的iOS版本中没有任何东西会打破这一点。当我发布这篇文章时,我仍然有10.7或10.6你知道吗,如何使用JNI实现将3gp转换为音频不确定,我猜是的,在新的iOS版本中没有任何东西会打破这一点。当我发布这篇文章时,我还有10.7或10.6你知道吗,我如何使用JNI实现将3gp转换为音频你对guardianproject有什么经验?你对guardianproject有什么经验?这个包装器非常慢。200个图像到视频需要50-60秒。但通常ffmpeg会在4-5秒内完成这项任务。这个项目不再工作了。你有其他资源吗?@Arsench你有其他解决方案吗?你可以试试这个:这个包装器非常慢。200个图像到视频需要50-60秒。但通常ffmpeg会在4-5秒内完成这项任务。这个项目不再工作了。您有其他资源吗?@Arsench您有其他解决方案吗?您可以尝试一下:似乎您已经编译了FFmpeg v2.8.4,是否有升级FFmpeg的计划?我们正在寻找android解决方案,其最新版本可能是FFmpeg.Yes的3.2或3.4版本。我确实打算将其移动到3.x,您可以尝试在这里修改构建脚本并编译为3.4版本,谢谢@Madhvan。我正在windows上构建ffmpeg库。只是想知道为了构建,需要更改哪些内容?似乎您已经编译了FFmpeg v2.8.4,是否有升级FFmpeg的计划?我们正在寻找android解决方案,其最新版本可能是FFmpeg.Yes的3.2或3.4版本。我确实打算将其移动到3.x,您可以尝试在这里修改构建脚本并编译为3.4版本,谢谢@Madhvan。我正在windows上构建ffmpeg库。只是想知道为了构建,需要改变什么?我使用了这个解决方案,它的工作非常完美,但视频质量太差,只减少了3MB。还有其他解决方案吗?您可以使用1-vcodec mpeg4,而不是==>-vcodec libx264,使用比默认2-b:v 200k 3更高的比特率,或者从1-31中选择-qscale:v值,其中较低的值会导致更高的比特率,并且因此通常更好的质量我使用了这个解决方案,它的工作非常完美,但视频质量太差,只减少了3 mb。还有其他解决方案吗?您可以使用1-vcodec mpeg4,而不是==>-vcodec libx264,使用比默认2-b:v 200k 3更高的比特率,或者从1-31中选择-qscale:v值,其中较低的值会导致更高的比特率,并且因此通常质量更好