mpp icon indicating copy to clipboard operation
mpp copied to clipboard

mpp解码后数据拷贝占用CPU,是否有更好方式进行拷贝?

Open RockLing-18 opened this issue 1 year ago • 11 comments

1.应用场景:rk3568 arm盒子视频硬解,在应用层对解码后的图像数据进行处理 2.程序使用到的SDK为rk mpp的SDK 3.程序中使用了h264的硬解,解出YUV后使用RGA转换成RGB图像,最后将图像数据拷贝传出给上层应用 4.目前在对RGB图像数据进行拷贝时(目的内存是应用层new出来的,RGB图像数据的内存由mpp SDK控制,可以获取到首地址), CPU飙升,使用memcpy函数进行数据拷贝,对YUV的数据进行拷贝也会发生同样现象 5.屏蔽对RGB或YUV的数据拷贝CPU是正常的,对其他大的数据进行memcpy函数进行拷贝也是正常

RockLing-18 avatar Sep 05 '23 06:09 RockLing-18

最好不要让 cpu 访问数据,能用硬件处理就用硬件处理,用 RGA 拷贝数据的话,使用 dmabuf fd 来传递信息是不会有很大的开销的 一定要用 cpu 访问的话,需要把外部给解码器的 buffer group 配置成带 cache 模式

HermanChen avatar Sep 05 '23 08:09 HermanChen

目前默认的 mpp_buffer_group 都是 uncache 的,cpu 访问效率会比较低

HermanChen avatar Sep 05 '23 08:09 HermanChen

ret = mpp_buffer_group_get_external(&m_group, MPP_BUFFER_TYPE_EXT_DMA);
    if (ret) {
        printf("get mpp buffer group failed ret %d\n", ret);
        return -1;
    }
  
    memset(&m_bufferInfo[0], 0, sizeof(MppBufferInfo));
    // m_bufferInfo[0].type = MPP_BUFFER_TYPE_EXT_DMA;
    // m_bufferInfo[0].fd = 1;
    // m_bufferInfo[0].size = image_size & 0x07ffffff;
    // m_bufferInfo[0].index = (image_size & 0xf8000000) >> 27;
    mpp_buffer_commit(m_group, &m_bufferInfo[0]);

    ret = m_mpiData.mpi->control(m_rga_ctx, MPP_DEC_SET_EXT_BUF_GROUP, m_group);
    if (ret) {
        mpp_err("set buffer group failed ret %d\n", ret);
        return -1;
    }

是使用这部分代码吗?可行吗?mpp_buffer_commit函数的第二个入参的值不知道如何设置

RockLing-18 avatar Sep 05 '23 08:09 RockLing-18

最好不要让 cpu 访问数据,能用硬件处理就用硬件处理,用 RGA 拷贝数据的话,使用 dmabuf fd 来传递信息是不会有很大的开销的 一定要用 cpu 访问的话,需要把外部给解码器的 buffer group 配置成带 cache 模式

请问要如何配置成带cache模式,有相关demo吗

Ryan3812 avatar Sep 06 '23 06:09 Ryan3812

最好不要让 cpu 访问数据,能用硬件处理就用硬件处理,用 RGA 拷贝数据的话,使用 dmabuf fd 来传递信息是不会有很大的开销的 一定要用 cpu 访问的话,需要把外部给解码器的 buffer group 配置成带 cache 模式

RGA拷贝数据的demo有吗?我参考了https://github.com/airockchip/librga里的,还是不行,我把解码后yuv的数据直接写文件是可以用工具播放出来,经过rga拷贝后写文件就不行了,大概率流程是有问题的,代码如下:

rga_buffer_t g_src_img;
rga_buffer_t g_dst_img;
rga_buffer_handle_t g_src_handle;
rga_buffer_handle_t g_dst_handle;

g_src_handle = 0;
g_dst_handle = 0;
memset(&g_src_img, 0, sizeof(g_src_img));
memset(&g_dst_img, 0, sizeof(g_dst_img));
memset(g_dst_buf, 0x80, 1024*1024*10);
  
