美文网首页
android 使用ffmpeg 调用命令实现视频转gif(ff

android 使用ffmpeg 调用命令实现视频转gif(ff

作者: 淼素 | 来源:发表于2021-12-06 17:38 被阅读0次

    ffmpeg 学习二讲了把ffmpeg导入到项目中。今天说一下怎么在android上直接调用ffmpeg的命里,来实现把小视频转换成GIF动图格式。
    看这篇之前先把学习一和学习二搞定,这里直接从学习二的基础上添加文件。

    1.添加必要文件

    1.1这些文件都在上一篇文章添加了
    QQ截图20211130163035.png
    1.2.下面是添加ffmpeg运行命令的文件,文件在下载的ffmpeg里面的fftools文件夹里面。
    QQ截图20211206150459.png

    这里面有一个ffmpeg_hw.老版本的可能没有,因为我看别人文章都没有添加这个,但是发现最新版本如果不添加,会出现错误,主要是ffmpeg.h的方法,实现在这个类里面。

    1.3.修改ffmpeg.c

    mian方法改个名字。

    int runCmd(int argc, char **argv)
    {
        略...最后添加下面代码,恢复状态
        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;
    
        return main_return_code;
    }
    

    在ffmpeg.h文件里面,找个位置添加

    int runCmd(int argc, char **argv);
    

    cmdutils.c修改退出代码,直接屏蔽掉。

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

    把native-lib.cpp文件直接改名成ffmpeg_cmd.c,代码如下

    #include <jni.h>
    #include "ffmpeg.h"
    
    JNIEXPORT jint
    
    JNICALL
    Java_com_tj_myapplication_MainActivity_run(
            JNIEnv *env, jclass obj, 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);
        }
        return runCmd(argc, argv);
    }
    

    修改文件CMakeLists.txt,这里呢有个坑,不算大,不算小吧。主要是CMakeLists.txt文件位置导致的路径出现偏差,找不到文件。上一篇文章提到过,正好我这里有配置了一套,就都贴下来了。
    1.CMakeLists.txt文件在cpp目录下,配置如下

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.10.2)
    
    project("myapplication")
    set(my_lib_path ${CMAKE_SOURCE_DIR}/../../../libs)
    
    
    add_library(
            myapplication
            SHARED
            cmdutils.c
            ffmpeg.c
            ffmpeg_filter.c
            ffmpeg_opt.c
            ffmpeg_cmd.c
            ffmpeg_hw.c)
    
    find_library(
            log-lib
            log)
    
    add_library(libavcodec
            SHARED
            IMPORTED )
    set_target_properties(libavcodec
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libavcodec.so )
    
    add_library(libavfilter
            SHARED
            IMPORTED )
    set_target_properties(libavfilter
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libavfilter.so )
    add_library(libavformat
            SHARED
            IMPORTED )
    set_target_properties(libavformat
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libavformat.so )
    add_library(libavutil
            SHARED
            IMPORTED)
    set_target_properties(libavutil
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libavutil.so )
    add_library(libswresample
            SHARED
            IMPORTED)
    set_target_properties(libswresample
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libswresample.so )
    
    add_library(libswscale
            SHARED
            IMPORTED)
    set_target_properties(libswscale
            PROPERTIES IMPORTED_LOCATION
            ${my_lib_path}/armeabi-v7a/libswscale.so )
    
    
    include_directories( ${my_lib_path}/include)
    
    target_link_libraries( myapplication
            libavcodec libavfilter libavformat libavutil libswresample libswscale
            ${log-lib} )
    

    2.CMakeLists.txt文件在app目录下与src平级配置如下

    # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.10.2)
    
    # Declares and names the project.
    
    set(CPP_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
    
    # 添加库
    add_library( # 库名称
            myapplication
    
            # 动态库,生成so文件
            SHARED
    
            # 源码
            ${CPP_DIR}/cmdutils.c
            ${CPP_DIR}/ffmpeg.c
            ${CPP_DIR}/ffmpeg_filter.c
            ${CPP_DIR}/ffmpeg_opt.c
            ${CPP_DIR}/ffmpeg_cmd.c
            ${CPP_DIR}/ffmpeg_hw.c
            )
    
    
    
    find_library( # Sets the name of the path variable.
            log-lib
    
            # Specifies the name of the NDK library that
            # you want CMake to locate.
            log )
    
    
    add_library(libavcodec
            SHARED
            IMPORTED )
    set_target_properties(libavcodec
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libavcodec.so )
    
    add_library(libavfilter
            SHARED
            IMPORTED )
    set_target_properties(libavfilter
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libavfilter.so )
    add_library(libavformat
            SHARED
            IMPORTED )
    set_target_properties(libavformat
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libavformat.so )
    add_library(libavutil
            SHARED
            IMPORTED)
    set_target_properties(libavutil
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libavutil.so )
    add_library(libswresample
            SHARED
            IMPORTED)
    set_target_properties(libswresample
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libswresample.so )
    
    add_library(libswscale
            SHARED
            IMPORTED)
    set_target_properties(libswscale
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libswscale.so )
    
    
    include_directories(libs/include)
    
    
    target_link_libraries( myapplication
            -Wl,--start-group
            libavcodec libavfilter libavformat libavutil libswresample libswscale
            -Wl,--end-group
            ${log-lib} )
    

    2修改问题

    精彩的部分来了,这时候运行项目,开始报错了。不过看很多文章都没出现这样的问题,我一直怀疑是不是我编译过程少了东西,懂的可以说一下。基本报错全是这样。fatal error: 'libavutil/thread.h' file not found


    QQ截图20211206165256.png
    注意!注意!注意!千万不要把报错的地方都删除掉。我就干过这么一次,好不容易泡成功了也没报错,结果生成的文件是0kb。

    把缺少的文件全都复制过来。说一下我的方法。用Androidstudio打开ffmpeg项目。然后全局搜索文件,找错误提示说缺少的文件,注意包名然后复制到include里面。如果文件没有就创建文件夹。


    QQ截图20211206165856.png
    最后我的include文件夹下是这样 QQ截图20211206150412.png
    再次提醒一下,不要复制错包名下的文件,很多文件在很多包下都有重名的。

    3调试测试

    package com.tj.myapplication;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.app.ActivityCompat;
    
    import android.app.Activity;
    import android.content.pm.PackageManager;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.TextView;
    
    import com.tj.myapplication.databinding.ActivityMainBinding;
    
    public class MainActivity extends AppCompatActivity {
    
        // Used to load the 'myapplication' library on application startup.
        static {
            System.loadLibrary("myapplication");
        }
        private static final int REQUEST_EXTERNAL_STORAGE = 1;
    
        private ActivityMainBinding binding;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            binding = ActivityMainBinding.inflate(getLayoutInflater());
            setContentView(binding.getRoot());
            binding.sampleText.setOnClickListener(view -> {
                ceshi();
            });
            verifyStoragePermissions(this);
        }
        private static String[] PERMISSIONS_STORAGE = {
                "android.permission.READ_EXTERNAL_STORAGE",
                "android.permission.WRITE_EXTERNAL_STORAGE"};
    
        //然后通过一个函数来申请
        public static void verifyStoragePermissions(Activity activity) {
            try {
                //检测是否有写的权限
                int permission = ActivityCompat.checkSelfPermission(activity,
                        "android.permission.WRITE_EXTERNAL_STORAGE");
                if (permission != PackageManager.PERMISSION_GRANTED) {
                    // 没有写的权限,去申请写的权限,会弹出对话框
                    ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public void ceshi() {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //转换gif从1秒到4秒。
                    //ffmpeg -y -i /storage/emulated/0/DCIM/Camera/VID_20211205_103838.mp4 -ss 1.0 -t 4.0 /storage/emulated/0/DCIM/Camera/VID_20211205_103838.gif
                    //将视频的第0.1秒装换成png,类似获取视频封面。很多命令
                    String cmd = "ffmpeg -i /storage/emulated/0/DCIM/Camera/VID_20211205_103838.mp4 -t 0.1 /storage/emulated/0/DCIM/Camera/VID_20211205_1038381111.png";
                    cmdRun(cmd);
                }
            }).start();
    
        }
    
        private int cmdRun(String cmd) {
            Log.e("命令", cmd);
            String regulation = "[ \\t]+";
            final String[] split = cmd.split(regulation);
            return run(split);
        }
    
    
        public native int run(String[] cmd);
    }
    

    这里还有一个问题。主要是10以上的android版本。搞了半天,运行直接崩溃,以为有写错东西了,打了半天日志,才找到返回的错误码是13,权限问题。在AndroidManifest.xml 的<application中加上android:requestLegacyExternalStorage="true"就ok了。

    参考地址:
    https://xch168.github.io/2018/10/26/android-invoke-ffmpeg-cmd/
    https://www.jianshu.com/p/3479bba0cf28

    相关文章

      网友评论

          本文标题:android 使用ffmpeg 调用命令实现视频转gif(ff

          本文链接:https://www.haomeiwen.com/subject/rhogxrtx.html