rockchip-linux / mpp

Media Process Platform (MPP) module
467 stars 156 forks source link

grabbing native MPPBuffer from CamSource... #548

Closed belveder79 closed 2 days ago

belveder79 commented 3 months ago

I want to grab the MPPBuffer that comes right from a CamSource and dump it to a file. Unfortunately I can't get around an error related to the memory mapping, but I don't understand why... The code was essentially taken from the encoder test example.

The critical call is this one: mpp_buffer_get_ptr

#include <iostream>

#define MODULE_TAG "mpi_video_cap"

#include <camera_source.h>
#include <mpp_debug.h>

#include "rk_mpi.h"
#include "mpp_env.h"
#include "mpp_mem.h"
#include "mpp_time.h"
#include "mpp_debug.h"
#include "mpp_common.h"

#include "utils.h"
#include "mpi_enc_utils.h"

#include "mpp_enc_roi_utils.h"
#include "mpp_rc_api.h"

extern RK_U32 mpp_debug;

int main(int argc, char* argv[])
{
  mpp_debug = 1;
  CamSource *cam_ctx = NULL;
  MppFrameFormat fmt = MPP_FMT_YUV420SP;
  //MppFrameFormat fmt = MPP_FMT_YUV422_YUYV;

  std::cout << "Opening..." << std::endl;

  cam_ctx = camera_source_init("/dev/video22", 4, 1920, 1080, fmt);
  std::cout << "Test..." << std::endl;
  if(cam_ctx == NULL)
  {
    std::cout << "Error!" << std::endl;
    return -1;
  }

  std::cout << "Done..." << std::endl;

  // need to wait for the stop event here...
  RK_S32 cam_frm_idx = -1;
  RK_U32 cap_num = 0;
  MppBuffer cam_buf = NULL;

  std::cout << "start loop..." << std::endl;

  while(true)
  {
    cam_frm_idx = camera_source_get_frame(cam_ctx);
    mpp_assert(cam_frm_idx >= 0);

    // skip unstable frames
    if (cap_num++ < 50) {
      camera_source_put_frame(cam_ctx, cam_frm_idx);
      continue;
    }
    cam_buf = camera_frame_to_buf(cam_ctx, cam_frm_idx);
    mpp_assert(cam_buf);

    // make copy
    RK_U32 bufsz = mpp_buffer_get_size(cam_buf);

    std::cout << "Size of buffer: " << bufsz << std::endl;
    // THIS ONE FAILS CONSTANTLY
    const uint8_t* buf = static_cast<const uint8_t*>(mpp_buffer_get_ptr(cam_buf));
    std::cout << ((buf != NULL) ? "OK!" : "NULL") << std::endl;
    mpp_assert(buf != NULL);
    FILE* f = fopen("frame.raw", "wb");
    fwrite(buf,bufsz,sizeof(uint8_t),f);
    fclose(f);

    camera_source_put_frame(cam_ctx, cam_frm_idx);
    std::cout << "." << std::flush;
    break;

  }

  camera_source_deinit(cam_ctx);

  return 0;
}

The output basically looks like this:

mpp[9]: camera_source: input devices:Camera

mpp[9]: camera_source: fmt name: [UYVY 4:2:2]

mpp[9]: camera_source: fmt pixelformat: 'UYVY', description = 'UYVY 4:2:2'

mpp[9]: camera_source: fmt name: [Y/CbCr 4:2:2]

mpp[9]: camera_source: fmt pixelformat: 'NV16', description = 'Y/CbCr 4:2:2'

mpp[9]: camera_source: fmt name: [Y/CrCb 4:2:2]

mpp[9]: camera_source: fmt pixelformat: 'NV61', description = 'Y/CrCb 4:2:2'

mpp[9]: camera_source: fmt name: [Y/CrCb 4:2:0]

mpp[9]: camera_source: fmt pixelformat: 'NV21', description = 'Y/CrCb 4:2:0'

mpp[9]: camera_source: fmt name: [Y/CbCr 4:2:0]

mpp[9]: camera_source: fmt pixelformat: 'NV12', description = 'Y/CbCr 4:2:0'

mpp[9]: camera_source: fmt name: [Y/CrCb 4:2:0 (N-C)]

