android全平台编译libyuv库实现YUV和RGB的转换

32 篇文章 3 订阅
28 篇文章 0 订阅

音视频实践学习

概述

libyuv是Google开源的实现各种YUV与RGB之间相互转换、旋转、缩放的库。它是跨平台的,可在Windows、Linux、Mac、Android等操作系统,x86、x64、arm架构上进行编译运行,支持SSE、AVX、NEON等SIMD指令加速。

环境配置

操作系统:ubuntu 16.05
ndk版本:android-ndk-r16b

开始编译

第一步:先克隆出最新的libyuv版本

git clone git@github.com:lemenkov/libyuv.git

第二步:重命名libyuvjni,编辑Android.mk文件,注释掉JPEG相关的配置

第三步:新建Application.mk文件

APP_ABI := armeabi-v7a x86 x86_64
APP_PLATFORM := android-16
APP_STL := stlport_static  
APP_CPPFLAGS += -fno-rtti  

开始编译ndk-build

工程实践

还是基于之前的graphic4android工程,新建native-libyuv工程,配置可以参考之前的配置:

enum Type {
    TYPE_YUV420P_TO_RGB24 = 0,
    TYPE_NV12_TO_RGB24 = 1,
    TYPE_NV21_TO_RGB24 = 2
};

/**
 * I420就是YUV420P
 * @param yuvData
 * @param rgb24
 * @param width
 * @param height
 */
void I420_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {

    unsigned char *ybase = yuvData;
    unsigned char *ubase = &yuvData[width * height];
    unsigned char *vbase = &yuvData[width * height * 5 / 4];
    //YUV420P转RGB24
    libyuv::I420ToRGB24(ybase, width, ubase, width / 2, vbase, width / 2,
                        rgb24,
                        width * 3, width, height);

}

/**
 * NV12属于YUV420SP
 * @param yuvData
 * @param rgb24
 * @param width
 * @param height
 */
void NV12_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {

    unsigned char *ybase = yuvData;
    unsigned char *uvbase = &yuvData[width * height];
    //NV12转RGB24
    libyuv::NV12ToRGB24(ybase, width, uvbase, width,
                        rgb24,
                        width * 3, width, height);

}

/**
 * NV21属于YUV420SP
 * @param yuvData
 * @param rgb24
 * @param width
 * @param height
 */
void NV21_TO_RGB24(unsigned char *yuvData, unsigned char *rgb24, int width, int height) {

    unsigned char *ybase = yuvData;
    unsigned char *vubase = &yuvData[width * height];
    //NV21转RGB24
    libyuv::NV21ToRGB24(ybase, width, vubase, width,
                        rgb24,
                        width * 3, width, height);

}

void drawYUV(const char *path, int type, int width, int height, ANativeWindow_Buffer buffer) {
    FILE *file = fopen(path, "rb");

    int frameSize = width * height * 3 / 2;

    unsigned char *yuvData = new unsigned char[frameSize];

    fread(yuvData, 1, frameSize, file);

    unsigned char *rgb24 = new unsigned char[width * height * 3];

    //YUV转RGB24
    switch (type) {
        case TYPE_YUV420P_TO_RGB24:
            //YUV420P转RGB24
            I420_TO_RGB24(yuvData, rgb24, width, height);
            break;
        case TYPE_NV12_TO_RGB24:
            //YUV420SP转RGB24
            NV12_TO_RGB24(yuvData, rgb24, width, height);
            break;
        case TYPE_NV21_TO_RGB24:
            //YUV420SP转RGB24
            NV21_TO_RGB24(yuvData, rgb24, width, height);
            break;
    }

    uint32_t *line = (uint32_t *) buffer.bits;
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int index = y * width + x;
            line[x] = rgb24[index * 3] << 16
                      | rgb24[index * 3 + 1] << 8
                      | rgb24[index * 3 + 2];
        }
        line = line + buffer.stride;
    }

    //释放内存
    delete[] yuvData;
    delete[] rgb24;

    //关闭文件句柄
    fclose(file);
}

void yuv2rgb(JNIEnv *env, jobject obj, jstring yuvPath, jint type, jint width, jint height,
             jobject surface) {

    const char *path = env->GetStringUTFChars(yuvPath, 0);

    //获取目标surface
    ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    if (NULL == window) {
        ThrowException(env, "java/lang/RuntimeException", "unable to get native window");
        return;
    }
    //默认的是RGB_565
    int32_t result = ANativeWindow_setBuffersGeometry(window, 0, 0, WINDOW_FORMAT_RGBA_8888);
    if (result < 0) {
        ThrowException(env, "java/lang/RuntimeException", "unable to set buffers geometry");
        //释放窗口
        ANativeWindow_release(window);
        window = NULL;
        return;
    }
    ANativeWindow_acquire(window);

    ANativeWindow_Buffer buffer;
    //锁定窗口的绘图表面
    if (ANativeWindow_lock(window, &buffer, NULL) < 0) {
        ThrowException(env, "java/lang/RuntimeException", "unable to lock native window");
        //释放窗口
        ANativeWindow_release(window);
        window = NULL;
        return;
    }

    //绘制YUV420P
    drawYUV(path, type, width, height, buffer);

    //解锁窗口的绘图表面
    if (ANativeWindow_unlockAndPost(window) < 0) {
        ThrowException(env, "java/lang/RuntimeException",
                       "unable to unlock and post to native window");
    }

    env->ReleaseStringUTFChars(yuvPath, path);
    //释放
    ANativeWindow_release(window);
}

直接调用libyuv库里的函数即可完成转换过程

项目地址:native-libyuv
https://github.com/byhook/graphic4android

libyuv中,可以使用ARGBToI420函数将RGB32格式的图像数据转换YUV格式。ARGBToI420函数的定义如下: ```c++ int ARGBToI420(const uint8* src_argb, int src_stride_argb, 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); ``` 其中,src_argb参数表示RGB32格式的原始数据,src_stride_argb表示每一行像素数据的跨度,即每一行像素占用的字节数。dst_y、dst_u和dst_v参数分别表示转换后的YUV格式数据中的Y、U和V分量数据,dst_stride_y、dst_stride_u和dst_stride_v参数则表示每一行像素数据的跨度,即每一行像素占用的字节数。width和height参数表示图像的宽度和高度。 使用ARGBToI420函数将RGB32格式的图像数据转换YUV格式的示例如下: ```c++ #include "libyuv.h" void RGB32ToYUV(unsigned char *src, unsigned char *dst_y, unsigned char *dst_u, unsigned char *dst_v, int width, int height) { int src_stride = width * 4; int dst_stride_y = width; int dst_stride_u = width / 2; int dst_stride_v = width / 2; ARGBToI420(src, src_stride, dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v, width, height); } ``` 其中,src参数表示RGB32格式的原始数据,dst_y、dst_u和dst_v参数分别表示转换后的YUV格式数据中的Y、U和V分量数据,width和height参数表示图像的宽度和高度。在函数中,首先计算每个分量数据的跨度,然后调用ARGBToI420函数将RGB32格式的图像数据转换YUV格式。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值