正在上传图片(0/1)

【OSDK】高级视觉功能代码跟读

 0
手机看帖 1 1782
通过无人机获取到视频流及图像再通过记载计算机拓展算了,对图像或视频进行处理是一个应用场景很广泛的需求,这篇文章记录记录OSDK的高级视觉功能,
即通过官方代码sample了解怎样通过DJI OSDK来获取挂载在DJI无人机上的视频或图像数据。

首先,先给个高级视觉功能官方链接:
https://developer.dji.com/cn/doc ... 1-a6ec-e879f5dbd353
关于官方支持的产品特性,就可以参考这个链接上的说明了。。。

再来看代码文件夹,找到sample中的advance-sensing部分,如下:
/Onboard-SDK-4.1/sample/platform/linux/advanced-sensing
文件夹中sample比较多,包含获取裸流播放,获取裸流保存成H264文件,视觉图像获取等。这篇文章先聊聊最基本的功能获取FPV/主相机视频裸流。
涉及到的三个文件夹:
camera_h264_callback_sample    //保存成H264裸流文件
camera_stream_callback_sample  //回调方式获取视频流,并解码播放
camera_stream_poll_sample      //poll方式获取视频流,并解码播放

这篇文章主要聊聊camera_h264_callback_sample,先了解一下代码结构和原理,具体的sample再对应看细节应该问题也不大。先看这个代码main.c

  /*! @brief
   *
   *  Start the FPV or Camera H264 Stream
   *
   *  @platforms M210V2, M300
   *  @Note For M210 V2 series, only OSDK_CAMERA_POSITION_NO_1 and
   *  OSDK_CAMERA_POSITION_FPV are supported.
   *  @note  For M300, all the poss are supported.
   *  @param pos point out which camera to output the H264 stream
   *  @param cb callback function that is called in a callback thread when a new
   *            h264 frame is received
   *  @param cbParam a void pointer that users can manipulate inside the callback
   *  @Return Errorcode of liveivew, ref to DJI::OSDK:: LiveView:: LiveViewErrCode
   */
  LiveView:: LiveViewErrCode startH264Stream(LiveView:: LiveViewCameraPosition pos, H264Callback cb, void *userData);

  跟代码可以看到这个函数的实现需要分机型,M300和M210的调用接口不一样,本文就以M300的例子说明一下了,大致查看一下,基本实现思路应该是一样的,方式上有差别,看官方的发布
  和更新记录,M300的方案应该比较成熟点,毕竟经过几次迭代。。。。。

  函数调用:
  dji_liveview.cpp
  liveview->startH264Stream(pos, cb, userData);
  继续:
  dji_liveview_impl.cpp
        impl->startH264Stream(pos, cb, userData)
        
        我们看到了传进来的回调和参数使用:
        
        ...
        if (h264CbHandlerMap.find(pos) != h264CbHandlerMap.end()) {
                h264CbHandlerMap[pos].cb = cb;
                h264CbHandlerMap[pos].userData = userData;
        }
        ...
        
        有点绕,到这里,貌似还没有找到获取裸流的源头,但是可以看到是将回调附给了h264CbHandlerMap,那就继续追h264CbHandlerMap。
        
        在这个文件:dji_liveview_impl.cpp
        std::map<LiveView:: LiveViewCameraPosition, LiveViewImpl::H264CallbackHandler> LiveViewImpl::h264CbHandlerMap = {
        {LiveView::OSDK_CAMERA_POSITION_NO_1, {defaultH264CB, (void *)&(defUserData[LiveView::OSDK_CAMERA_POSITION_NO_1])}},
        {LiveView::OSDK_CAMERA_POSITION_NO_2, {defaultH264CB, (void *)&(defUserData[LiveView::OSDK_CAMERA_POSITION_NO_2])}},
        {LiveView::OSDK_CAMERA_POSITION_NO_3, {defaultH264CB, (void *)&(defUserData[LiveView::OSDK_CAMERA_POSITION_NO_3])}},
        {LiveView::OSDK_CAMERA_POSITION_FPV,  {defaultH264CB, (void *)&(defUserData[LiveView::OSDK_CAMERA_POSITION_FPV])}},
    };

        T_RecvCmdItem LiveViewImpl::bulkCmdList[] = {
                PROT_CMD_ITEM(0, 0, LIVEVIEW_TEMP_CMD_SET, LIVEVIEW_FPV_CAM_TEMP_CMD_ID,  MASK_HOST_DEVICE_SET_ID, (void *)&h264CbHandlerMap, RecordStreamHandler),
                PROT_CMD_ITEM(0, 0, LIVEVIEW_TEMP_CMD_SET, LIVEVIEW_MAIN_CAM_TEMP_CMD_ID, MASK_HOST_DEVICE_SET_ID, (void *)&h264CbHandlerMap, RecordStreamHandler),
                PROT_CMD_ITEM(0, 0, LIVEVIEW_TEMP_CMD_SET, LIVEVIEW_VICE_CAM_TEMP_CMD_ID, MASK_HOST_DEVICE_SET_ID, (void *)&h264CbHandlerMap, RecordStreamHandler),
                PROT_CMD_ITEM(0, 0, LIVEVIEW_TEMP_CMD_SET, LIVEVIEW_TOP_CAM_TEMP_CMD_ID,  MASK_HOST_DEVICE_SET_ID, (void *)&h264CbHandlerMap, RecordStreamHandler),
        };
        
        阅读到这里,可以看到这里开始将应用端获取视频流关联到linker层了,再继续到底层,我们可以了解的信息有限,个人认为不用继续往下追了,看一下RecordStreamHandler的实现核心部分。
        
        ...
        std::map<LiveView:: LiveViewCameraPosition, H264CallbackHandler> handlerMap =
      *(std::map<LiveView:: LiveViewCameraPosition, H264CallbackHandler> *)userData;
         
          ...
         
          if((handlerMap.find(pos) != handlerMap.end()) && (handlerMap[pos].cb != NULL)) {
                handlerMap[pos].cb((uint8_t *)cmdData, cmdInfo->dataLen, handlerMap[pos].userData);
          } else {
                //DERROR("Can't find valid cb in handlerMap, pos = %d", pos);
          }
        ...

        h264CbHandlerMap 和 userData就对应起来了,即
        handlerMap[pos].cb执行的回调就是我们从main开始一直传过来的回调,所以当函数RecordStreamHandler触发时,我们sample  camera_h264_callback_sample就对应执行了保存数据流至文本文件中。
        
        所以到这里,数据流的获取过程大致就厘清了。我个人的理解就是OSDK提供从飞机获取视频流的接口,所有对视频流的处理均可以看做是应用端处理。比如我们传入的回调是写文本,这就是应用。到这里我们再看camera_stream_callback_sample, 也就是传入的回调将文本记录改成了解码和播放。

