欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

编译Android环境下Ffmpeg命令行

程序员文章站 2022-06-05 18:02:44
...

提示:如果Ubuntu中未搭建android studio、或对Linux系统操作不熟悉的,可拷贝ffmpeg相关文件到windows中进行后续开发。

新建Android项目,并创建一个ffmpeglib的module

编译Android环境下Ffmpeg命令行

尊重原创,转载请注明出处,原文地址: http://blog.csdn.net/qq137722697

接下来所有的编译工作都将在ffmpeglib中进行

新建调用ffmpeg命令行的类

public class Ffmpeg {
    static {
        System.loadLibrary("ffmpegrun");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("swscale-4");
    }

    /**
     * 执行ffmpeg命令行
     *
     * @param cmd
     * @return
     */
    public native int execute(String[] cmd);
}

新建jni目录

在src/main下新建jni目录

新建ffmpeg_run.c

在jni目录中新建ffmpeg_run.c文件,用于作为上面新建的Ffmpeg类调用c代码。

#include "android_log.h"
#include "ffmpeg.h"
#include <jni.h>

JNIEXPORT jint JNICALL Java_com_hdl_ffmpeg_Ffmpeg_execute(JNIEnv *env, jobject type,jobjectArray commands){
      int argc = (*env)->GetArrayLength(env,commands);
      char *argv[argc];
      int i;
      for (i = 0; i < argc; i++) {
          jstring js = (jstring) (*env)->GetObjectArrayElement(env,commands, i);
          argv[i] = (char *) (*env)->GetStringUTFChars(env,js, 0);
      }
      LOGD("----------begin---------");
      return main(argc,argv);
}

创建android_log.h

这个主要用于执行命令过程中在logcat中输出日志,便于调试.

在jni目录中创建android_log.h

#ifdef ANDROID
#include <android/log.h>
#ifndef LOG_TAG
#define  MY_TAG   "MYTAG"
#define  AV_TAG   "AVLOG"
#endif
#define LOGE(format, ...)  __android_log_print(ANDROID_LOG_ERROR, MY_TAG, format, ##__VA_ARGS__)
#define LOGD(format, ...)  __android_log_print(ANDROID_LOG_DEBUG,  MY_TAG, format, ##__VA_ARGS__)
#define  XLOGD(...)  __android_log_print(ANDROID_LOG_INFO,AV_TAG,__VA_ARGS__)
#define  XLOGE(...)  __android_log_print(ANDROID_LOG_ERROR,AV_TAG,__VA_ARGS__)
#else
#define LOGE(format, ...)  printf(MY_TAG format "\n", ##__VA_ARGS__)
#define LOGD(format, ...)  printf(MY_TAG format "\n", ##__VA_ARGS__)
#define XLOGE(format, ...)  fprintf(stdout, AV_TAG ": " format "\n", ##__VA_ARGS__)
#define XLOGI(format, ...)  fprintf(stderr, AV_TAG ": " format "\n", ##__VA_ARGS__)
#endif

导入include文件

将上一篇《Ubuntu下编译android所需ffmpeg的so库》中生成的armlib/include文件夹拷贝到jni目录中

导入必备文件

将ffmpeg根目录的
cmdutils.c cmdutils.h cmdutils_common_opts.h
config.h(编译通过之后才会生成)
ffmpeg.c ffmpeg.h ffmpeg_filter.c ffmpeg_opt.c
等文件拷贝到jni目录;
将armlib/lib下所有带有编号的so文件(如libavcodec-57.so)拷贝到jni目录;

编译Android环境下Ffmpeg命令行

修改配置文件

修改cmdutils.c

找到cmdutils.c中的exit_program函数

修改前:

void exit_program(int ret)
{
    if (program_exit)
        program_exit(ret);

    exit(ret);
}

修改后:

int exit_program(int ret)
{
    if (program_exit)
        program_exit(ret);
   // exit(ret);
   return ret;
}

修改cmdutils.h

找到cmdutils.h中的exit_program函数

修改前:

void exit_program(int ret) av_noreturn;

修改后:

int exit_program(int ret);

修改ffmpeg.c

找到main函数,return 之前加上以下代码:(防止连续执行命令崩溃问题)

     nb_filtergraphs = 0;
     progress_avio = NULL;

     input_streams = NULL;
     nb_input_streams = 0;
     input_files = NULL;
     nb_input_files = 0;

     output_streams = NULL;
     nb_output_streams = 0;
     output_files = NULL;
     nb_output_files = 0;

