在android项目上集成libyuv库以及使用libyuv库完成camera的缩放,旋转,翻转,裁剪操作

news2024/11/18 18:23:15

目录

一、下拉google官方的libyuv库代码

二、在android项目中集成libyuv库

1.环境配置

2.拷贝libyuv源码文件

​编辑3.配置cmake libyuv相关的链接编译等 

三、使用libyuv库

1.libyuv库完成camera的旋转

2.libyuv库实现翻转

3.libyuv库实现缩放

4.libyuv库实现裁剪


一、下拉google官方的libyuv库代码

官方地址 https://chromium.googlesource.com/libyuv/libyuv

如果打不开打不开,可以去 github 上下载:https://github.com/lemenkov/libyuv

下拉完成后目录如下所示:

主要我们用到的是include和source目录内容

二、在android项目中集成libyuv库

1.环境配置

首先配置方面要支持ndk,所以需要下载cmake和ndk配置,如下:

然后下面的集成流程是根据Android Studio Electric Eel | 2022.1.1 Patch 2版本进行的,不同版本可以稍有差异

2.拷贝libyuv源码文件

将include的文件和source文件拷贝到项目中,我这边是专门在cpp目录下建了一个libyuv文件夹,然后将include文件夹和source文件夹拷贝进来,如下:


3.配置cmake libyuv相关的链接编译等 

首先我的cmake路径和libyuv是在同一目录下,这个老版本android studio和新版本有所差异,注意分辨,和下面的cmake中配置libyuv路径有关,然后我这边是以同一目录下进行配置的,配置文件如下所示:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.6.0)

# Declares and names the project.

project("xxx")

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

set(baseCppPath "libyuv")

