This is a follow up post of the previous blog How to Build FFmpeg for Android.  You can read the previous tutorial first, or refer back to it when you feel necessary.

This blog covers how to build a simple Android app based on FFmpeg library. The app will detect the input video file’s resolution and codec information through interface provided by FFmpeg.

Blow is a screenshot of the app,

Figure 1. Screen shot of the sample android app based on FFmpeg

0. Create a new Android Project FFmpegTest.

When you’re asked to select targeted platform, select 2.2 as it’s the platform used in previous blog. But you’re free to change it.

Also create a folder named jni under the root directory “FFmpegTest” of this project.

1. Download the ffmpeg Source Code and Extract it to jni Folder

Follow the previous blog How to Build FFmpeg for Android to build the library.

2. Write the Native Code that use FFmpeg’s libavcodec library.

You can copy and paste the code below and save it as ffmpeg-test-jni.c under FFmpegTest/jni/ directory. Note that the code below is not completed, you can download the entire code at the end of the post.

/*for android logs*/
#define LOG_TAG "FFmpegTest"
#define LOG_LEVEL 10
#define LOGI(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__);}
#define LOGE(level, ...) if (level <= LOG_LEVEL) {__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__);}
char *gFileName;      //the file name of the video
AVFormatContext *gFormatCtx;
int gVideoStreamIndex;    //video stream index
AVCodecContext *gVideoCodecCtx;
static void get_video_info(char *prFilename);
static void get_video_info(char *prFilename) {
    AVCodec *lVideoCodec;
    int lError;
    /*register the codec*/
    extern AVCodec ff_h264_decoder;
    avcodec_register(&ff_h264_decoder);
    /*register demux*/
    extern AVInputFormat ff_mov_demuxer;
    av_register_input_format(&ff_mov_demuxer);
    /*register the protocol*/
    extern URLProtocol ff_file_protocol;
    av_register_protocol2(&ff_file_protocol, sizeof(ff_file_protocol));
    /*open the video file*/
    if ((lError = av_open_input_file(&gFormatCtx, gFileName, NULL, 0, NULL)) !=0 ) {
        LOGE(1, "Error open video file: %d", lError);
        return;    //open file failed
    }
    /*retrieve stream information*/
    if ((lError = av_find_stream_info(gFormatCtx)) < 0) {
        LOGE(1, "Error find stream information: %d", lError);
        return;
    }
    /*find the video stream and its decoder*/
    gVideoStreamIndex = av_find_best_stream(gFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, &lVideoCodec, 0);
    if (gVideoStreamIndex == AVERROR_STREAM_NOT_FOUND) {
        LOGE(1, "Error: cannot find a video stream");
        return;
    } else {
        LOGI(10, "video codec: %s", lVideoCodec->name);
    }
    if (gVideoStreamIndex == AVERROR_DECODER_NOT_FOUND) {
        LOGE(1, "Error: video stream found, but no decoder is found!");
        return;
    }
    /*open the codec*/
    gVideoCodecCtx = gFormatCtx->streams[gVideoStreamIndex]->codec;
    LOGI(10, "open codec: (%d, %d)", gVideoCodecCtx->height, gVideoCodecCtx->width);
    if (avcodec_open(gVideoCodecCtx, lVideoCodec) < 0) {
        LOGE(1, "Error: cannot open the video codec!");
        return;
    }
}
JNIEXPORT void JNICALL Java_roman10_ffmpegTest_VideoBrowser_naInit(JNIEnv *pEnv, jobject pObj, jstring pFileName) {
    int l_mbH, l_mbW;
    /*get the video file name*/
    gFileName = (char *)(*pEnv)->GetStringUTFChars(pEnv, pFileName, NULL);
    if (gFileName == NULL) {
        LOGE(1, "Error: cannot get the video file name!");
        return;
    }
    LOGI(10, "video file name is %s", gFileName);
    get_video_info(gFileName);
}
JNIEXPORT jstring JNICALL Java_roman10_ffmpegTest_VideoBrowser_naGetVideoCodecName(JNIEnv *pEnv, jobject pObj) {
    char* lCodecName = gVideoCodecCtx->codec->name;
    return (*pEnv)->NewStringUTF(pEnv, lCodecName);
}
 
 
 

