android 使用ffmpeg 调用命令实现视频转gif(ffmpeg 学习三)

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/
//www.greatytc.com/p/3479bba0cf28

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,919评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,567评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,316评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,294评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,318评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,245评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,120评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,964评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,376评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,592评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,764评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,460评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,070评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,697评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,846评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,819评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,665评论 2 354

推荐阅读更多精彩内容