M300挂载相机,无法获取相机画面

已完成

评论

48 条评论

  • Caiyixun

    我重新对M300和M210进行了测试(挂载同一个相机),M210可以显示相机画面以及FPV画面,由于只挂载了一个相机,所以选择左相机还是右相机的那些按钮都是被禁用的(没挂第三个相机,默认不能选?),视频源也能显示,一个是LEFT_CAM,一个是FPV_CAM。当M300挂载同样的相机时,显示不了相机源,而且画面是黑的,显示来源为UNKONWN,另外一个则可以显示FPV画面,显示来源FPV_CAM。我想问一下,官方示例demo(V4)的获取相机源是在哪里实现的啊?因为GimbalCapabilityView.java和VideoFeederView.java这两个类都有用到相机。调用相机的语句没找到。

    0
    评论操作 固定链接
  • Caiyixun

    对于这个流程,我在官方demo中进行了查找

    occusync.assignSourceToPrimaryChannel先定义号视频源是上面的那三个语句吗?然后在V4的官方demo,我就没找到getPrimaryVideoDataFeed和getSecondaryVideoDataFeed获取主副视频数据。我不知道示例里面是如何进行视频数据获取的???

    0
    评论操作 固定链接
  • Caiyixun

    找到了,但是为什么M210挂载相机就能获取到,M300挂载相机就获取不到呢?前面两个函数updateM210SeriesButtons();和updateM300Buttons();只是对按钮的启用和禁用进行了设置,理论上是影响不到相机画面的获取的。现在偏偏是M210能获取,M300不能获取

    0
    评论操作 固定链接
  • Caiyixun

    我又测试了一下,因为代码是一样的,语句是getPrimaryVideoFeed()和getSecondaryVideoFeed()。我不知道是不是相机挂的位置错了,但是在M210中,不论相机挂左边还是右边,都能获取到,并显示画面。而在M300中不管调左相机获取还是右相机获取,源都是未知。

    0
    评论操作 固定链接
  • Caiyixun

    再次感谢进度:getPrimaryVideoFeed()和getSecondaryVideoFeed()拿到的都不是null,我做了判断,如果是空值就给出提示,但是不管是M300还M210都没有提示,猜测都不是NULL,但是为什么M300显示不出来,原因未知。应该是官方函数内部存在问题。

    0
    评论操作 固定链接
  • DJI Developer Support
    可以告诉我们您使用的云台相机是什么吗? 如果是M300不支持的相机,可能就是获取不到画面的,因为M300和M210支持的云台相机不完全一致。如果是相机的问题,您可以使用pilot检测,pilot可以获取,MSDK应该也可以获取。
    0
    评论操作 固定链接
  • Caiyixun

    M300的遥控器的那个pilot 2是可以看到画面的,就是官方Demo是获取不到画面的,但是我还以为是代码的问题。就单纯是官方示例Demo拿不到相机画面。M300的遥控器里面安装的pilot是有画面的。

    0
    评论操作 固定链接
  • Caiyixun

    是否是源通道设置的有问题?可是我都没改demo。

    0
    评论操作 固定链接
  • Caiyixun

    画面就是这样的,我尝试了获取左、右以及上三个源,显示的都是UNKNOWN。另外上面的显示的是0个相机已经连接。虽然这个实现的地方是isM210SeriesTwoCameraConnected这个函数,但为什么是0个相机连接?我明明挂载了一个云台相机。

    0
    评论操作 固定链接
  • DJI Developer Support
    ![](https://djisdksupport.zendesk.com/attachments/token/r7tj7ZzyAsQVdc6eg3jBlcfqN/?name=image.png) 这里的含义是MSDK识别到camera ,camera的index为0,它是一个第三方相机,挂载在index为0的云台位置上。 因为你使用的是第三方相机,第三方相机在实现的时候可以选择输出的视频流格式是DJI H264还是CUS H264。两种格式在画面渲染上有所不同。 getPrimaryVideoFeed()和getSecondaryVideoFeed()可以获取到的是DJI H264。你可以参考这篇文章里的获取CUS H264视频流的方法能否获取到视频流数据:MSDK 4.14如何显示PSDK开发的相机的视频流? 获取到视频流之后将其送入到codecManager.sendDataToDecoder进行编解码,因为codecManager在初始化的时候已经传入了View,编解码之后的数据就会渲染到对应的view里。
    0
    评论操作 固定链接
  • Caiyixun

    是解码不同导致的无法识别相机源吗?我试试看CUS H264.

    另外,Demo中getPrimaryVideoFeed()和getSecondaryVideoFeed()获取到的是DJI H264。也有经过codecManager.sendDataToDecoder进行编解码吗?

    0
    评论操作 固定链接
  • Caiyixun

    我确认了一遍,视频流格式确实是CUS H264。但是有个疑问,为什么M210可以显示视频?我想先确认问题再进行解决。目前就是云台相机是CUS H264格式的,有两个飞机M210和M300以及他们各自的遥控器。我APP(demo)写在iPad上,用数据线连接遥控器。M210可以显示视频流,M300不能显示视频流。如果是解码有问题的话,为什么同一个demo,M210可以显示视频流啊?

    0
    评论操作 固定链接
  • DJI Developer Support
    我确认了一遍,视频流格式确实是CUS H264。但是有个疑问,为什么M210可以显示视频?我想先确认问题再进行解决。目前就是云台相机是CUS H264格式的,有两个飞机M210和M300以及他们各自的遥控器。我APP(demo)写在iPad上,用数据线连接遥控器。M210可以显示视频流,M300不能显示视频流。如果是解码有问题的话,为什么同一个demo,M210可以显示视频流啊? -->应该与M300上新增了数据传输通道有关。 M300为了传输新增了MOP通道,因此视频格式不同采用的传输数据通道也不同。如果是CUS H264建议都使用这篇文章方法:MSDK 4.14如何显示PSDK开发的相机的视频流? Demo中getPrimaryVideoFeed()和getSecondaryVideoFeed()获取到的是DJI H264。也有经过codecManager.sendDataToDecoder进行编解码吗? -->是的,获取到的视频流数据都会送到codecManager进行编解码。
    0
    评论操作 固定链接
  • Caiyixun

    无人机有FPV,如果直接重写了,是否会影响到FPV的画面获取?是否会影响到FPV的画面获取?我要在哪个地方重写?(初步设想是在PayloadSendGetDataActivity.java类中进行重写,这个可以吗?)。而且重写之后,不再使用getPrimaryVideoFeed()和getSecondaryVideoFeed()了吗?原来使用这两个方法函数获取视频流的要怎么改?

    如果不在payload下改的话,是在这个地方改吗?

    实在是不知道重写在哪里,因为我看官方的文档,setVideoDataReceivedCallback有三个重载,void sendDataToDecoder(byte[] videoBuffer, int size, VideoSource source)和void sendDataToDecoder(byte[] videoBuffer, int size, int source)我不知道他们的区别,以及他们是通过哪个参数来知道是获取的格式是DJI H264的还是CUS H264的。

    0
    评论操作 固定链接
  • Caiyixun

    还是说,获取视频流数据方法类依旧是一样的,使用的还是getPrimaryVideoFeed()和getSecondaryVideoFeed()。只是在解码时不再使用官方的,而是使用自己重写的。

    0
    评论操作 固定链接
  • DJI Developer Support
    1.getPrimaryVideoFeed和getSecondaryVideoFeed获取到的是主副视频源视频流。当你需要获取FPV画面,且FPV是主副视频流中的一个的时候需要使用到这两个接口获取流数据。M300需要配分视频源:M300开机后为什么不显示视频流? 2.sendDataToDecoder有三个重载函数,可以只传入videoBuffer和size。sendDataToDecoder不区分DJI H264还是CUS H264,都可以使用。 3.根据上面两点,videoFeedView是用于获取视频流数据进行编解码,因此基本上不需要改动。如果需改动可以将第三个参数省掉。 因为你使用的是第三方负载,需要在videoFeederView里修改获取视频源数据的逻辑,也就是这篇文章提到的内容:MSDK 4.14如何显示PSDK开发的相机的视频流?
    0
    评论操作 固定链接
  • Caiyixun

    你推荐的那个文章我看过了,只有一个判断是不是CUS H264编码比较具体,其他的都太模糊了,而且我使用的是官方Demo,我怀疑应该是通道没开吧?如果M300新增了数据传输通道,反正我M210用demo跑能显示画面,我把M300新增的那个通道开了不行吗?

    这一块应该是分配端口带宽吧?

    0
    评论操作 固定链接
  • Caiyixun

    你介绍的那篇文字,实在太短了。我对照着Simple Demo找,发现VideoFeederView.java和VideoFeedView.java都没有用到payload的,不知道是不是写在了你们的SDK里面,所以,我实在不知道

    payload.setVideoDataReceivedCallback(new Payload.VideoDataReceivedCallback() {
    @Override
    public void onVideoDataReceived(byte[] var1, int var2) {
    if (mCodecManager != null) {
    mCodecManager.sendDataToDecoder(var1, var2, DJICodecManager.VideoSource.SECONDARY_CAMERA);
    }
    }
    });

    这个重写代码片段要在哪里实现才能用,而且哪怕写在了VideoFeederView.java里面了,如何使用啊?

    0
    评论操作 固定链接
  • Caiyixun

    目前问题就在这里,我做了一次判断,如果是DJI H264,则正常的用getPrimaryVideoFeed拿视频流数据,并使用registerLiveVideo函数。registerLiveVideo函数内会进行videoFeed.addVideoDataListener。

    现在是如果不是DJI H264编码的,我要怎么进行拿数据?并且要添加videoFeed.addVideoDataListener。

    如果依旧是使用原来的registerLiveVideo方法,第一个参数如何得到(DJI H264是用getPrimaryVideoFeed得到的),如果是用payload.setVideoDataReceivedCallback,如何能得到第一个参数的类型,以进行传参?

    0
    评论操作 固定链接
  • DJI Developer Support
    现在是如果不是DJI H264编码的,我要怎么进行拿数据?并且要添加videoFeed.addVideoDataListener。 -->M300获取视频流可以来自两种设备,一种是DJI云台相机,一种是第三方负载,第三方负载根据使用的视频格式分为DJI H254和CUS H264。DJI H264和DJI云台获取视频流使用的是同一种方法,也就是videoFeederView示例代码中的方法:VideoFeeder.getPrimaryVideoFeed再通过addVideoDataListener获取数据。 开发的时候需要判断你挂载的相机是camera还是payload,可以通过getCameras和Aircraft.getpayload获取到飞机当前挂载两种负载的列表,然后通过getIndex获取到负载的位置以判断负载,也可以通过负载名称进行判断。 如果是payload负载,此时可以通过isDJIVideoStreamingChannelAvailable判断是哪种类型。在确认是CUS H264之后,通过payload.setVideoDataReceivedCallback获取视频流数据。sample将注册DJI格式的视频流回调放置在了videoFeedView里,CUS H264需要另外处理。至于将处理CUS H264的代码放置在哪里需要由您自己决定。你可以在videoFeedView新增一个register方法用来实现cus H264的回调注册,逻辑可以参考原本的registerLiveVideo方法。
    0
    评论操作 固定链接
  • Caiyixun

    抱歉,还是实现不了,感觉就是黑盒,可能是我能力不够吧。

    0
    评论操作 固定链接
  • DJI Developer Support
    你是对于那些方面还存在疑惑呢?如果是在基于sample上修改存在困难,可以先从头开始创建一个页面用于展示负载的画面。实现了显示画面之后再考虑整合。
    0
    评论操作 固定链接
  • Caiyixun

    主要还是没有样例。而里面很多方法函数又是大疆开发的函数。就比如payload.setVideoDataReceivedCallback。重写了方法,如何使用?他是怎么和视图绑在一起的?(换句话说,APP怎么知道执行这个方法函数后应该把视频显示在哪个视图上的?)第二,这个函数获取视频流数据,是如何绑定监听的?我目前的一切都是官方的Demo,没修改,只是读程序,看运行状态、结果。

    0
    评论操作 固定链接
  • Caiyixun

    我重新看了代码,视图绑定那一块我看到了,现在最大的问题还是监听的绑定以及回调函数的处理。因为前面对照着,VideoFeeder.VideoFeed有内置的函数方法设置监听,但现在我不用这个了,改用payload.setVideoDataReceivedCallback,如何监听。

    0
    评论操作 固定链接
  • Caiyixun

    我再试试吧,如果还不行就得放弃了。网上其他参考资料基本上没有

    0
    评论操作 固定链接
  • DJI Developer Support
    **payload.setVideoDataReceivedCallback。重写了方法,如何使用?这个函数获取视频流数据,是如何绑定监听的?** **改用payload.setVideoDataReceivedCallback,如何监听?** -->payload.setVideoDataReceivedCallback是用于传入回调的接口,你可以理解为setVideoDataReceivedCallback就是设置了相机视频流数据的监听。MSDK内部对外是透明的,您可以不需要关注具体实现。简单来说,您按照setVideoDataReceivedCallback要求传入对应的callblack就可以实现相机挂载在M300上被识别且成功运行之后获取到负载的视频流数据,如下: ![](https://djisdksupport.zendesk.com/attachments/token/bNu6MDWsMkt4R5sIZWFcWWmhh/?name=image.png) 参数定义: ![](https://djisdksupport.zendesk.com/attachments/token/XoWd8DrA7IBrb0dUOJyuTJT96/?name=image.png) **他是怎么和视图绑在一起的?他是怎么和视图绑在一起的?(换句话说,APP怎么知道执行这个方法函数后应该把视频显示在哪个视图上的?)** -->DJICodecManager作为编解码器,它绑定了视图,即下面红色箭头所指的参数。 ![](https://djisdksupport.zendesk.com/attachments/token/KwaiUcynyRzPnp3561Q27Hw97/?name=image.png) ![](https://djisdksupport.zendesk.com/attachments/token/14PN761lSRPR7fC5KXjRhUwhE/?name=image.png) ![](https://djisdksupport.zendesk.com/attachments/token/zJplqlori75roCFs7oP0DjR8F/?name=image.png) 您可以先利用sample和API文档学习一下如何使用MSDK的接口,API文档中会描述函数的作用以及传入参数的含义。API文档:https://developer.dji.com/api-reference/android-api/Components/SDKManager/DJISDKManager.html
    0
    评论操作 固定链接
  • Caiyixun

    你说的后面那个我懂,就是前面的payload.setVideoDataReceivedCallback有问题。

    您按照setVideoDataReceivedCallback要求传入对应的callblack就可以实现相机挂载在M300上被识别且成功运行之后获取到负载的视频流数据-->就是这一块有问题!上面那个是回调函数,但是我不知道哪里调用他,传入哪个对应的callblack。

    目前我在V4的官方Demo。目前就是:我有两个VideoFeedView类型的变量。这个VideoFeedView类下有各自的View,并且绑定好了对应的(不用考虑)。同时VideoFeedView类下同时也有codecManager,进行了

    codecManager = new DJICodecManager(context,
    surfaceHolder,
    getWidth(),
    getHeight(),
    isPrimaryVideoFeed
    ? UsbAccessoryService.VideoStreamSource.Camera
    : UsbAccessoryService.VideoStreamSource.Fpv)

    绑定,这些我知道。

    现在我之所以不会,是因为不知道setVideoDataReceivedCallback是需要在哪里调用的,传入什么样的参数。

    我初步设想是

    payload.setVideoDataReceivedCallback(new Payload.VideoDataReceivedCallback() {
    @Override
    public void onVideoDataReceived(byte[] var1, int var2) {
    if (codecManager != null) {
    codecManager.sendDataToDecoder(var1, var2, DJICodecManager.VideoSource.CAMERA);
    }
    }
    })

    将这个方法写在VideoFeedView.java这个类下,因为这样拿的codecManager就是已经绑定好视图的codecManager。写完这个方法,它并不会自动调用啊,需要我们去调用吧,还有就是解码完,总有监听吧?

    像示例写的那个:

    public VideoFeeder.VideoDataListener registerLiveVideo(VideoFeeder.VideoFeed videoFeed, boolean isPrimary) {
    isPrimaryVideoFeed = isPrimary;

    if (videoDataListener != null && videoFeed != null && !videoFeed.getListeners().contains(videoDataListener)) {
    videoFeed.addVideoDataListener(videoDataListener);
    return videoDataListener;
    }
    return null;
    }

    本来我也打算仿写,但是没有第一个参数VideoFeeder.VideoFeed videoFeed,因为这个参数刚刚好就是VideoFeeder.getPrimaryVideoFeed拿到的,而我们使用的是setVideoDataReceivedCallback。我拿不到任何一个像VideoFeeder.VideoFeed类型的变量,来添加监听。

    0
    评论操作 固定链接
  • Caiyixun

    还是说

    payload.setVideoDataReceivedCallback(new Payload.VideoDataReceivedCallback() {
    @Override
    public void onVideoDataReceived(byte[] var1, int var2) {
    if (codecManager != null) {
    codecManager.sendDataToDecoder(var1, var2, DJICodecManager.VideoSource.CAMERA);
    }
    }
    })

    这段函数写在VideoFeedView.java这个类下就行了,我们并不需要去调用它,它自己就能发挥作用了?

    我们只需要在我们模仿registerLiveVideo写一个类似的方法,依旧用VideoFeeder.getPrimaryVideoFeed拿到protected VideoFeed primaryVideoFeed变量,然后addVideoDataListener就可以了?

    0
    评论操作 固定链接
  • Caiyixun

    我应该是解决了编码的问题了。但是好像产生了通道占用?就是不加下面这段代码时:

    payload.setVideoDataReceivedCallback(new Payload.VideoDataReceivedCallback() {
    @Override
    public void onVideoDataReceived(byte[] var1, int var2) {
    if (codecManager != null) {
    codecManager.sendDataToDecoder(var1, var2, DJICodecManager.VideoSource.CAMERA);
    }
    }
    })

    第三方负载相机确实没画面。在我加了这段代码之后,我测试过了,会有一瞬间的画面,然后就被fpv的画面占用了。如果不加上面那段代码,那一瞬间的画面都没有,加了之后,有一瞬间的画面,之后就迅速被fpv画面挤占,而第二个画面一直是黑屏的。

    0
    评论操作 固定链接
  • Caiyixun

    这是VideoFeederView.java上的关键代码。

    因为我固定知道挂载相机是CUS H264编码的,FPV是DJI H264,所以就没判断了,而是一个用CUSregisterLiveVideo函数,一个用registerLiveVideo

    private void setVideoFeederListeners(boolean isOpen) {
    if (VideoFeeder.getInstance() == null) return;

    final BaseProduct product = DJISDKManager.getInstance().getProduct();
    updateM210SeriesButtons();
    updateM300Buttons();
    if (product != null) {
    payload=product.getPayload();

    VideoFeeder.VideoDataListener primaryVideoDataListener = primaryVideoFeed.CUSregisterLiveVideo(VideoFeeder.getInstance().getPrimaryVideoFeed(), true);
    VideoFeeder.VideoDataListener secondaryVideoDataListener = fpvVideoFeed.registerLiveVideo(VideoFeeder.getInstance().getSecondaryVideoFeed(), false);


    if (isOpen) {
    String newText =
    "Primary Source: " + VideoFeeder.getInstance().getPrimaryVideoFeed().getVideoSource().name();
    ToastUtils.setResultToText(primaryVideoFeedTitle, newText);
    if (Helper.isMultiStreamPlatform()) {
    String newTextFpv = "Secondary Source: " + VideoFeeder.getInstance()
    .getSecondaryVideoFeed()
    .getVideoSource()
    .name();
    ToastUtils.setResultToText(fpvVideoFeedTitle, newTextFpv);
    }
    VideoFeeder.getInstance().addPhysicalSourceListener(sourceListener);
    } else {
    VideoFeeder.getInstance().removePhysicalSourceListener(sourceListener);
    VideoFeeder.getInstance().getPrimaryVideoFeed().removeVideoDataListener(primaryVideoDataListener);
    if (Helper.isMultiStreamPlatform()) {
    VideoFeeder.getInstance()
    .getSecondaryVideoFeed()
    .removeVideoDataListener(secondaryVideoDataListener);
    }
    }
    }
    }

    这是VideoFeedView.java上关键代码:

    public VideoFeeder.VideoDataListener registerLiveVideo(VideoFeeder.VideoFeed videoFeed, boolean isPrimary) {
    isPrimaryVideoFeed = isPrimary;

    if (videoDataListener != null && videoFeed != null && !videoFeed.getListeners().contains(videoDataListener)) {
    videoFeed.addVideoDataListener(videoDataListener);
    return videoDataListener;
    }
    return null;
    }

    //修改3
    public VideoFeeder.VideoDataListener CUSregisterLiveVideo(VideoFeeder.VideoFeed videoFeed, boolean isPrimary) {
    isPrimaryVideoFeed = isPrimary;
    if(ModuleVerificationUtil.isPayloadAvailable()){
    payload = DJISampleApplication.getAircraftInstance().getPayload();
    payload.setVideoDataReceivedCallback(new Payload.VideoDataReceivedCallback() {
    @Override
    public void onVideoDataReceived(byte[] var1, int var2) {
    if (codecManager != null) {
    //修改2
    codecManager.sendDataToDecoder(var1, var2, DJICodecManager.VideoSource.CAMERA);
    }
    }
    });
    }
    if (videoDataListener != null && videoFeed != null && !videoFeed.getListeners().contains(videoDataListener)) {
    videoFeed.addVideoDataListener(videoDataListener);
    return videoDataListener;
    }
    return null;
    }

     

    0
    评论操作 固定链接

请先登录再写评论。