How to get surface index when batch size bigger 1

Hi ALL
I was write frame or obj to jpg file in deepstream test5 app use nvds_obj_enc_process. But obj_meta and surface only true when batch_size=1, while set batch_size=2 i see obj_meta and surface not mapping.
I had try with create new idx_surface from surface and with source mp4 file but it not solve the problem.

Under this is my code, please help me. thanks

static void
bbox_generated_probe_after_analytics (AppCtx * appCtx, GstBuffer * buf,
    NvDsBatchMeta * batch_meta, guint index)
{
  /**my int**/
  GstMapInfo inmap = GST_MAP_INFO_INIT;
  if (!gst_buffer_map(buf, &inmap, GST_MAP_READ)) {
      g_print ("input buffer mapinfo failed\n");
      return;
  }
  // NvBufSurface *ip_surf = (NvBufSurface *) inmap.data;
  NvBufSurface *ip_surf = NULL, idx_surface;
  ip_surf = (NvBufSurface *) inmap.data;
  // NvBufSurface *idx_surface = (NvBufSurface *) g_malloc0 (sizeof (NvBufSurface));

  gst_buffer_unmap(buf, &inmap);

  ///Read path folder save image
  gchar *folderPath;
  NvDsImageSave nvds_imgsave = appCtx->config.image_save_config;
  if (nvds_imgsave.enable){
        if (nvds_imgsave.output_folder_path){
             folderPath = g_strdup(nvds_imgsave.output_folder_path);
        }
  }
  /**end int**/

  NvDsObjectMeta *obj_meta = NULL;
  GstClockTime buffer_pts = 0;
  guint32 stream_id = 0;

  for (NvDsMetaList * l_frame = batch_meta->frame_meta_list; l_frame != NULL;
      l_frame = l_frame->next) {
    NvDsFrameMeta *frame_meta = l_frame->data;
    stream_id = frame_meta->source_id;
    GstClockTime buf_ntp_time = 0;
    if (playback_utc == FALSE) {
      /** Calculate the buffer-NTP-time
       * derived from this stream's RTCP Sender Report here:
       */
      StreamSourceInfo *src_stream = &testAppCtx->streams[stream_id];
      buf_ntp_time = frame_meta->ntp_timestamp;

      if (buf_ntp_time < src_stream->last_ntp_time) {
        NVGSTDS_WARN_MSG_V ("Source %d: NTP timestamps are backward in time."
            " Current: %lu previous: %lu", stream_id, buf_ntp_time,
            src_stream->last_ntp_time);
      }
      src_stream->last_ntp_time = buf_ntp_time;
    }

    GList *l;

    for (l = frame_meta->obj_meta_list; l != NULL; l = l->next) {
       /*check

      /* Now using above information we need to form a text that should
       * be displayed on top of the bounding box, so lets form it here. */

      obj_meta = (NvDsObjectMeta *) (l->data);

      if(parse_nvdsanalytics_meta_data(obj_meta))///if object_meta in analytic region filter will save image and sent message to kafka
      {
        /**MY CUSTOM CODE**/
        /// Creat surface index
        idx_surface = *ip_surf;
        idx_surface.surfaceList = &(ip_surf->surfaceList[frame_meta->source_id]);
        idx_surface.numFilled = idx_surface.batchSize = 1;
        ///Creat path image
        gchar *daytimes;

        time_t t = time (NULL);
        struct tm *tm = localtime (&t);
        daytimes = g_strjoin("_",g_strjoin("", g_strdup_printf("%i", tm->tm_year + 1900),g_strdup_printf("%02i", tm->tm_mon + 1), g_strdup_printf("%02i", tm->tm_mday), NULL),
                       g_strjoin("",g_strdup_printf("%02i", tm->tm_hour), g_strdup_printf("%02i", tm->tm_min), g_strdup_printf("%02i", tm->tm_sec),NULL), NULL);

        gchar *image_save_path = g_strjoin("", folderPath, "/camera", g_strdup_printf("%i",frame_meta->source_id), "_", g_strdup_printf("%04i",frame_meta->frame_num),"_", daytimes, ".jpg", NULL);
//        g_print("%s\n", image_save_path);
        g_print("batch ID:%d source ID:%d\n", frame_meta->batch_id, frame_meta->source_id);
        if (nvds_imgsave.save_image_full_frame){
            NvDsObjectMeta *dummy_obj_meta = (NvDsObjectMeta *) g_malloc0 (sizeof (NvDsObjectMeta));
            dummy_obj_meta->rect_params.width = idx_surface.surfaceList[0].width;
            dummy_obj_meta->rect_params.height = idx_surface.surfaceList[0].height;
            dummy_obj_meta->rect_params.top = 0;
            dummy_obj_meta->rect_params.left = 0;
            save_image(image_save_path, &idx_surface, dummy_obj_meta, frame_meta, 0 , appCtx->obj_ctx_handle);
        }
        else{
            if(nvds_imgsave.save_image_cropped_object){
                save_image(image_save_path, &idx_surface, obj_meta, frame_meta, 0, appCtx->obj_ctx_handle);
            }
        }
        /**END**/

        /**
         * Enable only if this callback is after tiler
         * NOTE: Scaling back code-commented
         * now that bbox_generated_probe_after_analytics() is post analytics
         * (say pgie, tracker or sgie)
         * and before tiler, no plugin shall scale metadata and will be
         * corresponding to the nvstreammux resolution
         */
        float scaleW = 0;
        float scaleH = 0;
        /* Frequency of messages to be send will be based on use case.
         * Here message is being sent for first object every 30 frames.
         */
        buffer_pts = frame_meta->buf_pts;
        if (!appCtx->config.streammux_config.pipeline_width
            || !appCtx->config.streammux_config.pipeline_height) {
          g_print ("invalid pipeline params\n");
          return;
        }
        LOGD ("stream %d==%d [%d X %d]\n", frame_meta->source_id,
            frame_meta->pad_index, frame_meta->source_frame_width,
            frame_meta->source_frame_height);
        scaleW =
            (float) frame_meta->source_frame_width /
            appCtx->config.streammux_config.pipeline_width;
        scaleH =
            (float) frame_meta->source_frame_height /
            appCtx->config.streammux_config.pipeline_height;

        if (playback_utc == FALSE) {
          /** Use the buffer-NTP-time derived from this stream's RTCP Sender
           * Report here:
           */
          buffer_pts = buf_ntp_time;
        }
        /** Generate NvDsEventMsgMeta for every object */
        NvDsEventMsgMeta *msg_meta =
            (NvDsEventMsgMeta *) g_malloc0 (sizeof (NvDsEventMsgMeta));
        generate_event_msg_meta (msg_meta, obj_meta->class_id, FALSE,
                  /**< useTs NOTE: Pass FALSE for files without base-timestamp in URI */
            buffer_pts,
            appCtx->config.multi_source_config[stream_id].uri, image_save_path, daytimes, stream_id,
            appCtx->config.multi_source_config[stream_id].camera_id,
            obj_meta, scaleW, scaleH, frame_meta);
        testAppCtx->streams[stream_id].meta_number++;
        NvDsUserMeta *user_event_meta =
            nvds_acquire_user_meta_from_pool (batch_meta);
        if (user_event_meta) {
          /*
           * Since generated event metadata has custom objects for
           * Vehicle / Person which are allocated dynamically, we are
           * setting copy and free function to handle those fields when
           * metadata copy happens between two components.
           */
          user_event_meta->user_meta_data = (void *) msg_meta;
          user_event_meta->base_meta.batch_meta = batch_meta;
          user_event_meta->base_meta.meta_type = NVDS_EVENT_MSG_META;
          user_event_meta->base_meta.copy_func =
              (NvDsMetaCopyFunc) meta_copy_func;
          user_event_meta->base_meta.release_func =
              (NvDsMetaReleaseFunc) meta_free_func;
          nvds_add_user_meta_to_frame (frame_meta, user_event_meta);
        } else {
          g_print ("Error in attaching event meta to buffer\n");
        }
      }
    }
    testAppCtx->streams[stream_id].frameCount++;
  }
}


