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

news2024/12/24 10:17:50

目录

一、下拉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/430094.html

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

相关文章

为什么重视安全的公司都在用SSL安全证书?

我们今天来讲一讲为什么重视安全的公司都在用SSL证书 SSL证书是什么&#xff1f; SSL安全证书是由权威认证机构颁发的&#xff0c;是CA机构将公钥和相关信息写入一个文件&#xff0c;CA机构用他们的私钥对我们的公钥和相关信息进行签名后&#xff0c;将签名信息也写入这个文件…

对于数据库而言,其锁范围可以分为全局锁 、表级锁、 行级锁

一、全局锁 全局锁就是对整个数据库实例加锁。 MySQL 提供了一个加全局读锁的方法&#xff0c;命令是 Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候&#xff0c;可以使用这个命令&#xff0c;之后其他线程的以下语句会被阻塞&#xff1a;数据更新…

DOM(1)

DOM&#xff08;文档对象模型&#xff09;&#xff1a;处理可扩展标记语言(HTML或XML&#xff09;的标准编程接口&#xff0c;可以改变网页的内容、结构和样式。DOM树&#xff1a; …

ubuntu18 网络问题

在/etc/netplan/*.yaml配置文件中&#xff1a; renderer的值可以是networkd&#xff0c;或者是NetworkManager 它俩的其中一个区别为&#xff1a; networkd在图像界面&#xff0c;networking setting中不显示网卡配置。 版权简介&#xff1a; 从Ubuntu 18.04.2版本开始&…

腾讯云4核8G轻量服务器12M支持多少访客同时在线?并发数怎么算?

腾讯云轻量4核8G12M轻量应用服务器支持多少人同时在线&#xff1f;通用型-4核8G-180G-2000G&#xff0c;2000GB月流量&#xff0c;系统盘为180GB SSD盘&#xff0c;12M公网带宽&#xff0c;下载速度峰值为1536KB/s&#xff0c;即1.5M/秒&#xff0c;假设网站内页平均大小为60KB…

网络安全:网络攻击原理与方法.

网络安全&#xff1a;网络攻击原理与方法. 网络攻击&#xff1a;是损害网络系统安全属性的危害行为。危害行为导致网络系统的机密性、完整性、可控性、真实性、抗抵赖性等受到不同程度的破坏。 目录&#xff1a; 常见的危害行为有四个基本类型&#xff1a; 网络攻击模型&…

项目实践 | 行人跟踪与摔倒检测报警

项目实践 | 行人跟踪与摔倒检测报警 小白学视觉 7月7日 原文地址&#xff1a;项目实践 | 行人跟踪与摔倒检测报警 1.简介 本项目的目的是为了给大家提供跟多的实战思路&#xff0c;抛砖引玉为大家提供一个案例&#xff0c;也希望读者可以根据该方法实现更多的思想与想法&…

为什么Uber从PostgreSQL换成了MySQL

说明&#xff1a;本文翻译自Why Uber Engineering Switched from Postgres to MySQL 引言 Uber的早期架构包括一个用Python编写的单一后端应用程序&#xff0c;它使用Postgres进行数据持久化。从那时起&#xff0c;Uber的架构发生了重大变化&#xff0c;转向了微服务和新数据…

比例放大器设置接线US-DAS1/US-DAS2

US-DAS1、US-DAS2比例放大器接线定义 1 CMD 指令 2 CMD- 指令- 3/4/5 N.C. 不接 6 ENA 使能 7 VREF_5V 参考电压5V 8 VREF_0V 参考电压0V 9 SOL_A 电磁铁A 10 SOL_A- 电磁铁A- 11 PWR 电源 12 PWR- 电源- 13 SOL_B- 电磁铁B- 15 RS485_A - 16 RS485_B -

LeetCode-盛最多水的容器-11题

LeetCode-盛最多水的容器-11题 题目中要求计算最大面积&#xff0c;即需要选择对应的长和宽。 最终解决方法&#xff1a;使用对撞指针 对撞指针的概念&#xff1a;是指在数组的两个端引入两个指针&#xff0c;左指针不断向右移动&#xff0c;右指针不断向左移动。最终到达两个…

Spring AOP切入点表达式

先来认识两个概念吧&#xff08;其实Spring AOP实现功能增强的方式就是代理模式&#xff09; 目标对象(Target)&#xff1a;原始功能去掉共性功能对应的类产生的对象&#xff0c;这种对象是无法直接完成最终工作的代理(Proxy)&#xff1a;目标对象无法直接完成工作&#xff0c;…

【学术搬砖】第一期

“一期一会” —— 珍惜我们遇见的论文&#xff0c;把和每个论文的相遇&#xff0c;当做一种缘分。我们会定期推荐若干优质学术论文&#xff0c;并分享一段总结&#xff0c;非常欢迎提出任何建议和想法。 【NeurIPS2022】ShufflfleMixer: An Effificient ConvNet for Image Su…

R -- 时序分析

brief 横截面数据对应着某个时间点的数据。 纵向的数据对应着一系列时间点的数据&#xff0c;某个变量随着时间的变动被反复测量。 研究纵向数据&#xff0c;也许会得到“时间”的答案。 描述时间序列 生成时序对象 x <- runif(20)ts(x) ts(x,frequency 12) ts(x,frequen…

python整合Django框架初试

1.安装 以下是安装Django的步骤&#xff1a; 确认Python已经安装&#xff1a;在终端&#xff08;Mac/Linux&#xff09;或命令提示符&#xff08;Windows&#xff09;中输入python -V&#xff0c;如果出现Python版本号&#xff0c;则已经安装Python&#xff1b;如果未安装&…

Nginx配置与应用

Nginx 是开源、高性能、高可靠的 Web 和反向代理服务器&#xff0c;而且支持热部署&#xff0c;几乎可以做到 7 * 24 小时不间断运行&#xff0c;即使运行几个月也不需要重新启动&#xff0c;还能在不间断服务的情况下对软件版本进行热更新。性能是 Nginx 最重要的考量&#xf…

PCL源码剖析 -- 欧式聚类

PCL源码剖析 – 欧式聚类 参考&#xff1a; 1. pcl Euclidean Cluster Extraction教程 2. 欧式聚类分析 3. pcl-api源码 4. 点云欧式聚类 5. 本文完整工程地址 可视化结果 一. 理论 聚类方法需要将无组织的点云模型P划分为更小的部分&#xff0c;以便显著减少P的总体处理时间…

centos7.6部署ELK集群(三)之logstash7.7.0部署

32.5. 部署logstash7.7.0&#xff08;在主节点上操作&#xff09; 32.6.1. 下载logstash7.7.0 Logstash 官方下载地址&#xff1a;https://www.elastic.co/cn/downloads/logstash 32.6.2. 解压至安装目录 tar –xvf logstash-7.7.0.tar.gz -C /vmdata/ 32.6.3. 修改logstas…

逍遥自在学C语言 位运算符 “|“ 的5种高级用法

前言 在上一篇文章中&#xff0c;我们介绍了&运算符的高级用法&#xff0c;本篇文章&#xff0c;我们将介绍| 运算符的一些高级用法。 一、人物简介 第一位闪亮登场&#xff0c;有请今后会一直教我们C语言的老师 —— 自在。 第二位上场的是和我们一起学习的小白程序猿 —…

JAVA入坑之异常处理

目录 一、程序错误 二、异常 2.1概述 2.2产生原因 2.3Java 异常层次结构 Error Exception 2.3.1非受检异常 2.3.2受检异常 三、异常处理机制 3.1概述 ​编辑 调用栈Call Stack 3.2异常类型的实现 3.3异常处理的关键字&#xff1a; 3.3.1try-catch Block ​编辑 …

推荐系统概述

1.推荐系统的意义 随着移动互联网的飞速发展&#xff0c;人们已经处于一个信息过载的时代。在这个时代中&#xff0c;信息的生产者很难将信息呈现在对它们感兴趣的信息消费者面前&#xff0c;而对于信息消费者也很难从海量的信息中找到自己感兴趣的信息。推荐系统就是一个将信息…