mpp[9]: camera_source: fmt pixelformat: 'NM21', description = 'Y/CrCb 4:2:0 (N-C)'

mpp[9]: camera_source: fmt name: [Y/CbCr 4:2:0 (N-C)]

mpp[9]: camera_source: fmt pixelformat: 'NM12', description = 'Y/CbCr 4:2:0 (N-C)'

mpp[9]: camera_source: get width 1920 height 1080

mpp[9]: camera_source: get dma buf(0)-fd: 33

mpp[9]: camera_source: get dma buf(1)-fd: 34

mpp[9]: camera_source: get dma buf(2)-fd: 35

mpp[9]: camera_source: get dma buf(3)-fd: 36

mpp[9]: mpp_buffer: mpp_buffer_mmap buffer 2 group 1 fd 35 map failed caller main

mpp[9]: mpp_buffer: Assertion p->info.ptr != __null failed at mpp_buffer_get_ptr_with_caller:178

mpp[9]: mpp_buffer: mpp_buffer_get_ptr buffer 0x1c86a868 ret NULL from main

mpp[9]: mpp_buffer: mpp_buffer_mmap buffer 3 group 1 fd 36 map failed caller main

mpp[9]: mpp_buffer: Assertion p->info.ptr != __null failed at mpp_buffer_get_ptr_with_caller:178

mpp[9]: mpp_buffer: mpp_buffer_get_ptr buffer 0x1c86a9e8 ret NULL from main

mpp[9]: mpp_buffer: mpp_buffer_mmap buffer 0 group 1 fd 33 map failed caller main

mpp[9]: mpp_buffer: Assertion p->info.ptr != __null failed at mpp_buffer_get_ptr_with_caller:178

mpp[9]: mpp_buffer: mpp_buffer_get_ptr buffer 0x1c86a568 ret NULL from main

mpp[9]: mpp_buffer: mpp_buffer_mmap buffer 1 group 1 fd 34 map failed caller main

mpp[9]: mpp_buffer: Assertion p->info.ptr != __null failed at mpp_buffer_get_ptr_with_caller:178

mpp[9]: mpp_buffer: mpp_buffer_get_ptr buffer 0x1c86a6e8 ret NULL from main

Any hint highly appreciated...

PS: Any of https://github.com/rockchip-linux/mpp/issues/418#issuecomment-1734916224 did not work...

belveder79 commented 3 months ago

Ok, so I found that there might be something missing.

The actual pointer from the data is stored here: https://github.com/rockchip-linux/mpp/blob/ee946af015c350c926a0fca2f02da8e429f8b079/utils/camera_source.c#L37

However, the MPPBuffer does not have the respective info->ptr set - it is NULL. The function returns the buf, but as soon as you try to get the ptr or do read or access, there is this error from the previous post.

Not sure if it is ok to put it here, but it does the trick: https://github.com/rockchip-linux/mpp/blob/ee946af015c350c926a0fca2f02da8e429f8b079/utils/camera_source.c#L429

This one should read somewhat like:

#include "mpp_buffer_impl.h"
...
MppBuffer camera_frame_to_buf(CamSource *ctx, RK_S32 idx)
{
    MppBuffer buf = NULL;

    if (idx < 0)
        return buf;

    buf = ctx->fbuf[idx].buffer;

    MppBufferImpl *p = (MppBufferImpl*)buf;
    p->info.ptr = ctx->fbuf[idx].start;

    if (buf)
        mpp_buffer_sync_end(buf);

    return buf;
}

and then the buffer can be used as normal.

I did not find that it has any further implications and worked with my UVC camera. @HermanChen please comment if it is a bug and should get a fix...

Liaoyyyy commented 3 months ago

0001-fix-ext_dma-Refine-mmap-permission-configuration.patch Thank you for your feedback and providing suggestions for modification. In mpp_buffer_get_ptr(), the pointer is obtained through mmap with the file descriptor (fd). The buffer_type of the camera adopts the ext_dma mode, which has some deficiencies in the mmap process. Therefore, modifications have been made. Please apply the patch to verify if the issue is resolved.

belveder79 commented 3 months ago

Thx a lot for the patch. It works flawlessly now!

belveder79 commented 3 months ago

are you going to integrate it in the repo? then the issue can be closed...

HermanChen commented 3 months ago

Yes, sure.