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

2021-12-06  本文已影响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

上一篇下一篇

猜你喜欢

热点阅读