If you’re not familiar with Java JNI, you may need to read about JNI first in order to understand the code. But this is not the focus of this tutorial hence not covered.

3. Build the Native Code.

Create a file named Android.mk under jni directory and copy paste the content below,

LOCAL_PATH := $(call my-dir)

#declare the prebuilt library
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-prebuilt
LOCAL_SRC_FILES := ffmpeg-0.8/android/armv7-a/libffmpeg.so
LOCAL_EXPORT_C_INCLUDES := ffmpeg-0.8/android/armv7-a/include
LOCAL_EXPORT_LDLIBS := ffmpeg-0.8/android/armv7-a/libffmpeg.so
LOCAL_PRELINK_MODULE := true
include $(PREBUILT_SHARED_LIBRARY)

#the ffmpeg-test-jni library
include $(CLEAR_VARS)
LOCAL_ALLOW_UNDEFINED_SYMBOLS=false
LOCAL_MODULE := ffmpeg-test-jni
LOCAL_SRC_FILES := ffmpeg-test-jni.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/ffmpeg-0.8/android/armv7-a/include
LOCAL_SHARED_LIBRARY := ffmpeg-prebuilt
LOCAL_LDLIBS    := -llog -ljnigraphics -lz -lm $(LOCAL_PATH)/ffmpeg-0.8/android/armv7-a/libffmpeg.so
include $(BUILD_SHARED_LIBRARY)

Create another file named Application.mk under jni directory and copy paste the content below,

# The ARMv7 is significanly faster due to the use of the hardware FPU
APP_ABI := armeabi-v7a
APP_PLATFORM := android-8

For more information about what Android.mk and Application.mk do, you can refer to the documentation comes with android NDK.

Your folder structure should be something like below after you finish all steps above,

Figure 2. Folder structure of project FFmpegTest and jni

4. Call the Native Code from FFmpegTest Java Code.

You’ll need to load the libraries and declare the jni functions. The code below is extracted from the app source code, which is provided for download at the end of this tutorial.

/*this part communicates with native code through jni (java native interface)*/
    //load the native library
    static {
        System.loadLibrary("ffmpeg");
        System.loadLibrary("ffmpeg-test-jni");
    }
    //declare the jni functions
    private static native void naInit(String _videoFileName);
    private static native int[] naGetVideoResolution();
    private static native String naGetVideoCodecName();
    private static native String naGetVideoFormatName();
    private static native void naClose();

    private void showVideoInfo(final File _file) {
        String videoFilename = _file.getAbsolutePath();
        naInit(videoFilename);
        int[] prVideoRes = naGetVideoResolution();
        String prVideoCodecName = naGetVideoCodecName();
        String prVideoFormatName = naGetVideoFormatName();
        naClose();
        String displayText = "Video: " + videoFilename + "\n";
        displayText += "Video Resolution: " + prVideoRes[0] + "x" + prVideoRes[1] + "\n";
        displayText += "Video Codec: " + prVideoCodecName + "\n";
        displayText += "Video Format: " + prVideoFormatName + "\n";
        text_titlebar_text.setText(displayText);
    }

5. You can Download the Entire Source Code from here.

Note: the code is tested on Ubuntu 10.04 and Android ndk-5b, but it should work on other platforms (except for Windows, which I’m not sure about.)

