如果在编译的时候出现如下问题:
ffbuild/common.mak:60: recipe for target ‘libavformat/udp.o’ failed
make: *** [libavformat/udp.o] Error 1
将libavformat/udp.c
第290~295行进行注释
// mreqs.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
// if (local_addr)
// mreqs.imr_interface= ((struct sockaddr_in *)local_addr)->sin_addr;
// else
// mreqs.imr_interface.s_addr= INADDR_ANY;
// mreqs.imr_sourceaddr.s_addr = ((struct sockaddr_in *)&sources[i])->sin_addr.s_addr;
这样之后,基本就是ok的,在我们ffmpeg
的文件夹下,会生成一个ffmpeg/android/armv7-a
的文件目录,里面内容如下:
将编译后的ffmpeg移植到Android
准备
- 在任何地方新建一个
jni
的文件夹。 - 将我们刚刚编译的
ffmpeg/android/armv7-a/include
下的所有文件拷贝进入jni
文件夹。 - 在
jni
下新建一个prebuilt
的文件夹,将ffmpeg/android/armv7-a/lib
下的so文件全部拷贝到prebuilt
之下。 - 然后将
ffmpeg/fftools
文件下的如下文件拷贝进入jni
- cmdutils.c
- cmdutils.h
- config.h
- ffmpeg_filter.c
- ffmpeg_hw.c
- ffmpeg_opt.c
- ffmpeg.c
- ffmpeg.h
修改ffmpeg文件
- 修改刚刚拷贝的
ffmpeg.c
文件,找到int main(int argc, char **argv)
函数,将其替换为int run(int argc, char **argv)
- 在修改后的
run(int argc, char **argv)
末尾(retrun 之前)加上如上如下代码:
nb_filtergraphs = 0;
progress_avio = NULL;
input_streams = NULL;
nb_input_streams = 0;
input_files = NULL;
nb_input_files = 0;
output_streams = NULL;
nb_output_streams = 0;
output_files = NULL;
nb_output_files = 0;
- 并在
ffmpeg.h
文件末尾加上
int run(int argc, char **argv);
- 再次打开
ffmpeg.c
文件,注释掉run(int argc, char **argv)
下的所有exit_program
函数,大致代码如下:
int run(int argc, char **argv)
{
int i, ret;
BenchmarkTimeStamps ti;
init_dynload();
register_exit(ffmpeg_cleanup);
setvbuf(stderr,NULL,_IONBF,0); /* win32 runtime needs this */
av_log_set_flags(AV_LOG_SKIP_REPEATED);
parse_loglevel(argc, argv, options);
if(argc>1 && !strcmp(argv[1], “-d”)){
run_as_daemon=1;
av_log_set_callback(log_callback_null);
argc–;
argv++;
}
#if CONFIG_AVDEVICE
avdevice_register_all();
#endif
avformat_network_init();
show_banner(argc, argv, options);
/* parse options and open all input/output files */
ret = ffmpeg_parse_options(argc, argv);
if (ret < 0);
// exit_program(1);
if (nb_output_files <= 0 && nb_input_files == 0) {
show_usage();
av_log(NULL, AV_LOG_WARNING, “Use -h to get full help or, even better, run ‘man %s’\n”, program_name);
// exit_program(1);
}
/* file converter / grab */
if (nb_output_files <= 0) {
av_log(NULL, AV_LOG_FATAL, “At least one output file must be specified\n”);
// exit_program(1);
}
// if (nb_input_files == 0) {
// av_log(NULL, AV_LOG_FATAL, “At least one input file must be specified\n”);
// exit_program(1);
// }
for (i = 0; i < nb_output_files; i++) {
if (strcmp(output_files[i]->ctx->oformat->name, “rtp”))
want_sdp = 0;
}
current_time = ti = get_benchmark_time_stamps();
if (transcode() < 0);
// exit_program(1);
if (do_benchmark) {
int64_t utime, stime, rtime;
current_time = get_benchmark_time_stamps();
utime = current_time.user_usec - ti.user_usec;
stime = current_time.sys_usec - ti.sys_usec;
rtime = current_time.real_usec - ti.real_usec;
av_log(NULL, AV_LOG_INFO,
“bench: utime=%0.3fs stime=%0.3fs rtime=%0.3fs\n”,
utime / 1000000.0, stime / 1000000.0, rtime / 1000000.0);
}
av_log(NULL, AV_LOG_DEBUG, “%“PRIu64” frames successfully decoded, %“PRIu64” decoding errors\n”,
decode_error_stat[0], decode_error_stat[1]);
if ((decode_error_stat[0] + decode_error_stat[1]) * max_error_rate < decode_error_stat[1]);
// exit_program(69);
// exit_program(received_nb_signals ? 255 : main_return_code);
nb_filtergraphs = 0;
progress_avio = NULL;
input_streams = NULL;
nb_input_streams = 0;
input_files = NULL;
nb_input_files = 0;
output_streams = NULL;
nb_output_streams = 0;
output_files = NULL;
nb_output_files = 0;
return main_return_code;
}
新建ffmpeg-invoke
在jni
文件下新建一个ffmpeg-invoke.cpp
的c++文件,将如下代码写入
#include <jni.h>
#include <string.h>
#include “android/log.h”
#define LOGD(…) __android_log_print(ANDROID_LOG_DEBUG, “ffmpeg-invoke”, VA_ARGS)
extern “C”{
#include “ffmpeg.h”
#include “libavcodec/jni.h”
}
extern “C”
JNIEXPORT jint JNICALL
Java_com_coder_ffmpeg_jni_FFmpegCmd_run(JNIEnv *env, jclass type, jint cmdLen,
jobjectArray cmd) {
//set java vm
JavaVM *jvm = NULL;
env->GetJavaVM(&jvm);
av_jni_set_java_vm(jvm, NULL);
char *argCmd[cmdLen] ;
jstring buf[cmdLen];
for (int i = 0; i < cmdLen; ++i) {
buf[i] = static_cast(env->GetObjectArrayElement(cmd, i));
char *string = const_cast<char *>(env->GetStringUTFChars(buf[i], JNI_FALSE));
argCmd[i] = string;
LOGD(“argCmd=%s”,argCmd[i]);
}
int retCode = run(cmdLen, argCmd);
LOGD(“ffmpeg-invoke: re
tCode=%d”,retCode);
return retCode;
}
需注意的是 Java_com_coder_ffmpeg_jni_FFmpegCmd_run
中 com_coder_ffmpeg_jni
表示FFmpegCmd
所在你Android项目的位置。
新建Android.mk
在jni
文件夹下,新建Android.mk
的文件,将如下代码拷贝,但是需要注意的是将 LOCAL_C_INCLUDES
路径替换成你源码所在位置。
// 将此处的路径改为你ffmepg源码所在位置
LOCAL_C_INCLUDES := /home/anjoiner/Documents/AnJoiner/ffmpeg
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libavdevice
LOCAL_SRC_FILES := prebuilt/libavdevice.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavutil
LOCAL_SRC_FILES := prebuilt/libavutil.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libswresample
LOCAL_SRC_FILES := prebuilt/libswresample.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libswscale
LOCAL_SRC_FILES := prebuilt/libswscale.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavcodec
LOCAL_SRC_FILES := prebuilt/libavcodec.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavformat
LOCAL_SRC_FILES := prebuilt/libavformat.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libavfilter
LOCAL_SRC_FILES := prebuilt/libavfilter.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := libpostproc
LOCAL_SRC_FILES := prebuilt/libpostproc.so
include $(PREBUILT_SHARED_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg-invoke
LOCAL_SRC_FILES :=ffmpeg-invoke.cpp
cmdutils.c
ffmpeg_filter.c
ffmpeg_opt.c
ffmpeg_hw.c
ffmpeg.c
// 将此处的路径改为你ffmepg源码所在位置
LOCAL_C_INCLUDES := /home/anjoiner/Documents/AnJoiner/ffmpeg
LOCAL_LDLIBS := -llog -ljnigraphics -lz -landroid -lm -pthread -L$(SYSROOT)/usr/lib
LOCAL_SHARED_LIBRARIES := libavdevice libavcodec libavfilter libavformat libavutil libswresample libswscale libpostproc
include $(BUILD_SHARED_LIBRARY)
新建Application.mk
在jni
文件夹下,新建Application.mk并将如下代码拷贝进入
APP_ABI := armeabi-v7a
APP_PLATFORM := android-21
APP_OPTIM := release
APP_STL := stlport_static
到此基本上的配置已经完成,然后在jni
文件下运行ndk-build
/home/anjoiner/Documents/AnJoiner/build/jni# /home/anjoiner/Documents/AnJoiner/ffmpeg/ndk/ndk-build
当出现如下代码就表示成功了
[armeabi-v7a] SharedLibrary : libffmpeg-invoke.so
[armeabi-v7a] Install : libffmpeg-invoke.so => libs/armeabi-v7a/libffmpeg-invoke.so
[armeabi-v7a] Install : libpostproc.so => libs/armeabi-v7a/libpostproc.so
[armeabi-v7a] Install : libswresample.so => libs/armeabi-v7a/libswresample.so
[armeabi-v7a] Install : libswscale.so => libs/armeabi-v7a/libswscale.so
测试
- 新建一个支