SET(ly_src_dir ${baseCppPath})
FILE(GLOB_RECURSE ly_source_files ${ly_src_dir}/*.cc)
LIST(SORT ly_source_files)

add_library( # Sets the name of the library.
        liveassistant

        # Sets the library as a shared library.
        SHARED

        # Provides a relative path to your source file(s).
        ${ly_source_files}
        native-lib.cpp)

include_directories(${baseCppPath}/include)

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
        log-lib

        # Specifies the name of the NDK library that
        # you want CMake to locate.
        log)

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
        xxx

        # Links the target library to the log library
        # included in the NDK.
        jnigraphics
        ${log-lib})

如果想详细了解上面cmake配置的具体内容可参考:https://gonglipeng.blog.csdn.net/article/details/120026867

三、使用libyuv库

1.libyuv库完成camera的旋转

首先在jni中的cpp文件中添加头文件,如下:

头文件

#include <jni.h>

#include <string>

#include <libyuv.h>

#include <android/bitmap.h>

然后是cpp文件的具体实现

extern "C"

JNIEXPORT void JNICALL

Java_xxx_xxx_xxx_xxx_YuvNativeUtil_rotate(JNIEnv *env, jclass thiz, jobject y,

                                                          jobject u,

                                                          jobject v, jint yStride, jint uStride,

                                                          jint vStride,

                                                          jobject yOut, jobject uOut, jobject vOut,

                                                          jint yOutStride, jint uOutStride,

                                                          jint vOutStride,

                                                          jint width, jint height,

                                                          jint rotationMode) {

    uint8_t *yNative = (uint8_t *) env->GetDirectBufferAddress(y);

    uint8_t *uNative = (uint8_t *) env->GetDirectBufferAddress(u);

    uint8_t *vNative = (uint8_t *) env->GetDirectBufferAddress(v);

    uint8_t *yOutNative = (uint8_t *) env->GetDirectBufferAddress(yOut);

    uint8_t *uOutNative = (uint8_t *) env->GetDirectBufferAddress(uOut);

    uint8_t *vOutNative = (uint8_t *) env->GetDirectBufferAddress(vOut);

    libyuv::I420Rotate(yNative, yStride,

                       uNative, uStride,

                       vNative, vStride,

                       yOutNative, yOutStride,

                       uOutNative, uOutStride,

                       vOutNative, vOutStride,

                       width, height,

                       libyuv::RotationMode(rotationMode));

}

上面xxx对应自己的路径名

然后是java层代码实现,先加载so包:

static {

        System.loadLibrary("xxx");

    }

然后实现java代码,如下:

   public static YuvFrame rotate(Image image, int rotationMode) {

       YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(image.getWidth(),

               image.getHeight(), rotationMode);

       rotate(image.getPlanes()[0].getBuffer(),

               image.getPlanes()[1].getBuffer(),

               image.getPlanes()[2].getBuffer(),

               image.getPlanes()[0].getRowStride(),

               image.getPlanes()[1].getRowStride(),

               image.getPlanes()[2].getRowStride(),

               outFrame.getY(),

               outFrame.getU(),

               outFrame.getV(),

               outFrame.getYStride(),

               outFrame.getUStride(),

               outFrame.getVStride(),

               image.getWidth(),

               image.getHeight(),

               rotationMode);

       return outFrame;

   }

   public static YuvFrame rotate(YuvFrame yuvFrame, int rotationMode) {

       YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(yuvFrame.getWidth(),

               yuvFrame.getHeight(), rotationMode);

       rotate(yuvFrame.getY(),

               yuvFrame.getU(),

               yuvFrame.getV(),

               yuvFrame.getYStride(),

               yuvFrame.getUStride(),

               yuvFrame.getVStride(),

               outFrame.getY(),

               outFrame.getU(),

               outFrame.getV(),

               outFrame.getYStride(),

               outFrame.getUStride(),

               outFrame.getVStride(),

               yuvFrame.getWidth(),

               yuvFrame.getHeight(),

               rotationMode);

       return outFrame;

   }

   private static native void rotate(ByteBuffer y,

                                     ByteBuffer u,

                                     ByteBuffer v,

                                     int yStride,

                                     int uStride,

                                     int vStride,

                                     ByteBuffer yOut,

                                     ByteBuffer uOut,

                                     ByteBuffer vOut,

                                     int yOutStride,

                                     int uOutStride,

                                     int vOutStride,

                                     int width,

                                     int height,

                                     int rotationMode);

上面两种实现一是直接传入camera2中通过OnImageAvailableListener回调获取的Image,部分代码如下:

另一种方式是传递中间数据YuvFrame,然后写存储数据的YuvFrame类,如下,注意是kotlin方式写的

class YuvFrame {

    lateinit var y: ByteBuffer; private set

    lateinit var u: ByteBuffer; private set

    lateinit var v: ByteBuffer; private set

    var yStride: Int = 0private set

    var uStride: Int = 0private set

    var vStride: Int = 0private set

    var width: Int = 0private set

    var height: Int = 0private set

    fun fill(

        y: ByteBuffer,

        u: ByteBuffer,

        v: ByteBuffer,

        yStride: Int,

        uStride: Int,

        vStride: Int,

        width: Int,

        height: Int

    ) {

        this.y = y

        this.u = u

        this.v = v

        this.yStride = yStride

        this.uStride = uStride

        this.vStride = vStride

        this.width = width

        this.height = height

    }

    fun fill(image: Image) {

        for (i in 0 until 3) {

            when (i) {

                0 -> {

                    y = image.planes[i].buffer

                    yStride = image.planes[i].rowStride

                }

                1 -> {

                    u = image.planes[i].buffer

                    uStride = image.planes[i].rowStride

                }

                2 -> {

                    v = image.planes[i].buffer

                    vStride = image.planes[i].rowStride

                }

            }

        }

        width = image.width

        height = image.height

    }

    /** experimental method */

    fun fill(width: Int, height: Int, data: ByteArray) {

        this.width = width

        this.height = height

        val yArr = ByteArray(width * height)

        val uArr = ByteArray(width * height / 4)

        val vArr = ByteArray(width * height / 4)

        System.arraycopy(data, 0, yArr, 0, yArr.size)

        System.arraycopy(data, yArr.size, uArr, 0, uArr.size)

        System.arraycopy(data, yArr.size + uArr.size, vArr, 0, uArr.size)

        y = ByteBuffer.allocateDirect(yArr.size).put(yArr)

        u = ByteBuffer.allocateDirect(uArr.size).put(uArr)

        v = ByteBuffer.allocateDirect(vArr.size).put(vArr)

        y.position(0)

        u.position(0)

        v.position(0)

    }

    fun asArray(): ByteArray {

        var array: ByteArray

        val yPos = y.position()

        val uPos = u.position()

        val vPos = v.position()

        try {

            array =

                ByteBuffer.allocate(y.capacity() + u.capacity() + v.capacity()).put(y).put(u).put(v)

                    .array()

            y.position(yPos)

            u.position(uPos)

            v.position(vPos)

        catch (e: Exception) {

            array = ByteArray(size())

            y.get(array, 0, y.remaining())

            y.position(yPos)

            u.get(array, y.remaining(), u.remaining())

            u.position(uPos)

            v.get(array, y.remaining() + u.remaining(), v.remaining())

            v.position(vPos)

        }

        return array

    }

    fun size() = y.remaining() + u.remaining() + v.remaining()

    fun free() {

        y = ByteBuffer.allocate(1)

        u = ByteBuffer.allocate(1)

        v = ByteBuffer.allocate(1)

        yStride = 0

        uStride = 0

        vStride = 0

        width = 0

        height = 0

    }

}

2.libyuv库实现翻转

翻转有水平翻转和垂直翻转,垂直翻转可以直接通过旋转实现,水平翻转需要重新调用libyuv库,代码如下所示:

extern "C"

JNIEXPORT void JNICALL

Java_xxx_xxx_xxx_utils_YuvNativeUtil_mirrorH(JNIEnv *env, jclass thiz, jobject y,

                                                           jobject u,

                                                           jobject v, jint yStride, jint uStride,

                                                           jint vStride,

                                                           jobject yOut, jobject uOut, jobject vOut,

                                                           jint yOutStride, jint uOutStride,

                                                           jint vOutStride,

                                                           jint width, jint height) {

    uint8_t *yNative = (uint8_t *) env->GetDirectBufferAddress(y);

    uint8_t *uNative = (uint8_t *) env->GetDirectBufferAddress(u);

    uint8_t *vNative = (uint8_t *) env->GetDirectBufferAddress(v);

    uint8_t *yOutNative = (uint8_t *) env->GetDirectBufferAddress(yOut);

    uint8_t *uOutNative = (uint8_t *) env->GetDirectBufferAddress(uOut);

    uint8_t *vOutNative = (uint8_t *) env->GetDirectBufferAddress(vOut);

    libyuv::I420Mirror(yNative, yStride,

                       uNative, uStride,

                       vNative, vStride,

                       yOutNative, yOutStride,

                       uOutNative, uOutStride,

                       vOutNative, vOutStride,

                       width, height);

}

public static YuvFrame mirrorH(Image image) {

        YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(image.getWidth(), image.getHeight());

        mirrorH(image.getPlanes()[0].getBuffer(),

                image.getPlanes()[1].getBuffer(),

                image.getPlanes()[2].getBuffer(),

                image.getPlanes()[0].getRowStride(),

                image.getPlanes()[1].getRowStride(),

                image.getPlanes()[2].getRowStride(),

                outFrame.getY(),

                outFrame.getU(),

                outFrame.getV(),

                outFrame.getYStride(),

                outFrame.getUStride(),

                outFrame.getVStride(),

                image.getWidth(),

                image.getHeight());

        return outFrame;

    }

    public static YuvFrame mirrorH(YuvFrame yuvFrame) {

        YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(yuvFrame.getWidth(),

                yuvFrame.getHeight());

        mirrorH(yuvFrame.getY(),

                yuvFrame.getU(),

                yuvFrame.getV(),

                yuvFrame.getYStride(),

                yuvFrame.getUStride(),

                yuvFrame.getVStride(),

                outFrame.getY(),

                outFrame.getU(),

                outFrame.getV(),

                outFrame.getYStride(),

                outFrame.getUStride(),

                outFrame.getVStride(),

                yuvFrame.getWidth(),

                yuvFrame.getHeight());

        return outFrame;

    }

    public static YuvFrame mirrorV(Image image) {

        YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(image.getWidth(), image.getHeight());

        rotate(image.getPlanes()[0].getBuffer(),

                image.getPlanes()[1].getBuffer(),

                image.getPlanes()[2].getBuffer(),

                image.getPlanes()[0].getRowStride(),

                image.getPlanes()[1].getRowStride(),

                image.getPlanes()[2].getRowStride(),

                outFrame.getY(),

                outFrame.getU(),

                outFrame.getV(),

                outFrame.getYStride(),

                outFrame.getUStride(),

                outFrame.getVStride(),

                image.getWidth(),

                -image.getHeight(),

                0);

        return outFrame;

    }

    public static YuvFrame mirrorV(YuvFrame yuvFrame) {

        YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(yuvFrame.getWidth(),

                yuvFrame.getHeight());

        rotate(yuvFrame.getY(),

                yuvFrame.getU(),

                yuvFrame.getV(),

                yuvFrame.getYStride(),

                yuvFrame.getUStride(),

                yuvFrame.getVStride(),

                outFrame.getY(),

                outFrame.getU(),

                outFrame.getV(),

                outFrame.getYStride(),

                outFrame.getUStride(),

                outFrame.getVStride(),

                yuvFrame.getWidth(),

                -yuvFrame.getHeight(),

                0);

        return outFrame;

    }

    private static native void mirrorH(ByteBuffer y,

                                       ByteBuffer u,

                                       ByteBuffer v,

                                       int yStride,

                                       int uStride,

                                       int vStride,

                                       ByteBuffer yOut,

                                       ByteBuffer uOut,

                                       ByteBuffer vOut,

                                       int yOutStride,

                                       int uOutStride,

                                       int vOutStride,

                                       int width,

                                       int height);

3.libyuv库实现缩放

注意宽高必须为偶数,不然会出现花屏,代码如下所示:

extern "C"

JNIEXPORT void JNICALL

Java_xxx_xxx_xxx_utils_YuvNativeUtil_scale(

        JNIEnv *env, jclass thiz, jobject y, jobject u, jobject v,

        jint yStride, jint uStride, jint vStride,

        jobject yOut, jobject uOut, jobject vOut,

        jint yOutStride, jint uOutStride, jint vOutStride,

        jint srcWidth, jint srcHeight, jint dstWidth, jint dstHeight, jint filterMode) {

    uint8_t *yNative = (uint8_t *) env->GetDirectBufferAddress(y);

    uint8_t *uNative = (uint8_t *) env->GetDirectBufferAddress(u);

    uint8_t *vNative = (uint8_t *) env->GetDirectBufferAddress(v);

    uint8_t *yOutNative = (uint8_t *) env->GetDirectBufferAddress(yOut);

    uint8_t *uOutNative = (uint8_t *) env->GetDirectBufferAddress(uOut);

    uint8_t *vOutNative = (uint8_t *) env->GetDirectBufferAddress(vOut);

    libyuv::I420Scale(yNative, yStride,

                      uNative, uStride,

                      vNative, vStride,

                      srcWidth, srcHeight,

                      yOutNative, yOutStride,

                      uOutNative, uOutStride,

                      vOutNative, vOutStride,

                      dstWidth, dstHeight,

                      libyuv::FilterMode(filterMode));

}

public static YuvFrame scale(Image image, int dstWidth, int dstHeight, int filerMode) {

    YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(dstWidth, dstHeight);

    scale(image.getPlanes()[0].getBuffer(),

            image.getPlanes()[1].getBuffer(),

            image.getPlanes()[2].getBuffer(),

            image.getPlanes()[0].getRowStride(),

            image.getPlanes()[1].getRowStride(),

            image.getPlanes()[2].getRowStride(),

            outFrame.getY(),

            outFrame.getU(),

            outFrame.getV(),

            outFrame.getYStride(),

            outFrame.getUStride(),

            outFrame.getVStride(),

            image.getWidth(),

            image.getHeight(),

            dstWidth,

            dstHeight,

            filerMode);

    return outFrame;

}

public static YuvFrame scale(YuvFrame yuvFrame, int dstWidth, int dstHeight, int filerMode) {

    if (dstHeight <= 0 || dstWidth <= 0) {

        return null;

    }

    YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(dstWidth, dstHeight);

    scale(yuvFrame.getY(),

            yuvFrame.getU(),

            yuvFrame.getV(),

            yuvFrame.getYStride(),

            yuvFrame.getUStride(),

            yuvFrame.getVStride(),

            outFrame.getY(),

            outFrame.getU(),

            outFrame.getV(),

            outFrame.getYStride(),

            outFrame.getUStride(),

            outFrame.getVStride(),

            yuvFrame.getWidth(),

            yuvFrame.getHeight(),

            dstWidth,

            dstHeight,

            filerMode);

    return outFrame;

}

private static native void scale(ByteBuffer y,

                                 ByteBuffer u,

                                 ByteBuffer v,

                                 int yStride,

                                 int uStride,

                                 int vStride,

                                 ByteBuffer yOut,

                                 ByteBuffer uOut,

                                 ByteBuffer vOut,

                                 int yOutStride,

                                 int uOutStride,

                                 int vOutStride,

                                 int srcWidth,

                                 int srcHeight,

                                 int dstWidth,

                                 int dstHeight,

                                 int filterMode);

4.libyuv库实现裁剪

注意宽高和位置必须为偶数,不然会出现花屏,代码如下:

extern "C"

JNIEXPORT void JNICALL

Java_xxx_xxx_xxx_utils_YuvNativeUtil_crop(JNIEnv *env, jclass thiz, jbyteArray src_,

                                                        jobject yOut, jobject uOut, jobject vOut,

                                                        jint yOutStride, jint uOutStride,

                                                        jint vOutStride,

                                                        jint width, jint height, jint dst_width,

                                                        jint dst_height, jint left,

                                                        jint top) {

    //裁剪的区域大小不对

    if (left + dst_width > width || top + dst_height > height) {

        return;

    }

    //left和top必须为偶数,否则显示会有问题

    if (left % 2 != 0 || top % 2 != 0) {

        return;

    }

    jint src_length = env->GetArrayLength(src_);

    jbyte *src_i420_data = env->GetByteArrayElements(src_, NULL);

    uint8_t *yOutNative = (uint8_t *) env->GetDirectBufferAddress(yOut);

    uint8_t *uOutNative = (uint8_t *) env->GetDirectBufferAddress(uOut);

    uint8_t *vOutNative = (uint8_t *) env->GetDirectBufferAddress(vOut);

    libyuv::ConvertToI420((const uint8_t *) src_i420_data, width*height*3/2,

                          (uint8_t *) yOutNative, yOutStride,

                          (uint8_t *) uOutNative, uOutStride,

                          (uint8_t *) vOutNative, vOutStride,

                          left, top,

                          width, height,

                          dst_width, dst_height,

                          libyuv::kRotate0, libyuv::FOURCC_NV21);

}

/**

 * 裁剪,下面必须为偶数 不然画面会有问题

 *

 * @param src

 * @param image

 * @param cropWidth  必须为偶数

 * @param cropHeight 必须为偶数

 * @param left       必须为偶数

 * @param top        必须为偶数

 * @return

 */

public static YuvFrame crop(byte[] src, Image image, int cropWidth, int cropHeight, int left,

                            int top) {

    YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(cropWidth, cropHeight);

    crop(src,

            outFrame.getY(),

            outFrame.getU(),

            outFrame.getV(),

            outFrame.getYStride(),

            outFrame.getUStride(),

            outFrame.getVStride(),

            image.getWidth(),

            image.getHeight(),

            outFrame.getWidth(),

            outFrame.getHeight(),

            left, top);

    return outFrame;

}

public static YuvFrame crop(byte[] src, YuvFrame yuvFrame, int cropWidth, int cropHeight,

                            int left,

                            int top) {

    YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(cropWidth, cropHeight);

    crop(src,

            outFrame.getY(),

            outFrame.getU(),

            outFrame.getV(),

            outFrame.getYStride(),

            outFrame.getUStride(),

            outFrame.getVStride(),

            yuvFrame.getWidth(),

            yuvFrame.getHeight(),

            outFrame.getWidth(),

            outFrame.getHeight(),

            left, top);

    return outFrame;

}

/**

 * yuv数据的裁剪操作

 *

 * @param src        原始数据

 * @param width      原始的宽

 * @param height     原始的高

 * @param dst_width  输出的宽

 * @param dst_height 输出的高

 * @param left       裁剪的x的开始位置,必须为偶数,否则显示会有问题

 * @param top        裁剪的y的开始位置,必须为偶数,否则显示会有问题

 **/

public static native void crop(byte[] src, ByteBuffer yOut,

                               ByteBuffer uOut,

                               ByteBuffer vOut,

                               int yOutStride,

                               int uOutStride,

                               int vOutStride,

                               int width,

                               int height, int dst_width, int dst_height, int left, int top);

上面的裁剪需要传入一个原始数据的数组,得到原始数据的代码如下:

/**

     * q: 为什么要转换成NV21

     * a: 因为NV21是android系统的默认格式,而且NV21是YUV420SP格式,这种格式的特点是占用空间小,传输和存储都比较方便,适合移动设备

     * <p>

     * q: 为什么要转换成YUV420SP

     * a: 因为YUV420SP是NV21的一种变换格式,YUV420SP的特点是可以直接用于MediaCodec编码,而NV21不行

     * <p>

     * q: 为什么要转换成YUV420P

     * a: 因为YUV420P是YUV420SP的一种变换格式,YUV420P的特点是可以直接用于FFmpeg编码,而YUV420SP不行

     *

     * @param image

     * @return

     */

    public static byte[] getNV21FromImage(Image image) {

        long time1 = System.currentTimeMillis();

        int w = image.getWidth(), h = image.getHeight();

        int i420Size = w * h * 3 2;

        int picel1 = ImageFormat.getBitsPerPixel(ImageFormat.NV21);

        int picel2 = ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888);

        Image.Plane[] planes = image.getPlanes();

        //remaining0 = rowStride*(h-1)+w => 27632= 192*143+176

        int remaining0 = planes[0].getBuffer().remaining();

        int remaining1 = planes[1].getBuffer().remaining();

        //remaining2 = rowStride*(h/2-1)+w-1 =>  13807=  192*71+176-1

        int remaining2 = planes[2].getBuffer().remaining();

        //获取pixelStride,可能跟width相等,可能不相等

        int pixelStride = planes[2].getPixelStride();

        int rowOffest = planes[2].getRowStride();

        byte[] nv21 = new byte[i420Size];

        byte[] yRawSrcBytes = new byte[remaining0];

        byte[] uRawSrcBytes = new byte[remaining1];

        byte[] vRawSrcBytes = new byte[remaining2];

        planes[0].getBuffer().get(yRawSrcBytes);

        planes[1].getBuffer().get(uRawSrcBytes);

        planes[2].getBuffer().get(vRawSrcBytes);

        if (pixelStride == w) {

            //两者相等,说明每个YUV块紧密相连,可以直接拷贝

            System.arraycopy(yRawSrcBytes, 0, nv21, 0, rowOffest * h);

            System.arraycopy(vRawSrcBytes, 0, nv21, rowOffest * h, rowOffest * h / 2 1);

        else {

            byte[] ySrcBytes = new byte[w * h];

            byte[] uSrcBytes = new byte[w * h / 2 1];

            byte[] vSrcBytes = new byte[w * h / 2 1];

            for (int row = 0; row < h; row++) {

                //源数组每隔 rowOffest 个bytes 拷贝 w 个bytes到目标数组

                System.arraycopy(yRawSrcBytes, rowOffest * row, ySrcBytes, w * row, w);

                //y执行两次,uv执行一次

                if (row % 2 == 0) {

                    //最后一行需要减一

                    if (row == h - 2) {

                        System.arraycopy(vRawSrcBytes, rowOffest * row / 2, vSrcBytes, w * row / 2, w - 1);

                    else {

                        System.arraycopy(vRawSrcBytes, rowOffest * row / 2, vSrcBytes, w * row / 2, w);

                    }

                }

            }

            System.arraycopy(ySrcBytes, 0, nv21, 0, w * h);

            System.arraycopy(vSrcBytes, 0, nv21, w * h, w * h / 2 1);

        }

        return nv21;

    }

如上就是使用libyuv的旋转、翻转、缩放、裁剪的核心操作,如果需要将image转换成YuvFrame,可以如下操作,代码:

extern "C"

JNIEXPORT void JNICALL

Java_com_example_liveassistant_utils_YuvNativeUtil_convertToI420(JNIEnv *env, jclass thiz,

                                                                 jobject y, jobject u,

                                                                 jobject v, jint yStride,

                                                                 jint uStride, jint vStride,

                                                                 jint srcPixelStrideUv,

                                                                 jobject yOut, jobject uOut,

                                                                 jobject vOut,

                                                                 jint yOutStride, jint uOutStride,

                                                                 jint vOutStride,

                                                                 jint width, jint height) {

    uint8_t *yNative = (uint8_t *) env->GetDirectBufferAddress(y);

    uint8_t *uNative = (uint8_t *) env->GetDirectBufferAddress(u);

    uint8_t *vNative = (uint8_t *) env->GetDirectBufferAddress(v);

    uint8_t *yOutNative = (uint8_t *) env->GetDirectBufferAddress(yOut);

    uint8_t *uOutNative = (uint8_t *) env->GetDirectBufferAddress(uOut);

    uint8_t *vOutNative = (uint8_t *) env->GetDirectBufferAddress(vOut);

    libyuv::Android420ToI420(yNative, yStride,

                             uNative, uStride,

                             vNative, vStride,

                             srcPixelStrideUv,

                             yOutNative, yOutStride,

                             uOutNative, uOutStride,

                             vOutNative, vOutStride,

                             width, height);

}

public static YuvFrame convertToI420(Image image) {

    YuvFrame outFrame = FramesFactory.INSTANCE.instanceYuv(image.getWidth(), image.getHeight());

    convertToI420(image.getPlanes()[0].getBuffer(),

            image.getPlanes()[1].getBuffer(),

            image.getPlanes()[2].getBuffer(),

            image.getPlanes()[0].getRowStride(),

            image.getPlanes()[1].getRowStride(),

            image.getPlanes()[2].getRowStride(),

            image.getPlanes()[2].getPixelStride(),

            outFrame.getY(),

            outFrame.getU(),

            outFrame.getV(),

            outFrame.getYStride(),

            outFrame.getUStride(),

            outFrame.getVStride(),

            image.getWidth(),

            image.getHeight());

    return outFrame;

}

private static native void convertToI420(ByteBuffer y,

                                         ByteBuffer u,

                                         ByteBuffer v,

                                         int yStride,

                                         int uStride,

                                         int vStride,

                                         int srcPixelStrideUv,

                                         ByteBuffer yOut,

                                         ByteBuffer uOut,

                                         ByteBuffer vOut,

                                         int yOutStride,

                                         int uOutStride,

                                         int vOutStride,

                                         int width,

                                         int height);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/445020.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

九龙证券|多巨头竞相布局这个热门赛道,机构一致看好的概念股

华为高阶智能驾驭体系ADS 2.0版本发布。 早前&#xff0c;华为在2023华为智能轿车解决方案发布会上&#xff0c;发布了高阶智能驾驭体系 ADS 2.0。新体系将由 AITO 问界 M5 高阶智能驾驭版首发&#xff0c;并已适配阿维塔 11 全系列以及极狐阿尔法 S 全新 Hi 版等车型。 最近&…

JDBC(java数据库连接)—MySQL

文章目录 1.定义2.优势3.环境准备4.使用jdbc&#xff08;java程序操作数据库&#xff09;5.使用jdbc的操作步骤 1.定义 jdbc是一种用于执行SQL语句的java api&#xff0c;它是java中的数据库连接规范&#xff0c;为java开发人员操作数据库提供了一个标准的api&#xff0c;可以…

【Linux】系统文件接口

目录 一、C文件接口 1、fopen 2、fprintf 3、snprintf 二、系统文件IO 1、open 2、write 3、read 4、C文件接口与系统文件IO的关系 一、C文件接口 1、fopen FILE *fopen(const char *path, const char *mode); fopen 函数返回值类型为 FILE 。参数列表中&#xff0c…

优加DaaS背后,看见新的营销潮

DaaS、融合开放&#xff0c;这是京东云优加对外传递出来的两个最清晰的声音。前者对应的是能力和边界&#xff0c;后者对应的是态度和打法。两者结合&#xff0c;恰构成了京东云优加&#xff0c;或者说京东在营销侧的未来想象力。 作者|皮爷 出品|产业家 “今年我们有接近60%以…

第五章 工厂模式

文章目录 一、简单工厂模式1、传统方式实现披萨订购( 可以忽略)披萨父类 Pizza子类胡椒披萨 PepperPizza子类印度披萨 GreekPizza订购披萨 OrderPizza订购披萨的 客户端 PizzaStore运行结果传统的方式的优缺点&#xff0c;新增子类需要修改的地方牵扯太多传统方式的究极耦合 2、…

YOLOv8 更换骨干网络之 MobileNetV3

论文地址:https://arxiv.org/abs/1905.02244 代码地址:https://github.com/xiaolai-sqlai/mobilenetv3 我们展示了基于互补搜索技术和新颖架构设计相结合的下一代 MobileNets。MobileNetV3通过结合硬件感知网络架构搜索(NAS)和 NetAdapt算法对移动设计如何协同工作,利用互…

BswM模块之Ecu State Handling

文章目录 前言一、ESH是什么&#xff1f;二、基于BswM管理的ECU状态切换流程1.ECU启动2.ECU关闭 总结 前言 BswM – 基础软件模式管理模块&#xff0c; 它的职责是基于简单规则的BSW模块仲裁来自应用层sw - c或其他模块的模式请求&#xff0c;并根据仲裁结果进行相应的操作。 …

QT QPainter 绘制基本图形元件简介

1.基本图形元件 QPainter 提供了很多绘制基本图形的功能&#xff0c;包括点、直线、椭圆、矩形、曲线等&#xff0c;由这些基本的图形可以构成复杂的图形。QPainter 中提供的绘制基本图元的函数如下表所示。每个函数基本上都有多种参数形式&#xff0c;这里只列出函数名&#x…

Elastic Common Schema 和 OpenTelemetry — 无需供应商锁定即可获得更好的可观察性和安全性的途径

作者&#xff1a;Elastic 可观察性和安全团队 在 KubeCon Europe 上&#xff0c;宣布 Elastic Common Schema (ECS) 已被 OpenTelemetry (OTel) 接受作为对该项目的贡献。 目标是将 ECS 和 OpenTelemetry 的语义约定 (SemConv) 融合到一个由 OpenTelemetry 维护的开放模式中。 …

LearnOpenGL-模型加载

1.配置Assimp库。 下载Assimp&#xff0c;解压后得到 assimp-master 文件。在文件中新建一个 build 文件。使用 Cmake 生成工程文件保存在 build 中&#xff0c;从这里下载CMake&#xff0c;下载最新的即可。 打开CMake&#xff0c;选择需要源文件目录和目标目录。修改成适配…

机器学习平台、自研DPU、资源并池,火山引擎发布多云、AI基础设施与增长法宝

1、每十家大模型企业&#xff0c;七家在火山引擎云上。 2、火山引擎大模型训练云平台&#xff0c;支持万卡训练&#xff0c;集群性能提升3倍 3、火山引擎新一代自研DPU&#xff0c;实现计算、存储、网络的全组件卸载&#xff0c;释放更多资源给业务负载。 4、火山引擎与字节国内…

数据库管理软件dbeaver-ce 下载安装并离线配置

文章目录 前言数据库管理软件dbeaver-ce 下载安装并离线配置1. 概述2. 下载3. 安装4. 离线配置驱动jar包5. 链接mysql 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天…

谷歌aab包手机怎么安装教程

一、概述 bundletool是一种底层工具&#xff0c;可供 Android Studio、Android Gradle 插件和 Google Play 用于构建 Android App Bundle 文件并将 app bundle 转换为部署到设备的各种 APK。您也可以将 bundletool作为一种命令行工具&#xff0c;用于自行构建 app bundle 和重新…

【笔试强训编程题】Day2.(排序子序列 100448)和(倒置字符串 69389)

文章目录 前言 一、排序子序列 100448 题目描述 代码实现 二、倒置字符串 69389 题目描述 代码实现 总结 前言 今天让我们来练习两道经典的编程题&#xff01;&#xff01;&#xff01;&#xff01; 一、排序子序列 100448 题目描述&#xff1a;牛牛定义排序子序列为…

平台资金提现解决方案之实现支付宝单笔转账到银行卡功能

大家好&#xff0c;我是小悟 使用场景 不管是做APP、电脑网站、手机网站还是小程序&#xff0c;为了推广基本上都离不开用户分佣的场景。 换句话说就是在其平台内为每个用户设置“电子钱包”功能&#xff0c;而电子钱包在平台那里只是一串数字&#xff0c;这就需要平台为用户…

详解 ES6中 Promise 构造函数的使用

文章目录 前言什么是 Promise&#xff1f;Promise 的几种状态拆分细解 PromisePromise all&#xff08;&#xff09;方法then()方法 返回一个新的 Promise 时的状态由什么决定&#xff1f;总结 前言 Promise 是ES6 新增的一个异步调用解决方案&#xff0c;它的出现是为了解决异…

Elasticsearch的调优思路

环境&#xff1a;centos7、elasticsearch-5.6.4 1、性能调优 1.1、Linux参数调优 1.1.1、关闭交换分区 目的是防止内存置换降低性能&#xff0c;将 /etc/fstab 文件中包含 swap 的行注释掉。 #执行命令&#xff1a;注释相关 swap的行 sed -i /swap/s/^/#/ /etc/fstab#将 /etc/f…

彻底弄清FreeRTOS中的事件组(Event Groups)

​之前已经学过两个任务之间可以利用信号量、队列来通信&#xff0c;任务可以利用这两个机制等待某一个事件发生&#xff0c;但是假如需要等待多个事件发生呢&#xff1f;这就需要用到事件组了。 事件组可以让任务进入阻塞态&#xff0c;等待一个或多个事件的组合发生。当事件…

根据 cadence 设计图学习硬件知识 day02 了解飞腾 X100芯片

1. 飞腾芯片 X100的介绍 飞腾套片X100是一款微处理器的配套芯片&#xff0c;主要功能包括图形图像处理和接口扩展两类。在图形图像处理方面&#xff0c;集成了图形处理加速GPU、视频解码VPU、显示控制接口DisplayPort以及显存控制器&#xff1b;在接口扩展方面&#xff0c;支持…

【矩形面积】

题目来源&#xff1a;https://leetcode.cn/problems/rectangle-area/ 目录 矩形面积 矩形面积 题目介绍 给你 二维 平面上两个 由直线构成且边与坐标轴平行/垂直 的矩形&#xff0c;请你计算并返回两个矩形覆盖的总面积。 每个矩形由其 左下 顶点和 右上 顶点坐标表示&#xf…