Tuesday 17 June 2014

Below blog will explain the steps to setup and configure ffmpeg using android ndk.

ffmpeg is an open-source platform for recording, converting, playing and streaming video and audio. It includes libavcodec, a popular video/audio codec.


Several popular Android applications are built based on FFmpeg, including RockPlayer, MoboPlayer, acrMedia, vitalPlayer, V-Cut Express etc. If you’re developing multimedia applications that needs a video/audio codec, ffmpeg is a good choice.
This blog covers how to compile ffmpeg for Android, and next blog will cover how to use ffmpeg to build a simple application.
The steps below are done on Ubuntu , android NDK , and ffmpeg . It should work on any versions of Android NDK and ffmpeg, but it may require minor changes.
Step 1:
Download and Install NDK from the android official site and copy it to a specific location.
Below is the link for android NDK:

Step 2:
Now link the android NDK with your eclipse using steps mentioned in the below url.

Step 3:
Create a new project in eclipse and with name "ffmpegExample" in eclipse and create a new folder named jni.

Step 4:
Download ffmpeg source from the below URL and place it to a specific location in your system.

Step 5:
Unpack ffmpeg sources to you "jni" directory folder of your project.
Step 6:
Create a file named "build4android.sh" in your "jni" directory folder of your project.

Step 7:
Copy and paste below text:
#!/bin/bash
# Author: Dmitry Dzakhov (based on Guo Mingyu's script)

# Creating conf.sh in ffmpeg directory
NDK=/home/dmitrydzz/android-ndk
PLATFORM=$NDK/platforms/android-8/arch-arm
PREBUILT=$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86
output="conf.sh"

[ -f conf.sh ] && echo "Old $output has been removed."
echo '#!/bin/bash' > $output
echo "PREBUILT=$PREBUILT" >> $output
echo "PLATFORM=$PLATFORM" >> $output
echo './configure --target-os=linux \
    --prefix=./android/armv7-a \
    --enable-cross-compile \
    --extra-libs="-lgcc" \
    --arch=arm \
    --cc=$PREBUILT/bin/arm-linux-androideabi-gcc \
    --cross-prefix=$PREBUILT/bin/arm-linux-androideabi- \
    --nm=$PREBUILT/bin/arm-linux-androideabi-nm \
    --sysroot=$PLATFORM \
    --extra-cflags=" -O3 -fpic -DANDROID -DHAVE_SYS_UIO_H=1 -Dipv6mr_interface=ipv6mr_ifindex -fasm -Wno-psabi -fno-short-enums -fno-strict-aliasing -finline-limit=300 -mfloat-abi=softfp -mfpu=neon -marm -march=armv7-a -mtune=cortex-a8 " \
    --disable-shared \
    --enable-static \
    --extra-ldflags="-Wl,-rpath-link=$PLATFORM/usr/lib -L$PLATFORM/usr/lib -nostdlib -lc -lm -ldl -llog" \
    --enable-parsers \
    --enable-encoders \
    --enable-decoders \
    --enable-muxers \
    --enable-demuxers \
    --enable-swscale \
    --enable-swscale-alpha \
    --disable-ffplay \
    --disable-ffprobe \
    --enable-ffserver \
    --enable-network \
    --enable-indevs \
    --disable-bsfs \
    --enable-filters \
    --enable-avfilter \
    --enable-protocols \
    --disable-asm \
    --enable-neon' >> $output

# start configure
sudo chmod +x $output
echo "configuring..."
./$output || (echo configure failed && exit 1)

# modify the config.h
echo "modifying the config.h..."
sed -i "s/#define restrict restrict/#define restrict/g" config.h

# remove static functions in libavutil/libm.h
echo "removing static functions in libavutil/libm.h..."
sed -i "/static/,/}/d" libavutil/libm.h

# modify Makefiles
echo "modifying Makefiles..."
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libavcodec/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libavcodec/Makefile
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libavfilter/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libavfilter/Makefile
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libavformat/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libavformat/Makefile
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libavutil/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libavutil/Makefile
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libpostproc/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libpostproc/Makefile
sed -i "/include \$(SUBDIR)..\/subdir.mak/d" libswscale/Makefile
sed -i "/include \$(SUBDIR)..\/config.mak/d" libswscale/Makefile

# generate av.mk in ffmpeg
echo "generating av.mk in ffmpeg..."
echo '# LOCAL_PATH is one of libavutil, libavcodec, libavformat, or libswscale

#include $(LOCAL_PATH)/../config-$(TARGET_ARCH).mak
include $(LOCAL_PATH)/../config.mak

OBJS :=
OBJS-yes :=
MMX-OBJS-yes :=
include $(LOCAL_PATH)/Makefile

# collect objects
OBJS-$(HAVE_MMX) += $(MMX-OBJS-yes)
OBJS += $(OBJS-yes)

FFNAME := lib$(NAME)
FFLIBS := $(foreach,NAME,$(FFLIBS),lib$(NAME))
FFCFLAGS  = -DHAVE_AV_CONFIG_H -Wno-sign-compare -Wno-switch -Wno-pointer-sign
FFCFLAGS += -DTARGET_CONFIG=\"config-$(TARGET_ARCH).h\"

