libyuv的编译与使用

libyuv是Google开源的实现YUV数据格式转换,旋转,缩放和镜像等操作的库。

编译

使用cmake+ndk来编译.so文件

在新建的AS工程中建一个module--libyuv,该module下的源码目录下新建cpp目录,将下载的libyuv相关文件导入到cpp目录中:

libyuv的编译与使用_第1张图片

在src目录下新建CMakeLists.txt,脚本内容为:

cmake_minimum_required(VERSION 3.4.1)
include_directories(src/main/cpp/libyuv/include)
add_subdirectory(src/main/cpp/libyuv ./build)


# 查找指定目录下的所有源文件,然后将结果存进指定变量名
aux_source_directory(src/main/cpp SRC_FILE)
add_library(yuvutil
        SHARED
        ${SRC_FILE}
        )
find_library(log-lib log)
target_link_libraries(yuvutil ${log-lib} yuv)

在libyuv这个module的build.gradle配置中指定CMakeLists.txt的路径:

 externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }

在local.properties文件中指定ndk路径:

ndk.dir=/.../Android/sdk/ndk/21.0.6011959

然后build这个module就OK了

libyuv的编译与使用_第2张图片

使用

ibyuv的旋转,缩放,镜像等操作都是通过I420格式来进行的,所以对于不是I420格式的yuv输入首先要进行格式转换。

应用层通过jni的方式来使用libyuv,此处以NV21转I420为例进行演示。

java层中提供一个native方法:

/**
 * Convert NV21 to I420
 * @param nv21Src  NV21 input data
 * @param width    source width
 * @param height   source height 
 * @param i420Dst  I420 output data
 */
public static native void yuvNV21ToI420(byte[] nv21Src, int width, int height, byte[] i420Dst);

在libyuv的covert.cc文件中提供了NV21转I420的api

// Convert NV12 to I420.
LIBYUV_API
int NV12ToI420(const uint8* src_y,
               int src_stride_y,
               const uint8* src_uv,
               int src_stride_uv,
               uint8* dst_y,
               int dst_stride_y,
               uint8* dst_u,
               int dst_stride_u,
               uint8* dst_v,
               int dst_stride_v,
               int width,
               int height) {
  return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
                    dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
                    dst_stride_v, width, height);
}

jni实现:

extern "C"
JNIEXPORT void JNICALL
Java_com_libyuv_util_YuvUtil_yuvNV21ToI420(JNIEnv *env, jclass jcls, jbyteArray nv21Src,
                                           jint width, jint height, jbyteArray i420Dst) {
    jbyte *src_nv21_data = env->GetByteArrayElements(nv21Src, NULL);
    jbyte *dst_i420_data = env->GetByteArrayElements(i420Dst, NULL);
    NV21ToI420(src_nv21_data, width, height, dst_i420_data);
    env->ReleaseByteArrayElements(i420Dst, dst_i420_data, 0);
}


// NV21:YYYY YYYY VU VU
// I420: YYYY YYYY UU VV
void NV21ToI420(jbyte *src_nv21_data, jint width, jint height, jbyte *dst_i420_data) {
    jbyte *src_y_plane = src_nv21_data;
    jbyte *src_uv_plane = src_nv21_data + width * height;
    jbyte *dst_y_plane = dst_i420_data;
    jbyte *dst_u_plane = dst_i420_data + width * height;
    jbyte *dst_v_plane = dst_u_plane + (width * height / 4);
    libyuv::NV12ToI420(
            (const uint8_t *) src_y_plane, width,
            (const uint8_t *) src_uv_plane, width,
            (uint8_t *) dst_y_plane, width,
            (uint8_t *) dst_v_plane, width / 2,
            (uint8_t *) dst_u_plane, width / 2,
            width, height);
}

输入都统一为I420的格式后,就可以进行愉快的旋转,缩放和镜像等操作了。

常见的yuv操作都做个封装Util,代码:

https://github.com/sifutang/libyuv.git 

推荐阅读:

OpenGL ES 实现实时音频的可视化

或许是迄今为止第一篇讲解 fps 计算原理的文章吧

推荐几个堪称教科书级别的 Android 音视频入门项目

OpenGL 实现视频编辑中的转场效果

觉得不错,点个在看呗~

你可能感兴趣的:(libyuv的编译与使用)