rockchip-linux / mpp

Media Process Platform (MPP) module
466 stars 155 forks source link

MJPEG解码目前还是只能使用advanced接口吗 #586

Closed TRYOKETHEPEN closed 2 months ago

TRYOKETHEPEN commented 2 months ago

问题: 使用mpp解码UVC摄像头的视频流(MJPEG,1280*720,30fps),获取第一帧后,阻塞在Decode()的do...while循环中。 on_uvc_frame_out()中可以正常保存本地.jpeg文件,查看该文件图像格式为YUV422。

查看之前的issue(https://github.com/rockchip-linux/mpp/issues/309 https://github.com/rockchip-linux/mpp/issues/82 https://github.com/rockchip-linux/mpp/issues/171 ),以及mpi_dec_test.c例程中有如下内容。是否当前MJPEG的解码还是只能使用advanced接口

//省略
cmd->simple = (cmd->type != MPP_VIDEO_CodingMJPEG) ? (1) : (0);
//省略
//进入dec_advanced()

开发板: RK3588,Debian11 mpp安装过程: install_log.txt mpp环境测试信息: test_log.txt

相关应用代码: main()->process_video_UVC()-->初始化解码器-->开始播放-->on_uvc_frame_out()->Decode()->mpp_decoder_frame_callback()

// UVC播放回调
void on_uvc_frame_out(uvc_frame_t *frame, void *ptr)
{
  uvc_error_t ret;
  printf("callback! frame_format = %d, width = %d, height = %d, length = %lu, ptr = %p\n", frame->frame_format, frame->width, frame->height, frame->data_bytes, ptr);

  switch (frame->frame_format)
  {
  case UVC_FRAME_FORMAT_H264:
    break;
  case UVC_FRAME_FORMAT_MJPEG:
    static int jpeg_count = 0;
    char filename[16];
    sprintf(filename, "%d.jpeg", jpeg_count++);
    FILE *fp;
    fp = fopen(filename, "w");
    fwrite(frame->data, 1, frame->data_bytes, fp);
    fclose(fp);
    break;
  case UVC_FRAME_FORMAT_YUYV:
    break;
  default:
    break;
  }
  first_ctx.decoder->Decode((uint8_t *)frame->data, frame->data_bytes, 0); // 解码//*解码完成后触发回调mpp_decoder_frame_callback
}

// 处理UVC视频输入
static int process_video_UVC(const char *path)
{
  uvc_context_t *ctx;
  uvc_device_t *dev;
  uvc_device_handle_t *devh;
  uvc_stream_ctrl_t ctrl;
  uvc_error_t res;

  res = uvc_init(&ctx, NULL); // 初始化UVC ctx
  if (res < 0)
  {
    uvc_perror(res, "uvc_init");
    return res;
  }
  puts("UVC初始化成功");

  res = uvc_find_device(ctx, &dev, 0x1e4e, 0x0109, NULL); // 寻找设备 筛选项: vendor_id, product_id, "serial_num",不筛选置为0,0,NULL

  if (res < 0)
  {
    uvc_perror(res, "uvc_find_device");
    return res;
  }

  puts("找到UVC设备");
  res = uvc_open(dev, &devh); // 打开设备,不能与其他进程同时占用
  if (res < 0)
  {
    uvc_perror(res, "uvc_open");
    return res;
  }

  puts("开启UVC设备");
  printf("UVC设备信息:\n");
  uvc_print_diag(devh, stderr);                                      // 打印UVC设备信息
  const uvc_format_desc_t *format_desc = uvc_get_format_descs(devh); // 格式描述体
  enum uvc_frame_format frame_format;                                // 帧格式
  int width, height, fps;
  switch (format_desc->bDescriptorSubtype)
  {
  case UVC_VS_FORMAT_MJPEG:
    frame_format = UVC_FRAME_FORMAT_MJPEG;
    break;
  case UVC_VS_FORMAT_FRAME_BASED:
    frame_format = UVC_FRAME_FORMAT_H264;
    break;
  default:
    frame_format = UVC_FRAME_FORMAT_YUYV;
    break;
  }
  if (format_desc->frame_descs)
  {
    width = format_desc->frame_descs->wWidth;
    height = format_desc->frame_descs->wHeight;
    fps = 10000000 / format_desc->frame_descs->dwDefaultFrameInterval;
  }
  printf("UVC格式=%4s %dx%d %dfps\n", format_desc->fourccFormat, width, height, fps);

  res = uvc_get_stream_ctrl_format_size(devh, &ctrl, frame_format, width, height, fps); // 协商第一个流文件
  if (res < 0)
  {
    uvc_perror(res, "get_mode");
    return res;
  }

  printf("\nUVC流控信息:\n");
  uvc_print_stream_ctrl(&ctrl, stderr); // 打印流控信息

//省略
  if (first_ctx.decoder == NULL) //! 首次进入才设置
  {
    MppCodingType mpp_type;
    if (frame_format == UVC_FRAME_FORMAT_MJPEG)
    {
      mpp_type = MPP_VIDEO_CodingMJPEG;
    }
    else if (frame_format == UVC_FRAME_FORMAT_H264)
    {
      mpp_type = MPP_VIDEO_CodingAVC;
    }
    printf(">>>>>设置视频解码器\n");
    MppDecoder *decoder = new MppDecoder();           // 记得delete
    decoder->Init(mpp_type, fps, NULL);                // 初始化解码器
    decoder->SetCallback(mpp_decoder_frame_callback); //* 注册解码回调函数
    first_ctx.decoder = decoder;           
  }

  res = uvc_start_streaming(devh, &ctrl, on_uvc_frame_out, (void *)12345, 0); //! 开启流
  if (res < 0)
  {
    uvc_perror(res, "start_streaming");
    return res;
  }

  puts(">>>>>开始播放");

  printf(">>>>>按任意按键退出播放\n");
  getchar();
//省略
  return 0;
}

int main(int argc, char **argv)
{
//省略
  printf(">>>>>处理输入视频\n");
  if (strncmp(in_video_path.c_str(), "rtsp", 4) == 0) // 如果视频路径开头为rtsp
  {
    printf("输入为rtsp\n");
    process_video_rtsp(in_video_path.c_str());
  }
  else if (strncmp(in_video_path.c_str(), "USB", 3) == 0) // UVC摄像头
  {
    printf("输入为UVC\n");
    process_video_UVC(in_video_path.c_str()); 
  }
  else
  {
    printf("输入视频不支持\n");
  }
//省略
  return 0;
}

解码实现: 参考https://github.com/rockchip-linux/rknn-toolkit2/blob/master/rknpu2/examples/rknn_yolov5_demo/utils/mpp_decoder.cpp ,只修改了Init传入MppCodingType 参数。

int MppDecoder::Init(MppCodingType video_type, int fps, void *userdata)
{
    MPP_RET ret = MPP_OK;
    this->userdata = userdata;
    this->fps = fps;
    this->last_frame_time_ms = 0;
    mpp_type = video_type;
    LOGD("mpi_dec_test start \n");
//省略
}

运行日志:

>>>>>处理输入视频
输入为UVC
UVC初始化成功
找到UVC设备
开启UVC设备
UVC设备信息:
DEVICE CONFIGURATION (1e4e:0109/[none]) ---
Status: idle
VideoControl:
        bcdUVC: 0x0100
VideoStreaming(1):
        bEndpointAddress: 129
        Formats:
        MJPEGFormat(1)
                  bits per pixel: 0
                  GUID: 4d4a5047000000000000000000000000 (MJPG)
                  default frame: 1
                  aspect ratio: 0x0
                  interlace flags: 00
                  copy protect: 00
                        FrameDescriptor(1)
                          capabilities: 00
                          size: 1280x720
                          bit rate: 442368000-442368000
                          max frame size: 1843200
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(2)
                          capabilities: 00
                          size: 800x600
                          bit rate: 230400000-230400000
                          max frame size: 960000
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(3)
                          capabilities: 00
                          size: 640x480
                          bit rate: 147456000-147456000
                          max frame size: 614400
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(4)
                          capabilities: 00
                          size: 352x288
                          bit rate: 48660480-48660480
                          max frame size: 202752
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(5)
                          capabilities: 00
                          size: 320x240
                          bit rate: 36864000-36864000
                          max frame size: 153600
                          default interval: 1/30
                          interval[0]: 1/30
                        StillFrameDescriptor
                          bEndPointAddress: 00
                          wWidth(1) = 1280
                          wHeight(1) = 720
                          wWidth(2) = 800
                          wHeight(2) = 600
                          wWidth(3) = 640
                          wHeight(3) = 480
                          wWidth(4) = 352
                          wHeight(4) = 288
                          wWidth(5) = 320
                          wHeight(5) = 240
        UncompressedFormat(2)
                  bits per pixel: 16
                  GUID: 5955593200001000800000aa00389b71 (YUY2)
                  default frame: 1
                  aspect ratio: 0x0
                  interlace flags: 00
                  copy protect: 00
                        FrameDescriptor(1)
                          capabilities: 00
                          size: 1280x720
                          bit rate: 132710400-132710400
                          max frame size: 1843200
                          default interval: 1/9
                          interval[0]: 1/9
                        FrameDescriptor(2)
                          capabilities: 00
                          size: 640x480
                          bit rate: 147456000-147456000
                          max frame size: 614400
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(3)
                          capabilities: 00
                          size: 800x600
                          bit rate: 153600000-153600000
                          max frame size: 960000
                          default interval: 1/20
                          interval[0]: 1/20
                        FrameDescriptor(4)
                          capabilities: 00
                          size: 352x288
                          bit rate: 48660480-48660480
                          max frame size: 202752
                          default interval: 1/30
                          interval[0]: 1/30
                        FrameDescriptor(5)
                          capabilities: 00
                          size: 320x240
                          bit rate: 36864000-36864000
                          max frame size: 153600
                          default interval: 1/30
                          interval[0]: 1/30
                        StillFrameDescriptor
                          bEndPointAddress: 00
                          wWidth(1) = 1280
                          wHeight(1) = 720
                          wWidth(2) = 640
                          wHeight(2) = 480
                          wWidth(3) = 800
                          wHeight(3) = 600
                          wWidth(4) = 352
                          wHeight(4) = 288
                          wWidth(5) = 320
                          wHeight(5) = 240
END DEVICE CONFIGURATION
UVC格式=MJPG 1280x720 30fps

UVC流控信息:
bmHint: 0001
bFormatIndex: 1
bFrameIndex: 1
dwFrameInterval: 333333
wKeyFrameRate: 0
wPFrameRate: 0
wCompQuality: 0
wCompWindowSize: 0
wDelay: 0
dwMaxVideoFrameSize: 1843200
dwMaxPayloadTransferSize: 3060
bInterfaceNumber: 1
开启自动曝光 ...
 ... full AE not supported, trying aperture priority mode
开启自动曝光成功
>>>>>设置视频解码器
mpi_dec_test start 
mpi_dec_test decoder test start mpp_type 8 
>>>>>开始播放
>>>>>按任意按键退出播放
callback! frame_format = 7, width = 1280, height = 720, length = 44602, ptr = 0x3039
//然后阻塞在这里

对应的mpp日志:

Apr 29 09:43:10 lubancat mpp[698243]: mpp_info: mpp version: e34f0dd1 author: Herman Chen   2023-07-17 [hal_vp8e]: Fix crash on unsupport input format
//然后阻塞在这里

本地保存的.jpeg文件: 在on_uvc_frame_out()中生成的,0.jpeg.zip mpi_dec_test: 使用保存的.jpeg文件进行解码,结果OK

root@lubancat:/home/mpp/build/linux/aarch64/test# ./mpi_dec_test -i 0.jpeg -w 1280 -h 720 -t 8
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: input file 0.jpeg size 48365
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: cmd parse result:
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: input  file name: 0.jpeg
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: output file name:
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: width      : 1280
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: height     :  720
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: type       :    8
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_utils: max frames :    0
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_test: mpi_dec_test start
Apr 29 09:59:42 lubancat mpp[706083]: mpp_info: mpp version: 4cc3fb25 author: leo           2024-04-26 fix[allocato                                                            r]: fix on invalid DMA heap allocator
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_test: 0x55962c2680 mpi_dec_test decoder test start w 1280 h 720 type                                                             8
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_test: 0x55962c2680 decoded frame 0
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_test: decode 1 frames time 1 ms delay   1 ms fps 562.75
Apr 29 09:59:42 lubancat mpp[706083]: mpi_dec_test: test success max memory 0.00 MB
TRYOKETHEPEN commented 2 months ago

@HermanChen 佬来看一下

Sherman86 commented 2 months ago

是的,jpeg 解码走 advanced 接口。

Sherman86 commented 2 months ago

可以参考 rkmedia 的做法

https://github.com/Caesar-github/rkmedia/blob/master/src/rkmpp/mpp_decoder.cc