ALL_S_FILES := $(wildcard $(LOCAL_PATH)/$(TARGET_ARCH)/*.S)
ALL_S_FILES := $(addprefix $(TARGET_ARCH)/, $(notdir $(ALL_S_FILES)))

ifneq ($(ALL_S_FILES),)
ALL_S_OBJS := $(patsubst %.S,%.o,$(ALL_S_FILES))
C_OBJS := $(filter-out $(ALL_S_OBJS),$(OBJS))
S_OBJS := $(filter $(ALL_S_OBJS),$(OBJS))
else
C_OBJS := $(OBJS)
S_OBJS :=
endif

C_FILES := $(patsubst %.o,%.c,$(C_OBJS))
S_FILES := $(patsubst %.o,%.S,$(S_OBJS))

FFFILES := $(sort $(S_FILES)) $(sort $(C_FILES))' > av.mk

echo 'include $(all-subdir-makefiles)' > ../Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_LIBRARIES := libavformat libavcodec libavutil libpostproc libswscale
LOCAL_MODULE := ffmpeg
include $(BUILD_SHARED_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))' > Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_CFLAGS += -include "string.h" -Dipv6mr_interface=ipv6mr_ifindex
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libavformat/Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_CFLAGS += -std=c99
LOCAL_LDLIBS := -lz
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libavcodec/Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libavfilter/Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libavutil/Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libpostproc/Android.mk

echo 'LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
include $(LOCAL_PATH)/../av.mk
LOCAL_SRC_FILES := $(FFFILES)
LOCAL_C_INCLUDES :=        \
    $(LOCAL_PATH)        \
    $(LOCAL_PATH)/..
LOCAL_CFLAGS += $(FFCFLAGS)
LOCAL_STATIC_LIBRARIES := $(FFLIBS)
LOCAL_MODULE := $(FFNAME)
include $(BUILD_STATIC_LIBRARY)' > libswscale/Android.mk

# start build!
echo "start ndk-building..."
cd ../..
$NDK/ndk-build
# Change previous line to "$NDK/ndk-build V=1" if you'll get errors. This will give some more information.

Change NDK build location in this script.
Step 8:
Go to your project folder directory and run the "build4android.sh" script.
After some time of ffmpeg building you'll get ffmpeg shared library and some static libraries in "<my-workspace>/ffmpegExample/obj" directory.

Step 9:
Now create a file named "mylib.c" in your "jni" folder directory and copy the below code.
#include <jni.h>
#include <android/log.h>

#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

#define LOG_TAG "mylib"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)

jint Java_ru_dzakhov_ffmpeg_test_MainActivity_logFileInfo(JNIEnv * env, jobject this, jstring filename)
{
    av_register_all();

    AVFormatContext *pFormatCtx;
    const jbyte *str;
    str = (*env)->GetStringUTFChars(env, filename, NULL);

    if(av_open_input_file(&pFormatCtx, str, NULL, 0, NULL)!=0)
    {
        LOGE("Can't open file '%s'\n", str);
        return 1;
    }
    else
    {
        LOGI("File was opened\n");
        LOGI("File '%s', Codec %s",
            pFormatCtx->filename,
            pFormatCtx->iformat->name
        );
    }
    return 0;
}


Step 10:
Now create a file named "Android.mk" in the same location and copy the below code.
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_LDFLAGS := -Wl,-rpath-link=/home/dmitrydzz/android-ndk/platforms/android-14/arch-arm/usr/lib/ -rpath-link=/home/dmitrydzz/android-ndk/platforms/android-14/arch-arm/usr/lib/
LOCAL_MODULE := libavformat
LOCAL_SRC_FILES := ../obj/local/armeabi/libavformat.a
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon #надо именно эти 3 параметра! Нашёл это в android-ndk/docs/STANDALONE-TOOLCHAIN.html
LOCAL_LDLIBS := -lz -lm -llog -lc -L$(call host-path, $(LOCAL_PATH))/$(TARGET_ARCH_ABI) -landprof

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_LDFLAGS := -Wl,-rpath-link=/home/dmitrydzz/android-ndk/platforms/android-14/arch-arm/usr/lib/ -rpath-link=/home/dmitrydzz/android-ndk/platforms/android-14/arch-arm/usr/lib/
LOCAL_MODULE := libavcodec
LOCAL_SRC_FILES := ../obj/local/armeabi/libavcodec.a
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon
LOCAL_LDLIBS := -lz -lm -llog -lc -L$(call host-path, $(LOCAL_PATH))/$(TARGET_ARCH_ABI) -landprof

include $(PREBUILT_STATIC_LIBRARY)
include $(CLEAR_VARS)

LOCAL_MODULE := libpostproc
LOCAL_SRC_FILES := ../obj/local/armeabi/libpostproc.a
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := libswscale
LOCAL_SRC_FILES := ../obj/local/armeabi/libswscale.a
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_MODULE := libavutil
LOCAL_SRC_FILES := ../obj/local/armeabi/libavutil.a
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon

include $(PREBUILT_STATIC_LIBRARY)

include $(CLEAR_VARS)

LOCAL_LDLIBS += -llog -lz
LOCAL_STATIC_LIBRARIES := libavformat libavcodec libpostproc libswscale libavutil
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ffmpeg
LOCAL_SRC_FILES := mylib.c
LOCAL_CFLAGS := -march=armv7-a -mfloat-abi=softfp -mfpu=neon
LOCAL_MODULE := mylib

include $(BUILD_SHARED_LIBRARY)

LOCAL_PATH := $(call my-dir)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/ffmpeg
include $(all-subdir-makefiles)

Step 11:

Go to the folder directory of your project the build the code to generate .so files using command "~/android-ndk/ndk-build"

Step 12:

Create a new activity in your project and copy the below code:

package ru.dzakhov.ffmpeg.test;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {
    private static native int logFileInfo(String filename);
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        logFileInfo("/sdcard/VIDEO0050.mp4");
    }

    static
    {
        System.loadLibrary("mylib");
    }
}

Don's forget to correct the package name and media file name.

Run the application to see the result.


References:
1) http://dmitrydzz-hobby.blogspot.in/2012/04/how-to-build-ffmpeg-and-use-it-in.html
2) https://github.com/bbcallen/ijkplayer/tree/master/android/ijkmediademo
3) http://www.roman10.net/how-to-build-ffmpeg-for-android/
4) http://code.google.com/p/android-fplayer/source/checkout
5) http://www.roman10.net/how-to-port-ffmpeg-the-program-to-androidideas-and-thoughts/
6) https://github.com/hoary/JavaAV

No comments:

Post a Comment