g_src_handle = importbuffer_virtualaddr((char*)mpp_buffer_get_ptr(buffer), 1024*1024*10);
g_dst_handle = importbuffer_virtualaddr(g_dst_buf, 1024*1024*10);
if (g_src_handle == 0 || g_dst_handle == 0) 
{
      printf("importbuffer failed!\n");
      return ;
}

g_src_img = wrapbuffer_handle(g_src_handle, width, height, RK_FORMAT_RGB_888);
g_dst_img = wrapbuffer_handle(g_dst_handle, width, height, RK_FORMAT_RGB_888);

IM_STATUS checkRet = imcheck(g_src_img, g_dst_img, {}, {});
if (IM_STATUS_NOERROR != checkRet)
{
      printf("%d, check error! %s", __LINE__, imStrError((IM_STATUS)checkRet));
      return;
}

printf("dest handle:%d handle:%d fd:%d vir:%x phy:%x\n", g_dst_handle, g_dst_img.handle, g_dst_img.fd, g_dst_img.vir_addr, g_dst_img.phy_addr);
printf("src handle:%d handle:%d fd:%d vir:%x phy:%x\n", g_src_handle, g_src_img.handle, g_src_img.fd, g_src_img.vir_addr, g_src_img.phy_addr);
IM_STATUS retStatus = imcopy(g_src_img, g_dst_img);
if (retStatus == IM_STATUS_SUCCESS) 
{
           printf("imcopy running success!\n");
 } 
else
{
           printf("imcopy running failed, %s\n", imStrError((IM_STATUS)retStatus));
}

//这里对g_dst_buf进行操作,写文件之类
//......

if (g_src_handle)
            releasebuffer_handle(g_src_handle);
if (g_dst_handle)
            releasebuffer_handle(g_dst_handle);

其中,printf打印的g_dst_handle、g_src_handle均为-1,fd,vir__addr, phy_addr这些值均为0,看着是不正常的。

RockLing-18 avatar Sep 06 '23 08:09 RockLing-18

最好不要让 cpu 访问数据,能用硬件处理就用硬件处理,用 RGA 拷贝数据的话,使用 dmabuf fd 来传递信息是不会有很大的开销的 一定要用 cpu 访问的话,需要把外部给解码器的 buffer group 配置成带 cache 模式

大佬,能指导下吗

RockLing-18 avatar Sep 07 '23 09:09 RockLing-18

换个rga_api。 img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();通过这种方式拷贝,不再使用drm memory(uncache), 改用pysical cache memory。避免以cpu访问该段内存因为un-cached导致不必要的损失

demo:

src_buffer = wrapbuffer_virtualaddr((char*)mpp_buffer_get_ptr(buff), hor_stride, ver_stride, src_format);
mid_buffer = wrapbuffer_virtualaddr((char*)malloc(width * height * get_bpp_from_format(src_format)), width,height,  rc_format);
im_rect src_rect;
src_rect.x      = 0;
src_rect.y      = 0;
src_rect.width  = width;
src_rect.height = height;
IM_STATUS status;
//对齐后的图片crop
status = imcrop(src_buffer, mid_buffer, src_rect);
//cvtcolor+resize
status = imcvtcolor(mid_buffer, out_buffer , mid_buffer.format, out_buffer.format);
if(mid_buffer.vir_addr != NULL) {
	free(mid_buffer.vir_addr);
}

if (decode_method == "rga") {
  // RGA decode
  img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();
}

wzjmail avatar Nov 27 '23 07:11 wzjmail

最新代码已经支持带 cache 的 buffer 了,可以测试下速度提升了多少

HermanChen avatar Nov 29 '23 02:11 HermanChen

换个rga_api。 img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();通过这种方式拷贝,不再使用drm memory(uncache), 改用pysical cache memory。避免以cpu访问该段内存因为un-cached导致不必要的损失

demo:

src_buffer = wrapbuffer_virtualaddr((char*)mpp_buffer_get_ptr(buff), hor_stride, ver_stride, src_format);
mid_buffer = wrapbuffer_virtualaddr((char*)malloc(width * height * get_bpp_from_format(src_format)), width,height,  rc_format);
im_rect src_rect;
src_rect.x      = 0;
src_rect.y      = 0;
src_rect.width  = width;
src_rect.height = height;
IM_STATUS status;
//对齐后的图片crop
status = imcrop(src_buffer, mid_buffer, src_rect);
//cvtcolor+resize
status = imcvtcolor(mid_buffer, out_buffer , mid_buffer.format, out_buffer.format);
if(mid_buffer.vir_addr != NULL) {
	free(mid_buffer.vir_addr);
}

