第 20 篇 RK 平台 NPU / 硬件编解码驱动适配与安卓调用

目录

[开篇先搞懂:RK3568 的 NPU 和 VPU 到底是什么?](#开篇先搞懂:RK3568 的 NPU 和 VPU 到底是什么?)

[1. NPU(Neural Processing Unit,神经网络处理器)](#1. NPU(Neural Processing Unit,神经网络处理器))

[2. VPU(Video Processing Unit,视频处理单元)](#2. VPU(Video Processing Unit,视频处理单元))

小白必记

[第一部分:RK NPU 驱动适配与安卓 AI 推理实战](#第一部分:RK NPU 驱动适配与安卓 AI 推理实战)

[一、NPU 驱动适配与环境搭建](#一、NPU 驱动适配与环境搭建)

[1. 设备树配置,使能 NPU 模块](#1. 设备树配置,使能 NPU 模块)

[2. 内核配置,开启 NPU 驱动](#2. 内核配置,开启 NPU 驱动)

[3. 验证 NPU 驱动是否正常工作](#3. 验证 NPU 驱动是否正常工作)

[4. RKNN Toolkit2 环境搭建](#4. RKNN Toolkit2 环境搭建)

[5. 模型转换:把 ONNX 模型转换成 RKNN 模型](#5. 模型转换:把 ONNX 模型转换成 RKNN 模型)

[二、安卓系统 NPU 推理环境搭建](#二、安卓系统 NPU 推理环境搭建)

[1. 安卓项目集成 RKNN SDK](#1. 安卓项目集成 RKNN SDK)

[2. 安卓 NPU 推理核心代码实现](#2. 安卓 NPU 推理核心代码实现)

[3. 安卓 App 调用](#3. 安卓 App 调用)

[三、NPU 优化技巧](#三、NPU 优化技巧)

[第二部分:RK VPU 硬件编解码驱动适配与安卓调用](#第二部分:RK VPU 硬件编解码驱动适配与安卓调用)

[一、VPU 驱动适配与环境搭建](#一、VPU 驱动适配与环境搭建)

[1. 设备树配置,使能 VPU 模块](#1. 设备树配置,使能 VPU 模块)

[2. 内核配置,开启 VPU 相关驱动](#2. 内核配置,开启 VPU 相关驱动)

[3. 验证 VPU 驱动是否正常工作](#3. 验证 VPU 驱动是否正常工作)

[4. MPP 媒体处理平台环境搭建](#4. MPP 媒体处理平台环境搭建)

二、安卓系统硬件编解码实现

[1. 编码器初始化](#1. 编码器初始化)

[2. 编码一帧图像](#2. 编码一帧图像)

[3. 编码器释放](#3. 编码器释放)

[4. 安卓 App 调用](#4. 安卓 App 调用)

[三、VPU 编解码优化技巧](#三、VPU 编解码优化技巧)

结尾说两句


大家好,我是黒漂技术佬。上一篇我们讲了驱动的性能和功耗优化,很多兄弟后台问:

"佬,RK3568 的 NPU 和 VPU 到底怎么用?我想做人脸识别、视频编解码,用 CPU 跑太慢了,功耗还高,有没有完整的适配和调用教程?"

问的太对了!瑞芯微 RK 系列芯片的核心竞争力,就是内置的NPU 神经网络处理器 和VPU 视频编解码单元,这也是它能在工业、AIoT、边缘计算领域广泛应用的核心原因。很多新手买了 RK 开发板,却只会用 CPU 跑程序,完全浪费了 RK 芯片的核心硬件加速能力,用 CPU 做人脸识别,帧率不到 1 帧,用 NPU 能跑到 30 帧,差距天差地别。

今天这篇,我就给你讲透 RK3568 的 NPU 和 VPU 硬件加速模块,从驱动适配、SDK 环境搭建,到安卓系统的完整调用流程,手把手带你实现 NPU 人脸识别推理和 VPU 硬件编解码,充分发挥 RK 芯片的硬件优势。


开篇先搞懂:RK3568 的 NPU 和 VPU 到底是什么?

1. NPU(Neural Processing Unit,神经网络处理器)

RK3568 内置了一颗自研的 NPU,算力高达1TOPS,支持 INT8/FP16 量化,兼容 Caffe/TensorFlow/TFLite/PyTorch/ONNX 等主流的 AI 框架,专门用来做 AI 神经网络模型的推理加速,比如人脸识别、物体检测、车牌识别、语音识别等 AI 场景。

核心优势:

  • 相比 CPU,AI 推理速度提升几十倍,帧率更高;
  • 相比 GPU,功耗极低,NPU 跑推理的功耗,只有 CPU 的 1/10,适合边缘设备长时间运行;
  • 瑞芯微提供了完整的工具链,支持主流框架的模型转换,不用自己写算子,开发门槛极低。

2. VPU(Video Processing Unit,视频处理单元)

RK3568 内置了独立的硬件视频编解码器,也就是 VPU,支持4K@60fps H.265/H.264 解码 ,1080P@60fps H.265/H.264 编码,所有的编解码操作,全部由硬件完成,完全不占用 CPU 资源。

核心优势:

  • 硬件编解码,CPU 占用率几乎为 0,即使同时编解码多路视频,系统也不会卡顿;
  • 超低功耗,硬件编解码的功耗,只有 CPU 软编解码的 1/20;
  • 瑞芯微提供了完整的 MPP(Media Process Platform)媒体处理平台,封装了标准的 API,安卓和 Linux 系统都能直接调用,不用关心底层驱动细节。

小白必记

RK 官方已经把 NPU 和 VPU 的底层驱动,全部集成到了 SDK 里,我们不需要自己写驱动代码,只需要在设备树里使能对应的模块,搭建好对应的 SDK 环境,调用官方提供的 API 就行,开发门槛极低,不用懂底层驱动细节,也能快速上手。


第一部分:RK NPU 驱动适配与安卓 AI 推理实战

一、NPU 驱动适配与环境搭建

1. 设备树配置,使能 NPU 模块

RK3568 的 SDK 里,已经默认使能了 NPU 模块,我们只需要确认设备树里的 NPU 节点是开启的,打开rk3568.dtsi,确认下面的节点:

dts

复制代码
&npu {
    status = "okay";
    assigned-clocks = <&cru CLK_NPU_CORE>;
    assigned-clock-rates = <600000000>; // NPU核心时钟,600MHz
};
  • status = "okay":使能 NPU 模块,默认是开启的,不用改;
  • assigned-clock-rates:NPU 的核心时钟,最高可以设到 1GHz,默认 600MHz,平衡性能和功耗。
2. 内核配置,开启 NPU 驱动

确认内核配置里,已经开启了 NPU 驱动:

bash

运行

复制代码
cd kernel
make ARCH=arm64 menuconfig

进入以下路径,开启 NPU 驱动:

plaintext

复制代码
Device Drivers  --->
    Neural Processing Units  --->
        <*> Rockchip NPU support

默认情况下,RK SDK 已经开启了这个配置,我们只需要确认就行,然后编译内核,烧录到开发板。

3. 验证 NPU 驱动是否正常工作

开发板重启后,进入 ADB shell,验证 NPU 驱动是否正常加载:

bash

运行

复制代码
adb shell
su
# 查看NPU设备节点
ls /dev/dri/renderD128
# 查看NPU驱动日志
dmesg | grep rknpu

能看到/dev/dri/renderD128设备节点,内核日志里没有 NPU 的报错,说明 NPU 驱动已经正常加载,可以正常使用了。

4. RKNN Toolkit2 环境搭建

瑞芯微给我们提供了RKNN Toolkit2工具链,用来把主流 AI 框架的模型,转换成 RK 平台专用的 RKNN 模型,并且提供了 Python/C/C++ API,用来加载模型做推理。

环境搭建步骤:

  1. 下载 RKNN Toolkit2:从瑞芯微官方 GitHub 仓库下载,地址:https://github.com/rockchip-linux/rknn-toolkit2
  2. 安装 Python 环境:推荐 Ubuntu 20.04,Python 3.8,安装对应的依赖库;
  3. 安装 RKNN Toolkit2:按照官方文档,安装 whl 包,完成环境搭建。
5. 模型转换:把 ONNX 模型转换成 RKNN 模型

我们以人脸识别的模型为例,用 RKNN Toolkit2 把预训练的 ONNX 模型,转换成 RK3568 专用的 RKNN 模型,核心代码片段:

python

运行

复制代码
from rknn.api import RKNN

# 创建RKNN对象
rknn = RKNN(verbose=True)

# 模型配置
rknn.config(
    mean_values=[[0, 0, 0]],
    std_values=[[255, 255, 255]],
    target_platform='rk3568',
    quantized_dtype='asymmetric_quantized-u8' # INT8量化,提升推理速度
)

# 加载ONNX模型
ret = rknn.load_onnx(model='face_recognize.onnx')
if ret != 0:
    print('模型加载失败')
    exit(ret)

# 模型编译,生成RKNN模型
ret = rknn.build(do_quantization=True, dataset='dataset.txt')
if ret != 0:
    print('模型编译失败')
    exit(ret)

# 导出RKNN模型
ret = rknn.export_rknn('face_recognize.rknn')
if ret != 0:
    print('模型导出失败')
    exit(ret)

# 释放资源
rknn.release()

执行完成后,就会生成face_recognize.rknn模型文件,这个模型可以直接在 RK3568 的 NPU 上运行。

二、安卓系统 NPU 推理环境搭建

RK 官方提供了安卓平台的RKNN API,支持在安卓 App 里直接加载 RKNN 模型,调用 NPU 做推理,我们只需要把对应的库和头文件,集成到 Android Studio 项目里就行。

1. 安卓项目集成 RKNN SDK
  1. 从 RK 官方的rknpu2仓库,下载安卓平台的 SDK,地址:https://github.com/rockchip-linux/rknpu2
  2. 在 Android Studio 项目里,添加对应的库文件:
    • 把librknn_api.so和librknn_runtime.so放到app/src/main/jniLibs/arm64-v8a/目录下;
    • 把rknn_api.h头文件放到app/src/main/cpp/include/目录下;
  3. 配置 CMakeLists.txt,链接 RKNN 库。
2. 安卓 NPU 推理核心代码实现

我们用 C++ JNI 实现模型的加载和推理,核心代码片段:

cpp

运行

复制代码
#include <jni.h>
#include <string>
#include "rknn_api.h"
#include <android/bitmap.h>

// 全局变量
rknn_context ctx = 0;
rknn_input_output_num io_num;
rknn_tensor_attr input_attrs[1];
rknn_tensor_attr output_attrs[4];

// 加载RKNN模型
extern "C"
JNIEXPORT jint JNICALL
Java_com_heipiao_npudemo_NpuJni_loadModel(JNIEnv *env, jobject thiz, jbyteArray model_data)
{
    // 读取模型数据
    jbyte *model_buf = env->GetByteArrayElements(model_data, NULL);
    int model_len = env->GetArrayLength(model_data);

    // 初始化RKNN运行时
    int ret = rknn_init(&ctx, model_buf, model_len, 0, NULL);
    if (ret != RKNN_SUCC) {
        printf("rknn_init失败,错误码:%d\n", ret);
        return -1;
    }

    // 获取模型的输入输出信息
    ret = rknn_query(ctx, RKNN_QUERY_IN_OUT_NUM, &io_num, sizeof(io_num));
    if (ret != RKNN_SUCC) {
        printf("rknn_query失败\n");
        return -1;
    }

    // 获取输入输出张量属性
    memset(input_attrs, 0, sizeof(input_attrs));
    for (int i = 0; i < io_num.n_input; i++) {
        input_attrs[i].index = i;
        rknn_query(ctx, RKNN_QUERY_INPUT_ATTR, &input_attrs[i], sizeof(rknn_tensor_attr));
    }

    memset(output_attrs, 0, sizeof(output_attrs));
    for (int i = 0; i < io_num.n_output; i++) {
        output_attrs[i].index = i;
        rknn_query(ctx, RKNN_QUERY_OUTPUT_ATTR, &output_attrs[i], sizeof(rknn_tensor_attr));
    }

    env->ReleaseByteArrayElements(model_data, model_buf, 0);
    printf("模型加载成功,输入:%d,输出:%d\n", io_num.n_input, io_num.n_output);
    return 0;
}

// 执行推理
extern "C"
JNIEXPORT jobjectArray JNICALL
Java_com_heipiao_npudemo_NpuJni_inference(JNIEnv *env, jobject thiz, jobject bitmap)
{
    // 1. 从Bitmap获取图像数据,预处理
    AndroidBitmapInfo info;
    void *pixels;
    AndroidBitmap_getInfo(env, bitmap, &info);
    AndroidBitmap_lockPixels(env, bitmap, &pixels);

    // 图像预处理:缩放、归一化、格式转换,符合模型的输入要求
    unsigned char *input_data = preprocess_image(pixels, info.width, info.height, input_attrs);

    AndroidBitmap_unlockPixels(env, bitmap);

    // 2. 设置输入数据
    rknn_input inputs[1];
    memset(inputs, 0, sizeof(inputs));
    inputs[0].index = 0;
    inputs[0].type = RKNN_TENSOR_UINT8;
    inputs[0].size = input_attrs[0].size;
    inputs[0].fmt = RKNN_TENSOR_NHWC;
    inputs[0].buf = input_data;

    rknn_inputs_set(ctx, io_num.n_input, inputs);

    // 3. 执行NPU推理
    rknn_output outputs[4];
    memset(outputs, 0, sizeof(outputs));
    for (int i = 0; i < io_num.n_output; i++) {
        outputs[i].want_float = 1;
    }
    int ret = rknn_run(ctx, NULL);
    ret = rknn_outputs_get(ctx, io_num.n_output, outputs, NULL);

    // 4. 后处理:解析推理结果,比如人脸框、关键点、特征值
    jobjectArray result = postprocess_result(env, outputs, output_attrs);

    // 5. 释放资源
    rknn_outputs_release(ctx, io_num.n_output, outputs);
    free(input_data);

    return result;
}

// 释放模型
extern "C"
JNIEXPORT jint JNICALL
Java_com_heipiao_npudemo_NpuJni_releaseModel(JNIEnv *env, jobject thiz)
{
    if (ctx != 0) {
        rknn_destroy(ctx);
        ctx = 0;
    }
    return 0;
}
3. 安卓 App 调用

在 Java 层,我们只需要加载模型,传入摄像头采集的 Bitmap,就能调用 NPU 做推理,拿到人脸识别的结果,核心代码:

java

运行

复制代码
// 初始化NPU,加载模型
NpuJni npuJni = new NpuJni();
InputStream is = getAssets().open("face_recognize.rknn");
byte[] modelData = new byte[is.available()];
is.read(modelData);
npuJni.loadModel(modelData);

// 从摄像头获取Bitmap,执行推理
Bitmap frame = getCameraFrame();
FaceResult[] results = npuJni.inference(frame);

// 处理推理结果,绘制人脸框,做特征匹配
drawFaceRect(frame, results);
if (isFaceMatch(results)) {
    // 匹配成功,开锁
    doorLock.unlock();
}

三、NPU 优化技巧

  1. 模型量化:优先使用 INT8 量化,相比 FP16,推理速度提升一倍,功耗降低一半,精度损失很小,完全满足边缘场景的需求;
  2. 输入尺寸优化 :在满足精度的前提下,尽量减小模型的输入尺寸,比如 640640 改成 320320,推理速度能提升 4 倍;
  3. 模型预处理 / 后处理优化:把图像的预处理、后处理,放到 RGA2D 硬件加速器上执行,不要用 CPU 做像素运算,进一步提升速度;
  4. 多线程优化:把图像采集、预处理、推理、后处理,做成流水线多线程,最大化 NPU 的利用率,提升帧率;
  5. NPU 频率调整:对帧率要求高的场景,把 NPU 核心时钟调到 1GHz,最大化性能;对功耗要求高的场景,调到 300MHz,平衡性能和功耗。

第二部分:RK VPU 硬件编解码驱动适配与安卓调用

一、VPU 驱动适配与环境搭建

1. 设备树配置,使能 VPU 模块

RK3568 的 SDK 里,已经默认使能了 VPU 和编解码模块,我们只需要确认设备树里的相关节点是开启的:

dts

复制代码
&video_encoder {
    status = "okay";
};

&video_decoder {
    status = "okay";
};

&rkvdec {
    status = "okay";
};

&rkvenc {
    status = "okay";
};

这些节点默认都是status = "okay",不用我们修改,只需要确认就行。

2. 内核配置,开启 VPU 相关驱动

确认内核配置里,开启了 VPU、编解码、DMA 相关的配置,RK SDK 默认已经开启,我们只需要确认:

plaintext

复制代码
Device Drivers  --->
    Multimedia support  --->
        [*] Video capture adapters  --->
            [*] Rockchip Video Decoder Driver
            [*] Rockchip Video Encoder Driver
        [*] Media Controller support
        [*] V4L2 sub-device userspace API
3. 验证 VPU 驱动是否正常工作

开发板重启后,进入 ADB shell,验证 VPU 驱动是否正常加载:

bash

运行

复制代码
adb shell
su
# 查看编解码设备节点
ls /dev/video*
# 查看VPU驱动日志
dmesg | grep rkvdec
dmesg | grep rkvenc

能看到对应的 video 设备节点,内核日志没有报错,说明 VPU 驱动已经正常加载。

4. MPP 媒体处理平台环境搭建

瑞芯微给我们提供了MPP(Media Process Platform) 媒体处理平台,封装了硬件编解码的标准 API,支持 C/C++ 调用,安卓和 Linux 系统都能使用,我们不用关心底层的 VPU 驱动细节,直接调用 API 就行。

  1. 下载 RK MPP SDK:从瑞芯微官方 GitHub 仓库下载,地址:https://github.com/rockchip-linux/mpp
  2. 编译安卓平台的 MPP 库,生成librockchip_mpp.so动态库;
  3. 把对应的库文件和头文件,集成到 Android Studio 项目里。

二、安卓系统硬件编解码实现

我们以 H.264 视频编码为例,实现摄像头采集的画面,通过 VPU 硬件编码成 H.264 码流,保存为视频文件,核心代码用 JNI 实现。

1. 编码器初始化

cpp

运行

复制代码
#include "rk_mpi.h"
#include "mpp_log.h"
#include "rk_mpi_cmd.h"

// 全局变量
MppCtx mpp_ctx = NULL;
MppApi *mpi = NULL;
MppEncConfig enc_cfg;
int width = 1920;
int height = 1080;
int fps = 30;
int bitrate = 2000000; // 2Mbps码率

// 编码器初始化
extern "C"
JNIEXPORT jint JNICALL
Java_com_heipiao_mppdemo_MppJni_encoderInit(JNIEnv *env, jobject thiz, jint w, jint h, jint fps, jint bitrate)
{
    MPP_RET ret;
    width = w;
    height = h;

    // 1. 创建MPP编码器上下文,H.264编码
    ret = mpp_create(&mpp_ctx, &mpi);
    if (ret != MPP_OK) {
        mpp_err("mpp_create失败\n");
        return -1;
    }

    // 2. 初始化为H.264编码器
    ret = mpp_init(mpp_ctx, MPP_CTX_ENC, MPP_VIDEO_CodingAVC);
    if (ret != MPP_OK) {
        mpp_err("mpp_init失败\n");
        return -1;
    }

    // 3. 配置编码器参数
    memset(&enc_cfg, 0, sizeof(enc_cfg));
    enc_cfg.size = sizeof(enc_cfg);
    ret = mpi->control(mpp_ctx, MPP_ENC_GET_CFG, &enc_cfg);

    // 设置编码分辨率
    enc_cfg.prep.width = width;
    enc_cfg.prep.height = height;
    enc_cfg.prep.hor_stride = width;
    enc_cfg.prep.ver_stride = height;
    enc_cfg.prep.format = MPP_FMT_YUV420SP; // NV12格式,安卓摄像头常用格式

    // 设置码率、帧率
    enc_cfg.rc.rc_mode = MPP_ENC_RC_MODE_CBR; // 固定码率
    enc_cfg.rc.bps_target = bitrate;
    enc_cfg.rc.bps_max = bitrate * 1.2;
    enc_cfg.rc.fps_in_flex = 0;
    enc_cfg.rc.fps_in_num = fps;
    enc_cfg.rc.fps_in_den = 1;
    enc_cfg.rc.fps_out_num = fps;
    enc_cfg.rc.fps_out_den = 1;

    // 设置H.264编码级别
    enc_cfg.codec.h264.profile = MPP_ENC_H264_PROFILE_MAIN;
    enc_cfg.codec.h264.level = MPP_ENC_H264_LEVEL_41;
    enc_cfg.codec.h264.gop = fps * 2; // I帧间隔2秒

    // 应用配置
    ret = mpi->control(mpp_ctx, MPP_ENC_SET_CFG, &enc_cfg);
    if (ret != MPP_OK) {
        mpp_err("编码器配置失败\n");
        return -1;
    }

    mpp_log("编码器初始化成功,分辨率:%dx%d,帧率:%d\n", width, height, fps);
    return 0;
}
2. 编码一帧图像

cpp

运行

复制代码
// 编码一帧YUV数据,返回H.264码流
extern "C"
JNIEXPORT jbyteArray JNICALL
Java_com_heipiao_mppdemo_MppJni_encodeFrame(JNIEnv *env, jobject thiz, jbyteArray yuv_data)
{
    MPP_RET ret;
    MppFrame frame = NULL;
    MppPacket packet = NULL;
    jbyte *yuv_buf = env->GetByteArrayElements(yuv_data, NULL);
    int yuv_len = env->GetArrayLength(yuv_data);

    // 1. 创建MPP帧,填充YUV数据
    ret = mpp_frame_init(&frame);
    mpp_frame_set_width(frame, width);
    mpp_frame_set_height(frame, height);
    mpp_frame_set_hor_stride(frame, width);
    mpp_frame_set_ver_stride(frame, height);
    mpp_frame_set_fmt(frame, MPP_FMT_YUV420SP);
    mpp_frame_set_buffer(frame, yuv_buf, yuv_len);

    // 2. 把帧送入编码器
    ret = mpi->encode_put_frame(mpp_ctx, frame);
    if (ret != MPP_OK) {
        mpp_err("送入帧失败\n");
        mpp_frame_deinit(&frame);
        env->ReleaseByteArrayElements(yuv_data, yuv_buf, 0);
        return NULL;
    }

    // 3. 获取编码后的码流包
    ret = mpi->encode_get_packet(mpp_ctx, &packet);
    if (ret != MPP_OK) {
        mpp_err("获取码流失败\n");
        mpp_frame_deinit(&frame);
        env->ReleaseByteArrayElements(yuv_data, yuv_buf, 0);
        return NULL;
    }

    // 4. 拷贝码流数据,返回给Java层
    char *packet_data = (char *)mpp_packet_get_data(packet);
    int packet_len = mpp_packet_get_size(packet);
    jbyteArray result = env->NewByteArray(packet_len);
    env->SetByteArrayRegion(result, 0, packet_len, (jbyte *)packet_data);

    // 5. 释放资源
    mpp_packet_deinit(&packet);
    mpp_frame_deinit(&frame);
    env->ReleaseByteArrayElements(yuv_data, yuv_buf, 0);

    return result;
}
3. 编码器释放

cpp

运行

复制代码
extern "C"
JNIEXPORT jint JNICALL
Java_com_heipiao_mppdemo_MppJni_encoderRelease(JNIEnv *env, jobject thiz)
{
    if (mpp_ctx) {
        mpp_destroy(mpp_ctx);
        mpp_ctx = NULL;
        mpi = NULL;
    }
    mpp_log("编码器已释放\n");
    return 0;
}
4. 安卓 App 调用

在 Java 层,我们从摄像头采集 YUV 数据,调用编码器编码成 H.264 码流,保存为视频文件,或者通过网络推流:

java

运行

复制代码
// 初始化编码器
MppJni mppJni = new MppJni();
mppJni.encoderInit(1920, 1080, 30, 2000000);

// 摄像头回调,获取YUV数据
camera.setPreviewCallback((data, camera) -> {
    // 调用硬件编码
    byte[] h264Data = mppJni.encodeFrame(data);
    // 保存码流到文件,或者推流
    saveToFile(h264Data);
});

// 释放编码器
mppJni.encoderRelease();

三、VPU 编解码优化技巧

  1. 码率控制优化:实时视频流场景,用 CBR 固定码率,保证网络传输的稳定性;本地存储场景,用 VBR 可变码率,在保证画质的前提下,减小文件体积;
  2. GOP 优化:移动监控场景,GOP 设为 1~2 秒,保证随机播放和网络丢包后的恢复速度;本地存储场景,GOP 可以设为 5~10 秒,提升压缩率;
  3. 分辨率和帧率优化:在满足需求的前提下,尽量降低分辨率和帧率,比如 1080P30 改成 720P15,编码速度提升 4 倍,码率降低 75%;
  4. 零拷贝优化:用安卓的 HardwareBuffer,实现摄像头、RGA、编码器之间的内存零拷贝,完全避免数据在内存里的拷贝,提升性能,降低 CPU 占用;
  5. 多线程流水线:把采集、预处理、编码、封装 / 推流,做成多线程流水线,最大化 VPU 的利用率,实现低延迟编码。

结尾说两句

这篇文章,我们讲透了 RK3568 的 NPU 和 VPU 硬件加速模块,从驱动适配、环境搭建,到安卓系统的完整调用流程,实现了 NPU 人脸识别推理和 VPU 硬件编解码。充分利用 RK 芯片的硬件加速能力,能让你的产品在性能、功耗、成本上,都有巨大的优势,这也是 RK 平台在边缘计算、AIoT 领域的核心竞争力。

下一篇,我们进入量产落地的核心内容,量产落地必看:合规性、稳定性测试与量产注意事项,教你怎么把 demo 变成可量产的工业级产品,避开量产路上的所有坑。

我是黒漂技术佬,关注我,带你零基础入门 RK 安卓驱动开发,不踩坑。有任何 NPU/VPU 开发的问题,评论区留言,我都会一一回复。

相关推荐
千里马学框架4 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台4 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone4 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc4 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo4 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077004 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼4 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone4 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen4 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone4 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui