Android初探FFmpeg(1)--在Windows下编译FFmpeg

之前在博客中提到视频的裁剪和合并功能,用的是FFmpeg这块的东西,由于是从网上直接拔过来的东西,虽然功能算是实现了,但是心里总是感觉怪怪的,毕竟没有自己动手!自己也讨厌“伸手主义”,加之最近项目不是特别紧张,就自己动手编译了一遍,并在各种各样异常的情况下,总算在Android studio下跑成功了!本来打算把一些知识点再挖深一点,但是最近项目可能要迭代新版本,所以怕是要小忙一阵!为了避免把之前的忘了,所以还是需要草草的记录一下!下面开始。

准备环境:
VMware workstation 12 player
最新版下载地址:
https://my.vmware.com/cn/web/vmware/free#desktop_end_user_computing/vmware_workstation_player/12_0

Ubuntu 64(我存一份到我的云盘中了,大家可以到那下载)
下载地址:
http://pan.baidu.com/s/1bp8JG2j

安装完后打开界面如下:

这里写图片描述

OK,到这,就可以开始准备工作了!

由于之前家里的电脑也没下载NDK和FFmpeg,所以,我就打算在这个工作区间直接下载了(说到底是不会VMware的共享文件(大家可以自行谷歌或者百度,有解))

最新版的NDK下载地址:
https://dl.google.com/android/repository/android-ndk-r15b-linux-x86_64.zip

最新版的FFmpeg下载地址:
http://ffmpeg.org/releases/ffmpeg-3.3.2.tar.bz2

下载完之后,就可以开始编译了!
这里,我把两个压缩包全都放在home路径下了!

这里写图片描述

点击左键Extract File,进行解压文件夹(或者用命令行进行解压,都OK)

Ctrl+Alt+F2可打开命令行
Ctrl+Alt+F7可关闭命令行

接着打开FFmpeg的文件夹,打开configure文件,修改该属性为:

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

在接着创建文件build_android.sh文件,内容为:

#!/bin/bash
cd ffmpeg
export TMPDIR=/home/tianchuangxin/ffmpeg-3.3.2
NDK=/home/tianchuangxin/android-ndk-r15b
SYSROOT=$NDK/platforms/android-16/arch-arm/
TOOLCHAIN=$NDK/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64
CPU=arm
PREFIX=/home/tianchuangxin/ffmpeg-3.3.2/$CPU
ADDI_CFLAGS="-marm"
function build_one
{
    ./configure \
        --prefix=$PREFIX \
        --enable-shared \
        --disable-static \
        --disable-doc \
        --disable-ffmpeg \
        --disable-ffplay \
        --disable-ffprobe \
        --disable-ffserver \
        --disable-doc \
        --disable-symver \
        --enable-small \
        --cross-prefix=$TOOLCHAIN/bin/arm-linux-androideabi- \
        --target-os=linux \
        --arch=arm \
        --enable-cross-compile \
        --sysroot=$SYSROOT \
        --extra-cflags="-Os -fpic $ADDI_CFLAGS" \
        --extra-ldflags="$ADDI_LDFLAGS" \
        $ADDITIONAL_CONFIGURE_FLAG
    make clean
    make
    make install
}
build_one
cd ../

创建的这个文件需要注意的是,你自己需要修改一些东西:


这里写图片描述

圈出的这三处需要改成你自己的路径。
小提示:你最好先打开自己的命令行cd一下,看看能不能到这些文件路径下面,不然会一直报文件找不到的警告

接着给build_android.sh添加执行权限命令行如下:

$chmod+x build_android.sh 

接着执行.sh文件:

$./build_android.sh 

ok ,到这里,如果的你的配置都没有问题的话,已经开始生成.so文件了!

当你再打开ffmpeg的文件夹的时候多了一个文件夹 arm!

接着把arm文件夹copy出来之后开始在Android studio中测试一下咯!

在创建新的Android项目的的时候在,首页面需勾选:

这里写图片描述

接着一路next知道创建完成新的项目!

创建好新的项目,将之前的生成的arm包中的东西复制到工程下的libs文件夹下:


这里写图片描述

注意:现在是arm架构类型的CPU

接着开始配置native_lib.cpp文件,它在main目录下

这里写图片描述

#include <jni.h>
#include <string>

extern "C"
{

#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>

JNIEXPORT jstring JNICALL
Java_com_example_ffmpegtest_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());

}



JNIEXPORT jstring JNICALL
    Java_com_example_ffmpegtest_MainActivity_urlprotocolinfo(
            JNIEnv *env, jobject) {
        char info[40000] = {0};
        av_register_all();

        struct URLProtocol *pup = NULL;

        struct URLProtocol **p_temp = &pup;
        avio_enum_protocols((void **) p_temp, 0);

        while ((*p_temp) != NULL) {
            sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 0));
        }
        pup = NULL;
        avio_enum_protocols((void **) p_temp, 1);
        while ((*p_temp) != NULL) {
            sprintf(info, "%sInput: %s\n", info, avio_enum_protocols((void **) p_temp, 1));
        }
        return env->NewStringUTF(info);
    }

