Android 使用 FFmpeg命令行(多包)

简介: 1. 新建项目,导入.so文件将之前编译生成的多个.so文件及inclulde文件夹下的头文件拷贝到/app/libs文件夹下,拷贝后目录结果如下:图1.

1. 新建项目,导入.so文件

将之前编译生成的多个.so文件及inclulde文件夹下的头文件拷贝到/app/libs文件夹下,拷贝后目录结果如下:


img_387e762f07ed93f558d0c7de46074d77.png
图1.png

2. 配置/app/src/main目录下新建jni文件夹

img_b9c9ca2efc2d3a3fa91a69dbca0d9d43.png
图2.png

3. 创建FFmpegCmd.java类

package com.mazaiting.ffmpegcmdtest;
/**
 * FFmpeg命令行操作
 * @author mazaiting
 * @date 2018/1/12
 */

public class FFmpegCmd {

    static {
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avformat-57");
        System.loadLibrary("avutil-55");
        System.loadLibrary("swresample-2");
        System.loadLibrary("swscale-4");
        System.loadLibrary("FfmpegCmd");
    }

    public static int execute(String[] commands) {
        return run(commands);
    }

    public native static int run(String[] commands);
}

4. 配置/app/build.gradle文件

1). 在android节点下的defaultConfig目录下新增

        ndk {
            moduleName "ffmpegcmd"
            abiFilters "armeabi"
        }

2). 在android节点下新增,如果已有则替换这段

    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/libs']
            jni.srcDirs=[]
        }
    }

5. 生成jni的头文件

javah命令配置, 运行命令完成后,在jni文件夹下生成com_mazaiting_ffmpegcmdtest_FFmpegCmd.h文件

img_5d3a985aac3f7c0335ccb134c735b357.png
图3.png

6. 配置jni目录

将ffmpeg源码中的ffmpeg.h, ffmpeg.c, ffmpeg_opt.c, ffmpeg_filter.c,cmdutils.c, cmdutils.h, cmdutils_common_opts.h,config.h 赋值到jni目录下,并在 jni 目录新建文件 Android.mk Application.mk com_mazaiting_ffmpegcmdtest_FFmpegCmd.c。

7. 修改ffmpeg源码

1). 编辑ffmpeg.c,把

int main(int argc, char **argv)

改名为

int run(int argc, char **argv)

编辑ffmpeg.h, 在文件末尾(在#endif前面)添加函数申明:

int run(int argc, char **argv)

2). 编辑cmdutils.c中的exit_program函数,删掉函数中原来的内容, 添加 return ret;并修改函数的返回类型为int。
长这样:

int exit_program(int ret)
{
    return ret;
}

编辑cmdutils.h中exit_program的申明,把返回类型修改为int。

int exit_program(int ret);

8. 其他文件

1). com_mazaiting_ffmpegcmdtest_FFmpegCmd.c

#include "com_mazaiting_ffmpegcmdtest_FFmpegCmd.h"
#include "ffmpeg.h"
#include <android/log.h>

#define LOGI(FORMAT, ...) __android_log_print(ANDROID_LOG_INFO,"ffmpeg",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT, ...) __android_log_print(ANDROID_LOG_ERROR,"ffmpeg",FORMAT,##__VA_ARGS__);

JNIEXPORT jint JNICALL Java_com_mazaiting_ffmpegcmdtest_FFmpegCmd_run
  (JNIEnv *env, jclass cls, jobjectArray commands) {

      int argc = (*env)->GetArrayLength(env, commands);
      char *argv[argc];

      LOGE("Kit argc %d\n", 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);
          LOGE("Kit argv %s\n", argv[i]);
      }

      return run(argc, argv);
  }

2). Android.mk

LOCAL_PATH := $(call my-dir)

# FFmpeg library
include $(CLEAR_VARS)
# 打印当前路径
$(warning $(LOCAL_PATH))
# .so文件名称,去除前缀lib和-后的内容
LOCAL_MODULE := avcodec
# .so文件
LOCAL_SRC_FILES := libavcodec-57.so
# 已编译好的库使用PREBUILT_SHARED_LIBRARY
include $(PREBUILT_SHARED_LIBRARY)

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

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

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

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

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

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

# Program
# module名称
include $(CLEAR_VARS)
LOCAL_MODULE := FfmpegCmd
# module中的源文件
LOCAL_SRC_FILES := com_mazaiting_ffmpegcmdtest_FFmpegCmd.c ffmpeg.c ffmpeg_opt.c cmdutils.c ffmpeg_filter.c
# ffmpeg源码路径
LOCAL_C_INCLUDES += C:/Users/Administrator/Desktop/ffmpeg-3.3.6
LOCAL_LDLIBS := -llog -lz
# 链接的动态库文件
LOCAL_SHARED_LIBRARIES := avcodec avdevice avfilter avformat avutil swresample swscale
# 编译生成的库使用BUILD_SHARED_LIBRARY
include $(BUILD_SHARED_LIBRARY)

3). Application.mk

APP_MODULES := FfmpegCmd
APP_ABI := armeabi
APP_PLATFORM := android-14
# 去除原子性编译
APP_LDFLAGS := -latomic

9. 编译FfmpegCmd.so文件

编译之前先将/app/libs文件夹内的ffmpeg中拷贝的.so文件拷贝到jni文件夹一份,此时jni文件夹内的所有文件如图4,使用ndk-build命令编译(图5)。


img_d1877f465891effc48e3146528dcd915.png
图4.png
img_502652edb0c90c3c11ee9aea8cb1ef89.png
图5.png

10. 编译成功