How to Build Android Applications Based on FFmpeg by An Example的更多相关文章

  1. cordova build android Command failed with exit code EACCES

    问题: 执行cordova build android 出现输出如下,编译不成功. ANDROID_HOME=/Users/huangenai/Library/Android/sdkJAVA_HOME ...

  2. Android开发学习之路--Android Studio cmake编译ffmpeg

      最新的android studio2.2引入了cmake可以很好地实现ndk的编写.这里使用最新的方式,对于以前的android下的ndk编译什么的可以参考之前的文章:Android开发学习之路– ...

  3. 为 Android 编译并集成 FFmpeg 的尝试与踩坑

    前言与环境说明 随着 FFmpeg.NDK 与 Android Studio 的不断迭代,本文可能也会像我参考过的过期文章一样失效(很遗憾),但希望本文中提到的问题排查以及步骤说明能够帮到你,如果发现 ...

  4. ionic build Android错误记录未解决

    1.try itcordova -v cordova create testing cd testing cordova plugin add cordova-plugin-sim cordova p ...

  5. ionic build android error when download gradle

    这里我遇到一个问题,当用  ionic build android 的时候,无数次build,无数次失败的时候,我真想骂一句,NND的GNF,我又想起武大的臭鸡蛋,是的,该丢,发明这种东西的人,难道不 ...

  6. 原创: How to build a query based on Definition Updates installed

    In SCCM 2012 R2, you can use following class. Use SMS_CombinedDeviceResources.EPAntivirusSignatureLa ...

  7. MAC 环境 ionic build android 命令在"Downloading http://services.gradle.org/distributions/gradle-2.13-all.zip"卡住问题

    如题: 环境 node: 4.5.0,npm:2.15.9,cordova :6.3.1, ionic:2.1.0 在ionic build android 命令执行时,会去这个网址下载 gradel ...

  8. 5 Best Automation Tools for Testing Android Applications

    Posted In | Automation Testing, Mobile Testing, Software Testing Tools   Nowadays automated tests ar ...

  9. Android 环境下编译FFmpeg

    Android 环境下编译FFmpeg 开发环境:Ubuntu 12.04.2 LTS , android-sdk-linux, android-ndk-r8e 一 .X264 编译 1.    X2 ...

随机推荐

  1. j-query j-query

    jQuery   1.安装:http://jquery.com/download/登陆这个jQuery下载2在.html文件的<head>标签中导入3 语法$(selector).acti ...

  2. winform自动添加同级目录下可执行文件的快捷方式到右键菜单中

    /// <summary> /// 追加同目录下可执行文件到右键菜单中 /// 在form的Load事件中调用:new clsContextMenuStrip(this.FindForm( ...

  3. windows实用技巧

    电脑如今已经非常普及,不过目前大多数电脑系统都是Win7/Win8.1或者Win10.你真的对自己电脑系统了解吗?今天小编为大家分享13个实用电脑技巧,会这些电脑技巧才叫牛哦! 13个实用电脑技巧 一 ...

  4. apache2反向代理node.js应用

    在之前记录的随笔中,只是介绍了怎么在apache2中使用proxy模块,后来查到了一些资料,可以通过下面网址查看配置块的详细参数信息 http://man.ddvip.com/soft/apache2 ...

  5. 状态可以通过动画切换的按钮--第三方开源--TickPlusDrawable

    Android tickplusdrawable(TickPlusDrawable)在github上的项目主页是:https://github.com/flavienlaurent/tickplusd ...

  6. MySQL5.7重置root密码

    版本更新 缘故,好多网上的教程都不适用了,甚至连官网的文档也不是能够顺利操作的. 如果 MySQL 正在运行,首先杀之: killall -TERM mysqld. 运行mysqld_safe --s ...

  7. js实现touch移动触屏滑动事件

    在开始描述touch事件之前,需要先描述一下多触式系统中特有的touch对象(android和iOS乃至nokia最新的meego系统都模拟了类 似的对象).这个对象封装一次屏幕触摸,一般来自于手指. ...

  8. node.js web开发:EXPRESS 4.x 以上使用session和cookie 的记录

    关于session 和cookie 我搞了2-3天, 发现这个玩意也挺麻烦的. 很多教程都是把这种会话保存在nosql里面,比如mongo,或者redis等等.但是我还是想直接保存在计算机的内存中,比 ...

  9. debian完整部署 Nginx + uWSGI + Django

    手工部署一个Django服务器真心不容易,需要安装很多东西.从头开始搭建服务器,主要是为了梳理一下后续开发中一般为碰到的平台部署.对后续问题的解决有一定帮助. 通常部署有2中方式: 一种是使用现成提供 ...

  10. MIFARE系列7《安全性》

    飞利浦的MIFARE卡由于它的高安全性在市场上得到广泛应用,比如我们乘车用的公交卡,学校和企业食堂的饭卡等等.它每个扇区有独立的密匙(6个字节的密码),在通信过程中首先要验证密匙才能读写数据.它的关键 ...