if (decode_method == "rga") {
  // RGA decode
  img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();
}

您好,请问imcrop会分别裁剪y分量和uv分量,然后拼到一起吗?我使用mpp解码得到的MppFrame中,y分量和uv分量之间存在一些填充数据,这导致直接进行imcvtcolor时y分量和uv分量无法对齐,能否使用imcrop完成y分量和uv分量对齐的操作呢?

Kevin111369 avatar Apr 09 '24 15:04 Kevin111369

换个rga_api。 img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();通过这种方式拷贝,不再使用drm memory(uncache), 改用pysical cache memory。避免以cpu访问该段内存因为un-cached导致不必要的损失 demo:

src_buffer = wrapbuffer_virtualaddr((char*)mpp_buffer_get_ptr(buff), hor_stride, ver_stride, src_format);
mid_buffer = wrapbuffer_virtualaddr((char*)malloc(width * height * get_bpp_from_format(src_format)), width,height,  rc_format);
im_rect src_rect;
src_rect.x      = 0;
src_rect.y      = 0;
src_rect.width  = width;
src_rect.height = height;
IM_STATUS status;
//对齐后的图片crop
status = imcrop(src_buffer, mid_buffer, src_rect);
//cvtcolor+resize
status = imcvtcolor(mid_buffer, out_buffer , mid_buffer.format, out_buffer.format);
if(mid_buffer.vir_addr != NULL) {
	free(mid_buffer.vir_addr);
}

if (decode_method == "rga") {
  // RGA decode
  img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();
}

您好,请问imcrop会分别裁剪y分量和uv分量,然后拼到一起吗?我使用mpp解码得到的MppFrame中,y分量和uv分量之间存在一些填充数据,这导致直接进行imcvtcolor时y分量和uv分量无法对齐,能否使用imcrop完成y分量和uv分量对齐的操作呢?

看下你的mpp mapframe的hor_stride和vertical_stride. src_buffer的hor_stride, ver_stride应该与mpp mapframe一致

wzjmail avatar Apr 09 '24 15:04 wzjmail

换个rga_api。 img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();通过这种方式拷贝,不再使用drm memory(uncache), 改用pysical cache memory。避免以cpu访问该段内存因为un-cached导致不必要的损失 demo:

src_buffer = wrapbuffer_virtualaddr((char*)mpp_buffer_get_ptr(buff), hor_stride, ver_stride, src_format);
mid_buffer = wrapbuffer_virtualaddr((char*)malloc(width * height * get_bpp_from_format(src_format)), width,height,  rc_format);
im_rect src_rect;
src_rect.x      = 0;
src_rect.y      = 0;
src_rect.width  = width;
src_rect.height = height;
IM_STATUS status;
//对齐后的图片crop
status = imcrop(src_buffer, mid_buffer, src_rect);
//cvtcolor+resize
status = imcvtcolor(mid_buffer, out_buffer , mid_buffer.format, out_buffer.format);
if(mid_buffer.vir_addr != NULL) {
	free(mid_buffer.vir_addr);
}

if (decode_method == "rga") {
  // RGA decode
  img_rgb=cv::Mat(dst_height, dst_width, CV_8UC3, out_buffer.vir_addr).clone();
}

您好,请问imcrop会分别裁剪y分量和uv分量,然后拼到一起吗?我使用mpp解码得到的MppFrame中,y分量和uv分量之间存在一些填充数据,这导致直接进行imcvtcolor时y分量和uv分量无法对齐,能否使用imcrop完成y分量和uv分量对齐的操作呢?

看下你的mpp mapframe的hor_stride和vertical_stride. src_buffer的hor_stride, ver_stride应该与mpp mapframe一致

谢谢您的指导,我在使用wrapbuffer_handle封装RGA图像的时候加入了wstride和hstride参数,解决了我的问题

Kevin111369 avatar Apr 10 '24 05:04 Kevin111369