Android Camera2入门
Android Camera2入门系列1 - Camera2在textureView预览
Android Camera2入门系列2 - ImageReader获得预览数据
Android Camera2入门系列3 - Image中获得YUV数据及YUV格式理解
Android Camera2入门系列4 - libyuv的编译和使用
libyuv的编译
https://github.com/lemenkov/libyuv 下载下来源码,这里我使用ndk-build
编译,工作平台为mac,ndk版本r16b。
新建一个jni目录,把文件拷贝到jni目录下,命令行执行ndk-build编译,可能会报错,下面是我的Android.mk文件。
# This is the Android makefile for libyuv for NDK.
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_SRC_FILES := \
source/compare.cc \
source/compare_common.cc \
source/compare_gcc.cc \
source/compare_mmi.cc \
source/compare_msa.cc \
source/compare_neon.cc \
source/compare_neon64.cc \
source/convert.cc \
source/convert_argb.cc \
source/convert_from.cc \
source/convert_from_argb.cc \
source/convert_to_argb.cc \
source/convert_to_i420.cc \
source/cpu_id.cc \
source/planar_functions.cc \
source/rotate.cc \
source/rotate_any.cc \
source/rotate_argb.cc \
source/rotate_common.cc \
source/rotate_gcc.cc \
source/rotate_mmi.cc \
source/rotate_msa.cc \
source/rotate_neon.cc \
source/rotate_neon64.cc \
source/row_any.cc \
source/row_common.cc \
source/row_gcc.cc \
source/row_mmi.cc \
source/row_msa.cc \
source/row_neon.cc \
source/row_neon64.cc \
source/scale.cc \
source/scale_any.cc \
source/scale_argb.cc \
source/scale_common.cc \
source/scale_gcc.cc \
source/scale_mmi.cc \
source/scale_msa.cc \
source/scale_neon.cc \
source/scale_neon64.cc \
source/video_common.cc
# 这里我编译的时候报错。
# common_CFLAGS := -Wall -fexceptions
# 去掉编译JPEG
# ifneq ($(LIBYUV_DISABLE_JPEG), "yes")
# LOCAL_SRC_FILES += \
# source/convert_jpeg.cc \
# source/mjpeg_decoder.cc \
# source/mjpeg_validate.cc
# common_CFLAGS += -DHAVE_JPEG
# LOCAL_SHARED_LIBRARIES := libjpeg
# endif
LOCAL_CFLAGS += $(common_CFLAGS)
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
LOCAL_MODULE := libyuv_static
LOCAL_MODULE_TAGS := optional
include $(BUILD_STATIC_LIBRARY)
include $(CLEAR_VARS)
LOCAL_WHOLE_STATIC_LIBRARIES := libyuv_static
LOCAL_MODULE := libyuv
# 去掉编译JPEG
# ifneq ($(LIBYUV_DISABLE_JPEG), "yes")
# LOCAL_SHARED_LIBRARIES := libjpeg
# endif
include $(BUILD_SHARED_LIBRARY)
# 下面test同样可以不编译
# include $(CLEAR_VARS)
# LOCAL_STATIC_LIBRARIES := libyuv_static
# LOCAL_SHARED_LIBRARIES := libjpeg
# LOCAL_MODULE_TAGS := tests
# LOCAL_CPP_EXTENSION := .cc
# LOCAL_C_INCLUDES += $(LOCAL_PATH)/include
# LOCAL_SRC_FILES := \
# unit_test/unit_test.cc \
# unit_test/basictypes_test.cc \
# unit_test/color_test.cc \
# unit_test/compare_test.cc \
# unit_test/convert_test.cc \
# unit_test/cpu_test.cc \
# unit_test/cpu_thread_test.cc \
# unit_test/math_test.cc \
# unit_test/planar_test.cc \
# unit_test/rotate_argb_test.cc \
# unit_test/rotate_test.cc \
# unit_test/scale_argb_test.cc \
# unit_test/scale_test.cc \
# unit_test/video_common_test.cc
#
# LOCAL_MODULE := libyuv_unittest
# include $(BUILD_NATIVE_TEST)
几个地方要注意:
- JPEG部分注掉,可能会报错。
- common_CFLAGS := -Wall -fexceptions 我编译的时候报错,同样可以注释掉
- libyuv_unittest可以不用生成。也可以注释掉,不生成test包
这个时候执行ndk-build
,就会生成所有平台的so包,如果想只生成特定平台的so,可以添加一个Application.mk
,里面只加一句 APP_ABI := armeabi-v7a
,指定只生成arm v7的so,这时候执行ndk-build
则只会生成arm v7平台的so。
libyuv的调用
我们看上面libyuv的Android.mk,实际上是先生成了一个叫libyuv_static
的BUILD_STATIC_LIBRARY
,也就是一个libyuv_static.a
,然后再用这个libyuv_static.a
生成一个叫libyuv_static
的BUILD_SHARED_LIBRARY
,也就是libyuv_static.so
。
所以我们可以这样做。
看一下我们的目录结构
├── jni
│ ├── Android.mk
│ ├── Application.mk
│ ├── YUVTrans.cpp
│ └── libyuv
│ ├── ...
│ ├── Android.mk
│ ├── Application.mk
│ ├── include
│ │ ├── libyuv
│ │ ├── ...
│ ├── ...
│ ├── ...
省略了部分目录和文件,我们的思想是使用libyuv_static.a
再加上我们自己的JNI文件一同生成一个so就可以调用了。
看Android.mk文件:
#jni目录下的Android.mk文件
LOCAL_PATH := $(call my-dir)
GLOBAL_C_INCLUDES :=$(LOCAL_PATH)/libyuv/include
include $(CLEAR_VARS)
# module名字叫myYuv,生成libmyYuv.so
LOCAL_MODULE := myYuv
# 引用libyuv的头文件
LOCAL_C_INCLUDES := $(GLOBAL_C_INCLUDES)
# jni调用libyuv
LOCAL_SRC_FILES := YUVTrans.cpp
# 引用Android JNI Log 使用#include 必须添加,否则会报error: undefined reference to '__android_log_print'
LOCAL_LDLIBS := -llog
# 引用静态库libyuv_static.a
LOCAL_STATIC_LIBRARIES := libyuv_static
include $(BUILD_SHARED_LIBRARY)
# 找到子目录下所有的Android.mk执行
include $(call all-makefiles-under,$(LOCAL_PATH))
Application.mk文件:
#jni目录下的Application.mk文件
APP_ABI := armeabi-v7a
APP_STL := gnustl_static
APP_PLATFORM := android-14
build.gradle文件
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 26
targetSdkVersion 28
versionCode 1
versionName "1.0"
ndk {
abiFilters 'armeabi-v7a'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
sourceSets.main {
jni.srcDirs = []//disable automatic ndk-build call 屏蔽gradle自动生成Android.mk
jniLibs.srcDirs = ['jniLibs']//这个脚本的意思是把app下的libs文件夹,当成原本/src/main下的jniLibs文件夹,这样就可以加载so库了。
}
externalNativeBuild {
ndkBuild {
path "src/main/jni/Android.mk"
}
}
}
具体源码可以查看AndroidMediaCodec,
libyuv的使用还是蛮清晰的,传入对应的数组调用就可以了。
extern "C" JNIEXPORT void JNICALL
Java_com_yocn_libyuv_YUVTransUtil_ARGBToI420(JNIEnv *env, jobject thiz,
jbyteArray src_argb, int src_stride_argb,
jbyteArray dst_y, int dst_stride_y,
jbyteArray dst_u, int dst_stride_u,
jbyteArray dst_v, int dst_stride_v,
int width, int height) {
uint8_t *rgbBuffer = (uint8_t *) env->GetByteArrayElements(src_argb, NULL);
uint8_t *yBuffer = (uint8_t *) env->GetByteArrayElements(dst_y, NULL);
uint8_t *uBuffer = (uint8_t *) env->GetByteArrayElements(dst_u, NULL);
uint8_t *vBuffer = (uint8_t *) env->GetByteArrayElements(dst_v, NULL);
libyuv::ARGBToI420(rgbBuffer, src_stride_argb, yBuffer, dst_stride_y, uBuffer, dst_stride_u,
vBuffer, dst_stride_v, width, height);
}
源码查看YUVTransUtil.java 欢迎star/follow