How to Build Android Applications Based on FFmpeg by An Example
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.)
102 comments on “How to Build Android Applications Based on FFmpeg by An Example”
Leave a Reply Cancel reply
40% Discount on My Book — Android NDK Cookbook
Android NDK Cookbook ebook 40% discount with promotion code MREANC40 at Packt Publishing The promotion code is valid until 15th June.Categories
- Android Apps (18)
- Android Audio Editor (1)
- TS 2 (3)
- Video Converter Android (8)
- Video2Gif (1)
- Android Tutorial (26)
- Android Dev Tools (1)
- API illustrated (8)
- Multimedia API (3)
- ffmpeg on Android (4)
- NDK (6)
- UI (5)
- Animation (1)
- Code Snippet (2)
- Coding Beyond Technique (18)
- a word, a world (4)
- Bug Rectified (4)
- Programming Habit (1)
- Software as a Career (1)
- Software as User Experience (1)
- Compilers and Related (2)
- ELF (2)
- Computer Languages (31)
- C/C++ (13)
- Java (9)
- JavaScript (2)
- PHP (1)
- Python (8)
- Data Structure & Algorithms (29)
- Bits (1)
- Data Structure (5)
- Integers (10)
- BigInteger (1)
- Prime (4)
- Search (3)
- Sorting (5)
- Strings (5)
- Database (1)
- SQLite (1)
- Digital Signal Processing (33)
- Distributed Systems (17)
- Apache Cassandra (6)
- Apache Hadoop (8)
- Apache Avro (3)
- Apache Nutch (3)
- Apache Solr (1)
- Linux Study Notes (40)
- crontab (1)
- Linux Kernel Programming (8)
- Linux Programming (12)
- IPC (2)
- Linux Network Programming (5)
- Linux Signals (2)
- Linux Shell Scripting (1)
- ssh (3)
- Machinery (30)
- misc (1)
- My Ideas (1)
- My Project (3)
- Mobile Caching (1)
- Selective Decoding (2)
- My Publication (1)
- My Readings (1)
- Networking (15)
- Program for Performance (8)
- Uncategorized (1)
- Virtual Machine (2)
- Web Dev (8)
- web components (3)
- Android Apps (18)
Recent Comments
Archives
- May 2013 (1)
- April 2013 (1)
- March 2013 (4)
- December 2012 (2)
- November 2012 (6)
- October 2012 (6)
- September 2012 (3)
- August 2012 (13)
- July 2012 (15)
- June 2012 (3)
- May 2012 (8)
- April 2012 (4)
- March 2012 (13)
- February 2012 (19)
- January 2012 (9)
- December 2011 (11)
- November 2011 (12)
- October 2011 (4)
- September 2011 (12)
- August 2011 (16)
- July 2011 (15)
- June 2011 (6)
- May 2011 (10)
- April 2011 (13)
- March 2011 (20)
- February 2011 (4)
- November 2010 (2)
- May 2010 (1)
- April 2010 (1)
- February 2010 (1)





Hi, congratulation for you tutorial. I have a question. What I have to do if I would include on the file ffmpeg-test.c other libraries as for example .
I get always an error when I try to include new libraries..
Thanks in advance
Thanks for this wonderful tutorial.I have a problem is that when I ndk-build…it throw error
Android NDK: Could not find application project directory !
Android NDK: Please define the NDK_PROJECT_PATH variable to point to it.
/home/dilip/Desktop/Android/android-ndk-r8d/build/core/build-local.mk:130: *** Android NDK: Aborting . Stop.
Thanks for the example. But how do I run it on Windows and Android.
I get the following in logcat
03-23 11:01:56.291: E/AndroidRuntime(1246): FATAL EXCEPTION: main
03-23 11:01:56.291: E/AndroidRuntime(1246): java.lang.ExceptionInInitializerError
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.Class.newInstanceImpl(Native Method)
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.Class.newInstance(Class.java:1319)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.Instrumentation.newActivity(Instrumentation.java:1023)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1871)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.ActivityThread.access$600(ActivityThread.java:123)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.os.Handler.dispatchMessage(Handler.java:99)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.os.Looper.loop(Looper.java:137)
03-23 11:01:56.291: E/AndroidRuntime(1246): at android.app.ActivityThread.main(ActivityThread.java:4424)
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.reflect.Method.invokeNative(Native Method)
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.reflect.Method.invoke(Method.java:511)
03-23 11:01:56.291: E/AndroidRuntime(1246): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
03-23 11:01:56.291: E/AndroidRuntime(1246): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
03-23 11:01:56.291: E/AndroidRuntime(1246): at dalvik.system.NativeStart.main(Native Method)
03-23 11:01:56.291: E/AndroidRuntime(1246): Caused by: java.lang.UnsatisfiedLinkError: Couldn’t load ffmpeg: findLibrary returned null
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.Runtime.loadLibrary(Runtime.java:365)
03-23 11:01:56.291: E/AndroidRuntime(1246): at java.lang.System.loadLibrary(System.java:535)
03-23 11:01:56.291: E/AndroidRuntime(1246): at roman10.ffmpegTest.VideoBrowser.(VideoBrowser.java:37)
03-23 11:01:56.291: E/AndroidRuntime(1246): … 15 more
rgds
Hi!
I download Your example, but I run get the exception (ndk.r8d):
04-24 08:48:52.062: W/dalvikvm(27491): Exception Ljava/lang/UnsatisfiedLinkError; thrown while initializing Lroman10/ffmpegTest/VideoBrowser;
04-24 08:48:52.062: W/dalvikvm(27491): Class init failed in newInstance call (Lroman10/ffmpegTest/VideoBrowser;)
04-24 08:49:05.414: D/AndroidRuntime(27491): Shutting down VM
04-24 08:49:05.414: W/dalvikvm(27491): threadid=1: thread exiting with uncaught exception (group=0x40a9a300)
04-24 08:49:05.480: E/AndroidRuntime(27491): FATAL EXCEPTION: main
04-24 08:49:05.480: E/AndroidRuntime(27491): java.lang.ExceptionInInitializerError
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.Class.newInstanceImpl(Native Method)
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.Class.newInstance(Class.java:1319)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.Instrumentation.newActivity(Instrumentation.java:1053)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2090)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2210)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.ActivityThread.access$600(ActivityThread.java:142)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1208)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.os.Handler.dispatchMessage(Handler.java:99)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.os.Looper.loop(Looper.java:137)
04-24 08:49:05.480: E/AndroidRuntime(27491): at android.app.ActivityThread.main(ActivityThread.java:4931)
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.reflect.Method.invokeNative(Native Method)
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.reflect.Method.invoke(Method.java:511)
04-24 08:49:05.480: E/AndroidRuntime(27491): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:791)
04-24 08:49:05.480: E/AndroidRuntime(27491): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:558)
04-24 08:49:05.480: E/AndroidRuntime(27491): at dalvik.system.NativeStart.main(Native Method)
04-24 08:49:05.480: E/AndroidRuntime(27491): Caused by: java.lang.UnsatisfiedLinkError: Couldn’t load ffmpeg: findLibrary returned null
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.Runtime.loadLibrary(Runtime.java:365)
04-24 08:49:05.480: E/AndroidRuntime(27491): at java.lang.System.loadLibrary(System.java:535)
04-24 08:49:05.480: E/AndroidRuntime(27491): at roman10.ffmpegTest.VideoBrowser.(VideoBrowser.java:36)
04-24 08:49:05.480: E/AndroidRuntime(27491): … 15 more
You can write it to me, what I have to change in order for the code to run?