第 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.solibrknn_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 开发的问题,评论区留言,我都会一一回复。

相关推荐
Volunteer Technology2 小时前
mysql面试场景题(二)
android·mysql·面试
代码s贝多芬的音符3 小时前
Android NV21 转 YUV 系列格式
android·开发语言·python
匆忙拥挤repeat3 小时前
Android Compose 《编程思想》解读
android
进击的cc4 小时前
Activity 生命周期是如何被调度的?(从源码到实战全链路拆解)
android
路溪非溪4 小时前
Linux下iw工具的使用总结
linux·网络·arm开发·驱动开发
sp42a4 小时前
将 NativeScript 项目升级到 Android API 35 级别
android·nativescript
tangweiguo030519874 小时前
iOS vs Android 开发对照手册
android·ios
用户69371750013844 小时前
跟你唠唠!A2A协议来了,谁能拿下下一代手机系统的主动权?
android·前端·人工智能
用户69371750013844 小时前
微信悄悄搞大事!原生智能助手秘密研发,2026年改变亿人使用习惯
android·后端·微信小程序