我们继续看看这个sample:
     先找相关代码:
        sample代码源文件为:
        camera-stream-callback-sample.cpp
            camResult = vehicle->advancedSensing->startMainCameraStream(&show_rgb, &mainName);
        
        贴出代码实现:
        dji_advanced_sensing.cpp
        bool AdvancedSensing::startMainCameraStream(CameraImageCallback cb, void * cbParam)
        {
          // Use the keep_camera_x5s_state to prevent x5s become a storage device, otherwise could not get the stream
          if (vehicle_ptr->isM300()) {
                auto deocderPair = streamDecoder.find(LiveView::OSDK_CAMERA_POSITION_NO_1);
                if ((deocderPair != streamDecoder.end()) && deocderPair->second) {
                  deocderPair->second->init();
                  deocderPair->second->registerCallback(cb, cbParam);
                  return (LiveView::OSDK_LIVEVIEW_PASS
                          == startH264Stream(LiveView::OSDK_CAMERA_POSITION_NO_1, H264ToRGBCb,
                                                                 deocderPair->second));
                } else {
                  return false;
                }
          } else {
                return mainCam_ptr->startCameraStream(cb, cbParam);
          }
        }
        先直观看下参数和接口:
        (仅关注M300机型接口)除了我们经过上面提到的startH264Stream,还有引入了一个新的streamDecoder
        参数:
        H264Callback: H264ToRGBCb
        userData: deocderPair->second
        
        我们外部传入的回调:show_rgb,通过streamDecoder:deocderPair->second->registerCallback(cb, cbParam);给了一个线程调,功能就是将解码后的数据进行渲染显示。
        H264ToRGBCb这个回调仅做了一个动作:
        decoder->decodeBuffer
        也就是解码,结合获取H264裸流的介绍,这个就是应用端解码的回调实现。

        所以,sample:camera_stream_callback_sample的逻辑也就清晰了,即:通过startH264Stream的回调获取H264裸流数据,获取后直接解码成RGB格式,然后再使用传入的show_rgb对解码的RGB图像进行显示播放。
        
        我们现在跟的代码与取流写文本区别就在于应用端是一个解码部分,源码文件:dji_camera_stream_decoder.cpp
        这部分是使用ffmpeg解码,所以在编译OSDK时会依赖ffmeg是因为sample中会使用到,如果不需要这个功能,可以通过修改编译文件和代码将这部分移除也是可以的。希望这部分记录对DJI OSDK视频流部分还不太熟悉的开发者朋友们有点点帮助。
        
        比起代码逻辑理解的问题,可能有个问题更为棘手,就是使用OSDK获取M300上H20T相机视频和播放时,存在严重花屏的问题,看官方也提供了解决方案,采用SDL解码渲染以及论坛上基于妙算硬解的方案,但本人习惯在PC 虚拟Ubuntu环境下玩OSDK,使用官方提供的SDK渲染版本我这边花屏的问题一直没有得到有效解决。
        在写这篇文档的时候,又再仔细查看了下这个解码sample代码,感觉代码的处理上是不是有点小问题,先买个关子,毕竟也只是猜测。准备先修改代码验证看看,如果有新的发现,我再贴出来供大家讨论和分享。
评论
上传
你需要登录之后才能回帖    登录 | 注册
WriteBBBBBug   2021-4-15 3#
您好,请问一下,我使用sample进行相机的使用,一直都有问题,有时候拍照Camera take photo fail. 获取h264主相机流也是time out,这大概有什么原因导致的呢?感谢
取消 点赞 评论
分享至:
回复:
上传
取消 评论
快速回复 返回顶部 返回列表