编译成功后在main目录下生成libs和obj文件夹,将/libs/armeabi/下的libFfmpegcmd.so或者/obj/local/armeabi/objs/下的libFfmpegcmd.so文件复制到/app/libs/armeabi/目录下,此时在java文件中即可成功使用ffmpeg。


img_94730c09de2ad09205fa286af3cbbd6e.png
图6.png

11. 使用

1). 在AndroidManifest.xml添加权限

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

2). activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.mazaiting.ffmpegcmdtest.MainActivity">

    <Button
        android:onClick="start"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="合成"/>
</RelativeLayout>

3). MainActivity.java


public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private boolean isRun = false;
    /**视频源路径*/
    private String videoUrl = "/storage/emulated/0/input.mp4";
    /**图片路径*/
    private String imageUrl = "/storage/emulated/0/image.png";
    /**视频输出路径*/
    private String outputUrl = "/storage/emulated/0/output.mp4";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void start(View view){
        if (!isRun) {
            new Thread(mRunnable).start();
            isRun = true;
        } else {
            Toast.makeText(this, "正在运行", Toast.LENGTH_SHORT).show();
        }
    }


    /**
     * 添加水印任务
     */
    Runnable mRunnable = new Runnable() {
        @Override
        public void run() {
            String[] commands = new String[10];
            commands[0] = "ffmpeg";
            commands[1] = "-i";
            commands[2] = videoUrl;
            commands[3] = "-i";
            commands[4] = imageUrl;
            commands[5] = "-filter_complex";
            commands[6] = "overlay=(main_w-overlay_w)/2:(main_h-overlay_h)/2";
            commands[7] = "-codec:a";
            commands[8] = "copy";
            commands[9] = outputUrl;

            Log.e(TAG, "run: 开始执行");
            FFmpegCmd.execute(commands);
            Log.e(TAG, "run: 执行结束");
            isRun = false;
        }
    };

}

12. 运行结果

img_8f491b28b5561e1dbb8200a2a406dc2e.png
图7.png
目录
相关文章
|
Linux 编译器 Android开发
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
在Linux环境下,本文指导如何交叉编译x265的so库以适应Android。首先,需安装cmake和下载android-ndk-r21e。接着,下载x265源码,修改crosscompile.cmake的编译器设置。配置x265源码,使用指定的NDK路径,并在配置界面修改相关选项。随后,修改编译规则,编译并安装x265,调整pc描述文件并更新PKG_CONFIG_PATH。最后,修改FFmpeg配置脚本启用x265支持,编译安装FFmpeg,将生成的so文件导入Android工程,调整gradle配置以确保顺利运行。
702 1
FFmpeg开发笔记(九)Linux交叉编译Android的x265库
|
网络协议 Android开发 Python
Android 抓包工具r0capture使用
Android 抓包工具r0capture使用
1546 1
|
存储 Java API
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
Android 浅度解析:mk预置AAR、SO文件、APP包和签名
1669 0
|
Unix Linux Shell
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
在Linux环境下交叉编译Android所需的FFmpeg so库,首先下载`android-ndk-r21e`,然后解压。接着,上传FFmpeg及相关库(如x264、freetype、lame)源码,修改相关sh文件,将`SYSTEM=windows-x86_64`改为`SYSTEM=linux-x86_64`并删除回车符。对x264的configure文件进行修改,然后编译x264。同样编译其他第三方库。设置环境变量`PKG_CONFIG_PATH`,最后在FFmpeg源码目录执行配置、编译和安装命令,生成的so文件复制到App工程指定目录。
510 9
FFmpeg开发笔记(八)Linux交叉编译Android的FFmpeg库
|
Java 开发工具 Android开发
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
如何在Eclipse中查看Android源码或者第三方组件包源码(转)
136 4
|
11月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
360 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
安全 Java Android开发
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
如何解压OTA升级包、编辑升级包内容(例如移除不需要更新的分区)、重新打包、签名以及验证OTA文件的过程。
1081 2
【Android P】OTA升级包定制,移除不需要更新的分区,重新打包签名
|
Android开发 开发者
Android、Flutter为不同的CPU架构包打包APK(v7a、v8a、x86)
Android、Flutter为不同的CPU架构包打包APK(v7a、v8a、x86)
948 1
|
编解码
FFmpeg开发笔记(三十七)分析SRS对HLS协议里TS包的插帧操作
《FFmpeg开发实战》书中讲解了音视频封装格式,重点介绍了TS,因其固定长度和独立解码特性,常用于HLS协议。HLS通过m3u8文件指示客户端播放TS分片。SRS服务器在转换MP4至TS时,会在每个TS包头添加SPS和PPS帧,保证解码完整性。这一过程在SrsIngestHlsOutput::on_ts_video函数中体现,调用write_h264_sps_pps和write_h264_ipb_frame完成。详细实现涉及SrsRawH264Stream::mux_sequence_header函数,遵循ISO标准写入SPS和PPS NAL单元。
285 0
FFmpeg开发笔记(三十七)分析SRS对HLS协议里TS包的插帧操作
|
安全 Linux Android开发
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库
该文介绍了如何在Linux服务器上交叉编译Android的FFmpeg库以支持HTTPS视频播放。首先,从GitHub下载openssl源码,解压后通过编译脚本`build_openssl.sh`生成64位静态库。接着,更新环境变量加载openssl,并编辑FFmpeg配置脚本`config_ffmpeg_openssl.sh`启用openssl支持。然后,编译安装FFmpeg。最后,将编译好的库文件导入App工程的相应目录,修改视频链接为HTTPS,App即可播放HTTPS在线视频。
303 3
FFmpeg开发笔记(十六)Linux交叉编译Android的OpenSSL库