rockchip-linux / mpp

Media Process Platform (MPP) module
484 stars 159 forks source link

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

Open RockLing-18 opened 10 months ago

RockLing-18 commented 10 months ago

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函数进行拷贝也是正常

HermanChen commented 10 months ago

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

HermanChen commented 10 months ago

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

RockLing-18 commented 10 months ago
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函数的第二个入参的值不知道如何设置

Ryan3812 commented 10 months ago

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

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

RockLing-18 commented 10 months ago

最好不要让 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 commented 10 months ago

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

大佬,能指导下吗

wzjmail commented 7 months ago

换个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();
}
HermanChen commented 7 months ago

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

Kevin111369 commented 3 months ago

换个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分量对齐的操作呢?

wzjmail commented 3 months ago

换个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一致

Kevin111369 commented 3 months ago

换个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参数,解决了我的问题