编译Android环境下Ffmpeg命令行

新增日志输出【选填】

此选项可选,不需要输出日志到logcat的跳过此项。

找到ffmpeg.c,导入日志的头文件。

include "android_log.h"

找到log_callback_null函数,修改为以下内容(原方法没有任何实现哦):

static void log_callback_null(void *ptr, int level, const char *fmt, va_list vl)
{
   static int print_prefix = 1;
    static int count;
    static char prev[1024];
    char line[1024];
    static int is_atty;
    av_log_format_line(ptr, level, fmt, vl, line, sizeof(line), &print_prefix);
    strcpy(prev, line);
    if (level <= AV_LOG_WARNING){
        XLOGE("%s", line);
    }else{
        XLOGD("%s", line);
    }
}

找到main函数,在第一行加入日志输出:

int main(int argc, char **argv)
{
   av_log_set_callback(log_callback_null);
    int i, ret;
    int64_t ti;
    init_dynload();
    ...
    }

打包so

配置Android.mk

鉴于本人对CMake不是非常的熟悉,编译了很多次还是没有成功,后改为Android.mk方式编译。

在jni目录下创建Android.mk文件,并复制以下内容:

LOCAL_PATH := $(call my-dir)

# FFmpeg library
include $(CLEAR_VARS)
LOCAL_MODULE := avcodec
LOCAL_SRC_FILES := libavcodec-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avdevice
LOCAL_SRC_FILES := libavdevice-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avfilter
LOCAL_SRC_FILES := libavfilter-6.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avformat
LOCAL_SRC_FILES := libavformat-57.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := avutil
LOCAL_SRC_FILES := libavutil-55.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := postproc
LOCAL_SRC_FILES := libpostproc-54.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swresample
LOCAL_SRC_FILES := libswresample-2.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := swscale
LOCAL_SRC_FILES := libswscale-4.so
include $(PREBUILT_SHARED_LIBRARY)

# Program
include $(CLEAR_VARS)

LOCAL_MODULE    := ffmpegrun
LOCAL_SRC_FILES := ffmpeg_run.c cmdutils.c ffmpeg.c ffmpeg_filter.c ffmpeg_opt.c
LOCAL_LDLIBS += -llog
#LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_C_INCLUDES :=/home/hdl/ffmpeg/ffmpeg-3.2.9
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil postproc swresample swscale

include $(BUILD_SHARED_LIBRARY)

需要修改的地方:

LOCAL_MODULE:表示生成的so名字;

LOCAL_C_INCLUDES:表示ffmpeg源码的位置

创建Application.mk

复制以下内容:

APP_ABI := armeabi

最后的目录:

编译Android环境下Ffmpeg命令行

打包

进入到jni目录,输入:F:\sdk\ndk-bundle\ndk-build.cmd(此命令表示ndk的路径)

此时会在项目的libs中生成相应的so文件:

编译Android环境下Ffmpeg命令行

测试

在src/main目录下新建一个jniLibs目录,将上面生成的libs下的armeabi文件夹拷贝到jniLibs。

在主工程中编写测试类:(以下为点击按钮,将ts转换为mp4输出)

    public void onStartRun(View view) {
        try {
            Ffmpeg ffmpegCmd = new Ffmpeg();
            /**
             * 将sdcard中的test.ts文件转换成为output_ts_to_1001.mp4并输出
             */
            final String dir = Environment.getExternalStorageDirectory().getPath() + File.separator;
            String cmd = ("ffmpeg -i " + dir + "test.ts -acodec copy -vcodec copy -absf aac_adtstoasc " + dir + "output_ts_to_1001.mp4");
            ELog.e(cmd);
            int execute = ffmpegCmd.execute(cmd.split(" "));
            ELog.e("执行完毕了" + execute);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

错误记录:

Android studio会提示Error: Your project contains C++ files but it is not using a supported native build system.大致的意思就是你没有使用cmake来编译:

编译Android环境下Ffmpeg命令行

解决办法:

方法一、将jni目录重命名,如改为jin1,此时就不会报错了;(推荐)

方法二、将jni目录移除(此时已不需要该目录–以后改东西的话还是需要的,推荐方法一)。

E/AVLOG: /storage/emulated/0/test.ts: Permission denied
表示权限拒绝,需要适配权限

尊重原创,转载请注明出处,原文地址: http://blog.csdn.net/qq137722697