跳到主要内容

RGA Rotate

当需要对图片进行旋转时, 也可以使用RGA来实现, 以提高效率。

使用RGA进行旋转时, 对图片的尺寸有要求, w_stride需要16字节对齐, 否则RGA会失败。

此demo通过v4l2读取mipi摄像头(1920x1080 30@fps), 使用RGA把NV12转换成BGR, 再把缩放成1920x1088(16的倍数)。

1. 环境准备

在使用RGA之前,请确保你的RK3588运行环境已具备以下条件:

  • 设备系统里有DMA节点, 如下:
linaro@linaro-alip:~$ ls /dev/dma_heap/system-uncached-dma32 -l
crw-rw---- 1 root video 251, 3 10月14日 05:55 /dev/dma_heap/system-uncached-dma32

此demo也是基于DMA buffer, 详细请查看RGA DMA.

  • RGA库与头文件: SDK中应包含 librga.so 动态库以及对应的头文件(通常是 rga.h 或 RgaApi.h), Neardi设备出厂固件里已经包含。

2. RGA旋转代码

此demo是把一帧图像旋转90度, 实现代码如下:

inline int ALIGN16(int x) { return (x + 15) & ~15; }

int rga_rotate(int src_fd, int src_size, int dst_fd, int dst_size,
int width, int height, int rotation_angle) {
const int bpp = 3; // bytes per pixel for BGR888

if (src_fd < 0 || dst_fd < 0) {
cerr << "invalid fd\n";
return -1;
}

// compute dst logical dims based on rotation
int dst_width = width, dst_height = height;
if (rotation_angle == IM_HAL_TRANSFORM_ROT_90 || rotation_angle == IM_HAL_TRANSFORM_ROT_270) {
dst_width = height;
dst_height = width;
}

// RGA recommended align width to 16 pixels (wstride in pixels)
int src_wstride_pix = ALIGN16(width);
int dst_wstride_pix = ALIGN16(dst_width);

// hstride usually is number of lines (height)
int src_hstride = height;
int dst_hstride = dst_height;

// compute required buffer sizes in bytes
size_t required_src_bytes = size_t(src_wstride_pix) * src_hstride * bpp;
size_t required_dst_bytes = size_t(dst_wstride_pix) * dst_hstride * bpp;

if ((size_t)src_size < required_src_bytes) {
cerr << "src buffer too small: " << src_size << " < " << required_src_bytes << endl;
return -1;
}
if ((size_t)dst_size < required_dst_bytes) {
cerr << "dst buffer too small: " << dst_size << " < " << required_dst_bytes << endl;
return -1;
}

// import dma fds -> rga handles
rga_buffer_handle_t src_handle = importbuffer_fd(src_fd, src_size);
rga_buffer_handle_t dst_handle = importbuffer_fd(dst_fd, dst_size);
if (!src_handle || !dst_handle) {
if (src_handle) releasebuffer_handle(src_handle);
if (dst_handle) releasebuffer_handle(dst_handle);
cerr << "importbuffer_fd failed\n";
return -1;
}

// wrap buffer handles
rga_buffer_t src = wrapbuffer_handle(src_handle, width, height, RK_FORMAT_BGR_888);
rga_buffer_t dst = wrapbuffer_handle(dst_handle, dst_width, dst_height, RK_FORMAT_BGR_888);

// IMPORTANT: wstride is usually in pixels (aligned),
// and when RGA reads memory the real bytes-per-line = wstride * bpp.
src.wstride = src_wstride_pix;
src.hstride = src_hstride;
dst.wstride = dst_wstride_pix;
dst.hstride = dst_hstride;

// check
int chk = imcheck(src, dst, {}, {});
if (IM_STATUS_NOERROR != chk) {
cerr << "imcheck error: " << imStrError((IM_STATUS)chk) << endl;
releasebuffer_handle(src_handle);
releasebuffer_handle(dst_handle);
return -1;
}

/*
* Rotate the src image by 90°.
src_img dst_img
-------------- -----------
|. | | .|
| < | => | ^ |
| | | |
-------------- | |
-----------
*/
int ret = imrotate(src, dst, rotation_angle);
if (ret != IM_STATUS_SUCCESS) {
cerr << "imrotate failed: " << imStrError((IM_STATUS)ret) << endl;
releasebuffer_handle(src_handle);
releasebuffer_handle(dst_handle);
return -1;
}

// release handles (dma-buf still valid)
releasebuffer_handle(src_handle);
releasebuffer_handle(dst_handle);

return 0;
}

3. 使用示例

V4L2-CAMERA基础上, 把上面拷贝代码集成进去。

或者从此处下载完整的代码.

demo程序运行后, 也可以查看RGA的负载, 如下:

root@linaro-alip:/sys/kernel/debug/rkrga# cat load
num of scheduler = 3
================= load ==================
scheduler[0]: rga3
load = 18%
-----------------------------------
scheduler[1]: rga3
load = 0%
-----------------------------------
scheduler[2]: rga2
load = 0%
-----------------------------------
=========================================
<session> <status> <tgid> <process>
3 active 5939 ./rga_rotate 22