如何在Android中以程序化的方式执行命令行FFmpeg命令?

5
我已经成功使用bambuser为Android构建了ffmpeg。现在我需要构建一个示例转换应用程序,例如将mp4转换为3gp。我知道有命令行命令ffmpeg -i video_origine.avi video_finale.mpg,但我不知道如何以编程方式执行这些命令。我有示例代码,例如:
jint Java_com_example_ndklearning1_MainActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename)
{
    av_register_all();

    AVFormatContext *pFormatCtx;
    const jbyte *str;
    str = (*env)->GetStringUTFChars(env, filename, NULL);

    if(av_open_input_file(&pFormatCtx, str, NULL, 0, NULL)!=0)
    {
        LOGE("Can't open file '%s'\n", str);
        return 1;
    }
    else
    {
        LOGI("File was opened\n");
        LOGI("File '%s', Codec %s",
            pFormatCtx->filename,
            pFormatCtx->iformat->name
        );

    }
    return 0;
}

这段代码打开一个文件并提取编解码器信息。我想要的是将打开的文件转换为所需格式。非常感谢任何形式的帮助,例如代码片段或需要遵循的步骤。
ffmpeg API能够满足我的需求吗?如果已经有现成的API可用,那将更加有帮助。
1个回答

5

最近我遇到了类似的问题。我的解决方案是在Java程序中模拟命令行。

首先,我添加了一个函数到文件“ffmpeg.c”中:

int cmd_simulation(int argc, const char** argv)
{
OptionsContext o = { 0 };
// int64_t ti;

reset_options(&o, 0);

av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);

if(argc>1 && !strcmp(argv[1], "-d")){
    run_as_daemon=1;
    av_log_set_callback(log_callback_null);
    argc--;
    argv++;
}

avcodec_register_all();

avfilter_register_all();
av_register_all();
avformat_network_init();

//show_banner(argc, argv, options);

term_init();

parse_cpuflags(argc, argv, options);

/* parse options */
parse_options(&o, argc, argv, options, opt_output_file);

if (nb_output_files <= 0 && nb_input_files == 0) {
    show_usage();
    av_log(NULL, AV_LOG_WARNING, "Use -h to get full help or, even better, run 'man %s'\n", program_name);
    exit_program(1);
}


if (nb_output_files <= 0) {
    av_log(NULL, AV_LOG_FATAL, "At least one output file must be specified\n");
    exit_program(1);
}

if (transcode() < 0)
    exit_program(1);

//exit_program(0);
return 7;
}

实际上,这个函数只是主函数的复制,并做了一点修改。

然后创建一个本地函数:

extern const char* cmd_simulation(int, const char**);

JNIEXPORT int JNICALL Java_com_test_videowatermark_VideoUtil_test(JNIEnv * env, jobject object, jobjectArray strArray);



JNIEXPORT int JNICALL Java_com_test_videowatermark_VideoUtil_test(JNIEnv * env, jobject object, jobjectArray strArray)
{
    int arrayLength = (*env)->GetArrayLength(env, strArray);
    const char* args[arrayLength];

    int i;
    for(i = 0; i < arrayLength; i++){
        jstring jstr = (jstring)((*env)->GetObjectArrayElement(env, strArray, i));
        args[i] = (*env)->GetStringUTFChars(env, jstr, 0);
        //strcpy(args[i], arg);
        //env->ReleaseStringUTFChars(jstr, arg);
    }


    const char** argv = args;
    return  cmd_simulation(arrayLength, argv);  

}

在使用ffmpeg编译后,你可以模拟执行以下类似的ffmpeg命令:

private void executeCommand(){
    String[] command = {"ffmpeg", "-i", "some video file name",};
    int result = test(command);     
}

希望这能帮到您! 编辑: Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_WHOLE_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale libswresample libavfilter
LOCAL_MODULE    := VideoUtilLib
LOCAL_SRC_FILES := NativeVideoUtil.c ffmpeg.c ffmpeg_opt.c cmdutils.c ffmpeg_filter.c
LOCAL_LDLIBS := -lz -llog
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))

将NativeVideoUtil.c替换为您的本地文件。

很棒的方法!我会尝试你的方式!我现在不在办公室,所以我得等到明天早上。同时,你能告诉我,在修改后,我需要为Android重新构建ffmpeg吗?在我的本地代码文件中,我需要包含任何头文件吗? - Md. Arafat Al Mahmud
你需要包含的头文件只有 <jni.h> 和 <stdio.h>。我会在我的回答中发布我的 Android.mk。 - shhp
我遇到了这个错误: 08-14 05:30:11.729: W/dalvikvm(17973): PR_CAPBSET_DROP 0 失败:无效参数。请确保您的内核已启用文件能力支持。 - Md. Arafat Al Mahmud
我直接使用FFmpeg源代码编译了我的Android项目,所以我没有遇到这个问题。也许你可以尝试使用FFmpeg源代码进行编译。 - shhp
请问您可以提供已编译的FFmpeg源代码吗? - Sameer Z.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接