bool save_image(gchar *path,
                       NvBufSurface *ip_surf, NvDsObjectMeta *obj_meta,
                       NvDsFrameMeta *frame_meta, gint obj_counter, gpointer obj_ctx_handle) {
    NvDsObjEncUsrArgs userData = {0};
    if (strlen(path) >= sizeof(userData.fileNameImg)) {
        g_print ("Path save image out of size\n");
        return false;
    }
    userData.saveImg = TRUE;
    userData.attachUsrMeta = FALSE;
    g_stpcpy(userData.fileNameImg,path);
    userData.fileNameImg[strlen(path)] = '\0';
    userData.objNum = obj_counter++;

    nvds_obj_enc_process(obj_ctx_handle, &userData, ip_surf, obj_meta, frame_meta);
    nvds_obj_enc_finish (obj_ctx_handle);
    return true;
}

**• Hardware Platform Jetson **
• DeepStream Version 5.0
• JetPack Version 4.4
• TensorRT Version 7.1

at this line i try replace frame_meta->source_id with frame_meta->batch_id so i get:

batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
batch ID:0 source ID:1
batch ID:0 source ID:1
batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
qbatch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.
batch ID:1 source ID:1
Error: Object dimensions are greater than frame dimensions. Object not encoded.

Which “batch_size” do you mean? nvinfer batch-size or nvstreaemux batch-size?

nvinfer batch-size = 2 and nvstreaemux batch-size = 2

set nvstreaemux batch-size =4 and nvinfer batch-size =2 so the problem is solve, thank you