|
|
@@ -2,18 +2,27 @@
|
|
|
#include <cstring>
|
|
|
#include <cmath>
|
|
|
#include <algorithm>
|
|
|
+#include <iostream>
|
|
|
+#include <atomic>
|
|
|
+#include "RgaApi.h"
|
|
|
+#include "drmrga.h"
|
|
|
|
|
|
-RgaProcessor::~RgaProcessor() {}
|
|
|
-
|
|
|
+// RGA 硬件加速: NV12 -> RGB888 + resize + letterbox
|
|
|
+// 源: NV12(YCbCr 420 semi-planar), 目标: RGB888
|
|
|
bool RgaProcessor::init(int target_w, int target_h) {
|
|
|
target_w_ = target_w;
|
|
|
target_h_ = target_h;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+RgaProcessor::~RgaProcessor() {}
|
|
|
+
|
|
|
bool RgaProcessor::process(const Nv12Frame& nv12,
|
|
|
std::vector<float>& output,
|
|
|
float& scale, int& pad_x, int& pad_y) {
|
|
|
+ if (nv12.data == nullptr || nv12.width <= 0 || nv12.height <= 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
float sx = (float)target_w_ / nv12.width;
|
|
|
float sy = (float)target_h_ / nv12.height;
|
|
|
scale = std::min(sx, sy);
|
|
|
@@ -29,8 +38,60 @@ bool RgaProcessor::process(const Nv12Frame& nv12,
|
|
|
output.resize(3 * target_w_ * target_h_);
|
|
|
std::fill(output.begin(), output.end(), 0.0f);
|
|
|
|
|
|
- int uv_offset = nv12.ver_stride * nv12.stride;
|
|
|
+ // ========== RGA 硬件加速 ==========
|
|
|
+ static bool rga_ok = false;
|
|
|
+ static bool rga_tried = false;
|
|
|
+ if (!rga_tried) {
|
|
|
+ rga_ok = (c_RkRgaInit() == 0);
|
|
|
+ rga_tried = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (rga_ok) {
|
|
|
+ // 源: NV12(YCbCr 420 SP), 全图
|
|
|
+ rga_info_t src;
|
|
|
+ memset(&src, 0, sizeof(src));
|
|
|
+ src.fd = -1;
|
|
|
+ src.virAddr = nv12.data;
|
|
|
+ src.mmuFlag = 1; // 用户空间虚拟地址, 需MMU
|
|
|
+ src.blend = 0;
|
|
|
+ rga_set_rect(&src.rect, 0, 0, nv12.width, nv12.height,
|
|
|
+ nv12.stride,
|
|
|
+ nv12.ver_stride > 0 ? nv12.ver_stride : nv12.height,
|
|
|
+ RK_FORMAT_YCbCr_420_SP);
|
|
|
+
|
|
|
+ // 目标: 先转整张 RGB(resized_w x resized_h), 再手动填 letterbox
|
|
|
+ std::vector<uint8_t> rgb_tmp(resized_w * resized_h * 3);
|
|
|
+
|
|
|
+ rga_info_t dst;
|
|
|
+ memset(&dst, 0, sizeof(dst));
|
|
|
+ dst.fd = -1;
|
|
|
+ dst.virAddr = rgb_tmp.data();
|
|
|
+ dst.mmuFlag = 1;
|
|
|
+ dst.blend = 0;
|
|
|
+ dst.scale_mode = 1; // 双线性插值缩放
|
|
|
+ rga_set_rect(&dst.rect, 0, 0, resized_w, resized_h,
|
|
|
+ resized_w, resized_h, RK_FORMAT_RGB_888);
|
|
|
+
|
|
|
+ int ret = c_RkRgaBlit(&src, &dst, nullptr);
|
|
|
+ if (ret == 0) {
|
|
|
+ // 填 letterbox 并归一化到 [0,1]
|
|
|
+ for (int y = 0; y < resized_h; y++) {
|
|
|
+ const uint8_t* row = rgb_tmp.data() + (size_t)y * resized_w * 3;
|
|
|
+ for (int x = 0; x < resized_w; x++) {
|
|
|
+ int di = ((y + pad_y) * target_w_ + (x + pad_x)) * 3;
|
|
|
+ output[di + 0] = row[x * 3 + 0] / 255.0f;
|
|
|
+ output[di + 1] = row[x * 3 + 1] / 255.0f;
|
|
|
+ output[di + 2] = row[x * 3 + 2] / 255.0f;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ // RGA 失败则回退软件
|
|
|
+ std::cerr << "[RGA] blit失败, 回退软件: " << ret << std::endl;
|
|
|
+ }
|
|
|
|
|
|
+ // ========== 软件回退 ==========
|
|
|
+ int uv_offset = nv12.ver_stride * nv12.stride;
|
|
|
for (int y = 0; y < resized_h; y++) {
|
|
|
int src_y = std::min((int)(y / scale), nv12.height - 1);
|
|
|
for (int x = 0; x < resized_w; x++) {
|
|
|
@@ -53,6 +114,9 @@ bool RgaProcessor::process(const Nv12Frame& nv12,
|
|
|
|
|
|
bool RgaProcessor::processToRgb(const Nv12Frame& nv12, std::vector<uint8_t>& rgb_out,
|
|
|
int& out_w, int& out_h) {
|
|
|
+ if (nv12.data == nullptr || nv12.width <= 0 || nv12.height <= 0)
|
|
|
+ return false;
|
|
|
+
|
|
|
float sx = (float)target_w_ / nv12.width;
|
|
|
float sy = (float)target_h_ / nv12.height;
|
|
|
float s = std::min(sx, sy);
|
|
|
@@ -61,10 +125,45 @@ bool RgaProcessor::processToRgb(const Nv12Frame& nv12, std::vector<uint8_t>& rgb
|
|
|
if (out_w < 1) out_w = 1;
|
|
|
if (out_h < 1) out_h = 1;
|
|
|
|
|
|
- rgb_out.resize(out_w * out_h * 3);
|
|
|
+ rgb_out.resize((size_t)out_w * out_h * 3);
|
|
|
|
|
|
- int uv_offset = nv12.ver_stride * nv12.stride;
|
|
|
+ // ========== RGA 硬件加速 ==========
|
|
|
+ static bool rga_ok = false;
|
|
|
+ static bool rga_tried = false;
|
|
|
+ if (!rga_tried) {
|
|
|
+ rga_ok = (c_RkRgaInit() == 0);
|
|
|
+ rga_tried = true;
|
|
|
+ }
|
|
|
|
|
|
+ if (rga_ok) {
|
|
|
+ rga_info_t src;
|
|
|
+ memset(&src, 0, sizeof(src));
|
|
|
+ src.fd = -1;
|
|
|
+ src.virAddr = nv12.data;
|
|
|
+ src.mmuFlag = 1;
|
|
|
+ src.blend = 0;
|
|
|
+ rga_set_rect(&src.rect, 0, 0, nv12.width, nv12.height,
|
|
|
+ nv12.stride,
|
|
|
+ nv12.ver_stride > 0 ? nv12.ver_stride : nv12.height,
|
|
|
+ RK_FORMAT_YCbCr_420_SP);
|
|
|
+
|
|
|
+ rga_info_t dst;
|
|
|
+ memset(&dst, 0, sizeof(dst));
|
|
|
+ dst.fd = -1;
|
|
|
+ dst.virAddr = rgb_out.data();
|
|
|
+ dst.mmuFlag = 1;
|
|
|
+ dst.blend = 0;
|
|
|
+ dst.scale_mode = 1;
|
|
|
+ rga_set_rect(&dst.rect, 0, 0, out_w, out_h, out_w, out_h,
|
|
|
+ RK_FORMAT_RGB_888);
|
|
|
+
|
|
|
+ int ret = c_RkRgaBlit(&src, &dst, nullptr);
|
|
|
+ if (ret == 0) return true;
|
|
|
+ std::cerr << "[RGA] blit失败, 回退软件: " << ret << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ========== 软件回退 ==========
|
|
|
+ int uv_offset = nv12.ver_stride * nv12.stride;
|
|
|
for (int y = 0; y < out_h; y++) {
|
|
|
int src_y = std::min((int)(y / s), nv12.height - 1);
|
|
|
for (int x = 0; x < out_w; x++) {
|