Android Studio通过cmake创建FFmpeg项目

 

 

我的视频课程(基础):《(NDK)FFmpeg打造Android万能音频播放器》

我的视频课程(进阶):《(NDK)FFmpeg打造Android视频播放器》

我的视频课程(编码直播推流):《Android视频编码和直播推流》

我的视频课程(C++ OpenGL):《Android C++ OpenGL教程》

 

 

        在上一篇博客《FFmpeg(3.3.2)移植Android平台》 中介绍了FFmpeg移植到Android平台上来,通过博客我们最终得到了Android开发FFmpeg所需要的动态库(.so)和库文件(.h),博客结尾也上传了一个Android集成FFmpeg的demo,但是此demo是在eclipse下开发的,因为现在Android开发都是用的Android Studio了,所以就来讲讲在AS中怎么搭建FFmpeg开发环境吧。

 

一:首先下载需要的组件CMake和LLDB,前者是构建工具,后者是调试工具,注意这里我没有用SDK下载NDK,我喜欢单独下载NDK,后面导入。

二:创建支持C++的AS项目

新建工程,并勾选“C++ Support”,如图:

后面默认直接下一步,直到创建好工程。

三:此时工程编译出错,因为还没有导入NDK编译目录(注:最好用最新的NDK来构建,我原来的是10e,导致cmake构建失败,升级NDK就行了,下载地址:https://developer.android.com/ndk/downloads/index.html)我这里用的是现在最新14b版本。

下载后,配置环境变量,并为工程导入NDK编译目录:

Window配置:

ANDROID_NDK:E:\Android\android-ndk-r14b

Path:%ANDROID_NDK%

项目配置:

配置好后,再构建项目就可以了,下面是构建好的项目:

运行项目,效果如下就证明我们的C/C++项目创建成功了

四:AS默认C/C++项目介绍

1):c文件所在目录默认为cpp,并有一个简单的返回字符串的方法

2):我们看build.gradle里面

其中第一个cmake里面可以配置一些需要的参数,这里暂时就默认,不用更改;第二个cmakd里面导入了要参与构建的CMakeLists.txt脚本,这个脚本里面就是我们需要改写的,如:添加自己的c文件和系统库以及第三方库等。

3):CMakeLists.txt文件简析

这是根据功能推敲的,如有不对的,还请指正,哈哈。

4):生成的libxxxx.so位置

就在这里了,不用移动动态库位置,系统会自动调用这里面的。

5):Java调用

好的,默认的项目基本介绍完了,应该对AS中的c编译过程大概清楚了,接下来改造成我们自己的项目。

五:搭建FFmpeg目录

1):删除main下面的cpp目录和文件,创建jni目录(个人喜欢,其实在cpp目录里面也可以)

现在看着是不是熟悉又清爽了。

2):导入我们的FFmpeg库和头文件

因为只编译了arm平台下的FFmpeg,所以这里就只创建armeabi了,这样FFmpeg需要的库和头文件就导入到了项目中。

3):在activity同级目录下(这里就不新建包了,原理一样)添加我们自己的类,FFmpegPlayer.java

 

package com.ywl5320.ffmpegas;

/**
 * Created by ywl on 2017-7-14.
 */

public class FFmpegPlayer {

    static
    {
        System.loadLibrary("avutil-55");
        System.loadLibrary("swresample-2");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("swscale-4");
        System.loadLibrary("postproc-54");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avdevice-57");
    }
    public native void playMyMedia(String url);

}

首先是导入FFmpeg的动态库,然后自定义一个native方法来调用c代码。接下来生成xxx.c文件,AS挺智能的,把鼠标移到我们的native方法上面,然后 “alt+回车” 就能在jni中生成包含我们native方法的.c文件,文件名可以改一下,我这里改成的是play.c

 

 

 

 

 

 

 

这样就生成了我们需要的.c文件,不需要我们在命令行用javah来生成.h再写.c文件了,原来红色的native方法也变成

灰色的了:

4)接下来重点来了,配置CMakeLists.txt文件

4.1:为我们自己的c文件生成的动态库命名,这里就命名为wlffmpeg,把默认的改成如下:

 

add_library( # Sets the name of the library.
             wlffmpeg

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/jni/player.c )

4.2:添加FFmpeg动态库:

 

#添加libavcodec-57.so
add_library( avcodec-57
             SHARED
             IMPORTED)
set_target_properties( avcodec-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavcodec-57.so)
                       
#添加libavdevice-57.so                  
add_library( avdevice-57
             SHARED
             IMPORTED)
set_target_properties( avdevice-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavdevice-57.so)

add_library( avfilter-6
             SHARED
             IMPORTED)
set_target_properties( avfilter-6
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavfilter-6.so)

add_library( avformat-57
             SHARED
             IMPORTED)
set_target_properties( avformat-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavformat-57.so)

add_library( avutil-55
             SHARED
             IMPORTED)
set_target_properties( avutil-55
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavutil-55.so)

add_library( swresample-2
             SHARED
             IMPORTED)
set_target_properties( swresample-2
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswresample-2.so)

add_library( swscale-4
             SHARED
             IMPORTED)
set_target_properties( swscale-4
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswscale-4.so)
                       
add_library( postproc-54
             SHARED
             IMPORTED)
set_target_properties( postproc-54
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libpostproc-54.so)

简单介绍一下如图:

 

 

 

4.3:添加了FFmpeg动态库,最后还需要连接到系统中:

在此之前还需要导入FFmpeg的头文件才行:

 

include_directories(src/main/jni/ffmpeg/include)

 

然后再连接FFmpeg动态库

 

target_link_libraries( # Specifies the target library.

                       wlffmpeg
                       avcodec-57
                       avdevice-57
                       avfilter-6
                       avformat-57
                       avutil-55
                       swresample-2
                       swscale-4
                       postproc-54

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

4.4:现在还不能编译,现在编译会报“找不到mip64或其他cpu类型的错误”,因为我们这里只有arm的值,此时需要在build.gradle中配置编译的cup的类型,这里就只配置arm的:

 

externalNativeBuild {
            cmake {
                cppFlags ""
            }
            ndk {
                abiFilters "armeabi"
            }
        }

 

4.5:此时也还不能编译,会报“找不到FFmpeg的库的错误”,因为我们还需要给系统指定jniLibs的目录:

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

 

4.6:至此我们就可以愉快的编译代码了

完整的CMakeLists.txt

# 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.4.1)

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

add_library( # Sets the name of the library.
             wlffmpeg

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/jni/player.c )


#添加libavcodec-57.so
add_library( avcodec-57
             SHARED
             IMPORTED)
set_target_properties( avcodec-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavcodec-57.so)


#添加libavdevice-57.so
add_library( avdevice-57
             SHARED
             IMPORTED)
set_target_properties( avdevice-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavdevice-57.so)

add_library( avfilter-6
             SHARED
             IMPORTED)
set_target_properties( avfilter-6
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavfilter-6.so)

add_library( avformat-57
             SHARED
             IMPORTED)
set_target_properties( avformat-57
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavformat-57.so)

add_library( avutil-55
             SHARED
             IMPORTED)
set_target_properties( avutil-55
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libavutil-55.so)

add_library( swresample-2
             SHARED
             IMPORTED)
set_target_properties( swresample-2
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswresample-2.so)

add_library( swscale-4
             SHARED
             IMPORTED)
set_target_properties( swscale-4
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libswscale-4.so)

add_library( postproc-54
             SHARED
             IMPORTED)
set_target_properties( postproc-54
                       PROPERTIES IMPORTED_LOCATION
                       ${CMAKE_SOURCE_DIR}/src/main/jni/ffmpeg/armeabi/libpostproc-54.so)


# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

include_directories(src/main/jni/ffmpeg/include)

target_link_libraries( # Specifies the target library.

                       wlffmpeg
                       avcodec-57
                       avdevice-57
                       avfilter-6
                       avformat-57
                       avutil-55
                       swresample-2
                       swscale-4
                       postproc-54

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

 

完整的build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.ywl5320.ffmpegas"
        minSdkVersion 14
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags ""
            }
            ndk {
                abiFilters "armeabi"
            }
        }

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

    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-beta5'
    testCompile 'junit:junit:4.12'
}