JNIEXPORT jstring JNICALL
    Java_com_example_ffmpegtest_MainActivity_avformatinfo(
            JNIEnv *env, jobject) {
        char info[40000] = {0};

        av_register_all();

        AVInputFormat *if_temp = av_iformat_next(NULL);
        AVOutputFormat *of_temp = av_oformat_next(NULL);
        while (if_temp != NULL) {
            sprintf(info, "%sInput: %s\n", info, if_temp->name);
            if_temp = if_temp->next;
        }
        while (of_temp != NULL) {
            sprintf(info, "%sOutput: %s\n", info, of_temp->name);
            of_temp = of_temp->next;
        }
        return env->NewStringUTF(info);
    }

JNIEXPORT jstring JNICALL
    Java_com_example_ffmpegtest_MainActivity_avcodecinfo(
            JNIEnv *env, jobject) {
        char info[40000] = {0};

        av_register_all();

        AVCodec *c_temp = av_codec_next(NULL);

        while (c_temp != NULL) {
            if (c_temp->decode != NULL) {
                sprintf(info, "%sdecode:", info);
            } else {
                sprintf(info, "%sencode:", info);
            }
            switch (c_temp->type) {
                case AVMEDIA_TYPE_VIDEO:
                    sprintf(info, "%s(video):", info);
                    break;
                case AVMEDIA_TYPE_AUDIO:
                    sprintf(info, "%s(audio):", info);
                    break;
                default:
                    sprintf(info, "%s(other):", info);
                    break;
            }
            sprintf(info, "%s[%10s]\n", info, c_temp->name);
            c_temp = c_temp->next;
        }

        return env->NewStringUTF(info);
    }

JNIEXPORT jstring JNICALL
    Java_com_example_ffmpegtest_MainActivity_avfilterinfo(
            JNIEnv *env, jobject) {
        char info[40000] = {0};
        avfilter_register_all();

        AVFilter *f_temp = (AVFilter *)avfilter_next(NULL);
        while(f_temp != NULL) {
            sprintf(info, "%s%s\n", info, f_temp->name);
            f_temp = f_temp->next;
        }
        return env->NewStringUTF(info);
    }
}

注意的是native的写法,你的函数名称可能跟我的不太一样哦!

接着配置CMakeLists.txt文件:

# Sets the minimum version of CMake required to build the native
# library. You should either keep the default value or only pass a
# value of 3.4.0 or lower.

cmake_minimum_required(VERSION 3.4.1)

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 )

set(distribution_DIR ${CMAKE_SOURCE_DIR}/../../../../libs)

add_library( avutil-55
            SHARED
            IMPORTED )
set_target_properties( avutil-55
             PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libavutil-55.so )

add_library( swresample-2
             SHARED
             IMPORTED )
set_target_properties( swresample-2
             PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libswresample-2.so )
add_library( avcodec-57
             SHARED
             IMPORTED )
set_target_properties( avcodec-57
             PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libavcodec-57.so )
add_library( avfilter-6
             SHARED
             IMPORTED)
set_target_properties( avfilter-6
             PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libavfilter-6.so )
add_library( swscale-4
            SHARED
             IMPORTED)
set_target_properties( swscale-4
            PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libswscale-4.so )
add_library( avdevice-57
            SHARED
            IMPORTED)
set_target_properties( avdevice-57
            PROPERTIES IMPORTED_LOCATION
            ../../../../libs/armeabi-v7a/libavdevice-57.so )
add_library( avformat-57
            SHARED
            IMPORTED)
set_target_properties( avformat-57
            PROPERTIES IMPORTED_LOCATION
             ../../../../libs/armeabi-v7a/libavformat-57.so )

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")

add_library( native-lib
            SHARED
             src/main/cpp/native-lib.cpp )

include_directories(libs/include)

             #target_include_directories(native-lib PRIVATE libs/include)

target_link_libraries( native-lib swresample-2 avcodec-57 avfilter-6 swscale-4 avdevice-57 avformat-57
             ${log-lib} )

接着是build.gradle的文件配置:

这里写图片描述
这里写图片描述

这两个千万别忘了,不然就跑不起来了!

哈哈,到这基本就完了!

这是跑出来的结果图:

这里写图片描述

文章参考:
http://blog.csdn.net/gobitan/article/details/22750719
http://blog.csdn.net/eastmoon502136/article/details/52806640
感谢作者的无私技术分享!

如有问题请指正,共同进步,谢谢!

每天进步一点点,时间会让你成为巨人!加油!

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

推荐阅读更多精彩内容