Android Camera2入门系列4 - libyuv的编译和使用

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)

几个地方要注意:

  1. JPEG部分注掉,可能会报错。
  2. common_CFLAGS := -Wall -fexceptions 我编译的时候报错,同样可以注释掉
  3. 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_staticBUILD_STATIC_LIBRARY,也就是一个libyuv_static.a,然后再用这个libyuv_static.a生成一个叫libyuv_staticBUILD_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

你可能感兴趣的:(Android Camera2入门系列4 - libyuv的编译和使用)