编译后我们运行一下apk吧:

 

 

哈哈,there is nothing !当然了,因为我们在play.c里面还没有写什么代码,也还没有调用呢。

 

六:测试FFmpeg,调用里面的简单api,这里也查看其编码器的信息(本来想播放一段视频的声音或者画面,但是还需要集成SDL,所以就下次吧)。

player.c

#include <jni.h>

//ffmpeg库
#include "libavformat/avformat.h"

//打印日志
#include <android/log.h>
#define LOGI(FORMAT,...) __android_log_print(ANDROID_LOG_INFO,"ywl5320",FORMAT,##__VA_ARGS__);
#define LOGE(FORMAT,...) __android_log_print(ANDROID_LOG_ERROR,"ywl5320",FORMAT,##__VA_ARGS__);

JNIEXPORT void JNICALL
Java_com_ywl5320_ffmpegas_FFmpegPlayer_playMyMedia(JNIEnv *env, jobject instance, jstring url_) {
    const char *url = (*env)->GetStringUTFChars(env, url_, 0);

    LOGI("url:%s", url);

    av_register_all();
    AVCodec *c_temp = av_codec_next(NULL);
    while (c_temp != NULL)
    {
        switch (c_temp->type)
        {
            case AVMEDIA_TYPE_VIDEO:
                LOGI("[Video]:%s", c_temp->name);
                break;
            case AVMEDIA_TYPE_AUDIO:
                LOGI("[Audio]:%s", c_temp->name);
                break;
            default:
                LOGI("[Other]:%s", c_temp->name);
                break;
        }
        c_temp = c_temp->next;
    }
    // TODO

    (*env)->ReleaseStringUTFChars(env, url_, url);
}

调用代码:MainActivity.java

package com.ywl5320.ffmpegas;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    FFmpegPlayer fFmpegPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        fFmpegPlayer = new FFmpegPlayer();
        fFmpegPlayer.playMyMedia("http://blog.csdn.net/ywl5320");
    }
}

别忘了在FFmpegPlayer.java中添加我们自己的动态库(libwlffmpeg.so)哦:

package com.ywl5320.ffmpegas;

/**
 * Created by ywl on 2017-7-14.
 */

public class FFmpegPlayer {

    static
    {
        System.loadLibrary("avutil-55");
        System.loadLibrary("swresample-2");
        System.loadLibrary("avcodec-57");
        System.loadLibrary("avformat-57");
        System.loadLibrary("swscale-4");
        System.loadLibrary("postproc-54");
        System.loadLibrary("avfilter-6");
        System.loadLibrary("avdevice-57");
        System.loadLibrary("wlffmpeg");
    }
    public native void playMyMedia(String url);

}

其中libwlffmpeg.so的生成位置在这里:

 

因为只是打印了FFmpeg的编解码器信息,所以在AS的log日志中可以看到FFmpeg的信息了:


看到了我们的信息,说明FFmpeg已经在Android Studio上面跑起了,它能跑多快,就看各位大神的发挥了哈,搞定收工!!

且慢,还是总结一下:授人以鱼不如授人以渔,通过本次对FFmpeg的集成,基本了解了AS中用CMake来构建c/c++项目的过程了,以后遇到其他的库(c/c++优秀的库太多了)就可以迎刃而解了。最后附上github下载地址,里面有eclipse和AS两个版本的,仅供大家参考,eclipse版本的没有写博客,创建过程和博客《Android编译SDL2和demo展示(2.0.5)》中SDL一样,相信大家没问题的。

 

GitHub下载地址:https://github.com/wanliyang1990/FFmpeg-Android

 

 

 


 

 

 

 

 

 

 

 

 

 

 

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ywl5320

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值