You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DJI SDK 5.1.7 Android主通道RTMP推流致APP崩溃问题排查

DJI SDK 5.1.7 Android应用RTMP推流几分钟后崩溃问题

适配DJI Mini 3,运行在三星Galaxy S22设备上,基于SDK 5.1.7的示例代码开发。将视频通过主通道推流至云端RTMP服务器几分钟后APP崩溃,相关代码和崩溃日志如下:

HomeFragment.onCreateView相关代码

// 流源更新时触发的监听器
MediaDataCenter.getInstance().getVideoStreamManager().addStreamSourcesListener
        (sources -> getActivity().runOnUiThread(() -> updateFPVWidgetSource(sources)));
primaryFpvWidget.setOnFPVStreamSourceListener((devicePosition, lensType) -> {
    cameraSourceProcessor.onNext(new HomeFragment.CameraSource(devicePosition, lensType));
});

IVideoChannel primaryChannel =
        MediaDataCenter.getInstance().getVideoStreamManager().getAvailableVideoChannel(VideoChannelType.PRIMARY_STREAM_CHANNEL); 
if (primaryChannel != null) {
    primaryChannelStateListener = (from, to) -> {
        StreamSource primaryStreamSource = primaryChannel.getStreamSource();
        if (VideoChannelState.ON == to && primaryStreamSource != null) {
           
            getActivity().runOnUiThread(() -> primaryFpvWidget.updateVideoSource(primaryStreamSource, VideoChannelType.PRIMARY_STREAM_CHANNEL));

        }
    };
    primaryChannel.addVideoChannelStateChangeListener(primaryChannelStateListener);

独立线程启动推流的代码

ILiveStreamManager liveStreamManager = MediaDataCenter.getInstance().getLiveStreamManager();

LiveStreamSettings.Builder lssBuilder = new LiveStreamSettings.Builder();

RtmpSettings.Builder b = new RtmpSettings.Builder();
b.setUrl(liveURL);
RtmpSettings rtmp = b.build();
lssBuilder.setRtmpSettings(rtmp);
lssBuilder.setLiveStreamType(LiveStreamType.RTMP);
LiveStreamSettings lss = lssBuilder.build();

liveStreamManager.setLiveStreamSettings(lss);

// 本地预览用主通道,必须设置为PRIMARY否则看不到视频
liveStreamManager.setVideoChannelType(VideoChannelType.PRIMARY_STREAM_CHANNEL);
liveStreamManager.setLiveStreamQuality(StreamQuality.SD); // 尝试降低画质
//liveStreamManager.setLiveVideoBitrate(2048); // 低比特率
liveStreamManager.setLiveVideoBitrateMode(LiveVideoBitrateMode.AUTO);

liveStreamManager.startStream(new CommonCallbacks.CompletionCallback() {...}

崩溃日志

2023-11-03 14:42:44.584 14829-14829/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:44.584 14829-14829/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:44.589 12914-12988/com.tbolt.main E/fdsan: failed to exchange ownership of file descriptor: fd 297 is owned by unique_fd 0x6e6ca9d75c, was expected to be unowned
2023-11-03 14:42:44.620 12914-14680/com.tbolt.main E/co_b: (co_a:86) checkFrame() lastId = 18150 id=18156
2023-11-03 14:42:44.776 12914-12988/com.tbolt.main E/fdsan: attempted to close file descriptor 297, expected to be owned by unique_fd 0x6e6ca9dd9c, actually owned by unique_fd 0x6e6ca9d75c
2023-11-03 14:42:44.963 14834-14834/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:44.963 14834-14834/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:44.974 12914-14824/com.tbolt.main E/fdsan: failed to exchange ownership of file descriptor: fd 297 is owned by unique_fd 0x6e6ca9d75c, was expected to be unowned
2023-11-03 14:42:45.081 12914-14687/com.tbolt.main W/DJIV5/co_c@1a50a50: (co_b:99) onOutputFrame() frame index:18161
2023-11-03 14:42:45.161 12914-14688/com.tbolt.main E/co_b: (co_a:104) checkFrame()  len=6840 checkLen=11802 seiOffset:6854
2023-11-03 14:42:45.167 12914-12985/com.tbolt.main A/libc: Fatal signal 11 (SIGSEGV), code -6 (SI_TKILL) in tid 12985 (com.tbolt.main), pid 12914 (com.tbolt.main)
2023-11-03 14:42:45.201 12914-14685/com.tbolt.main E/co_b: (co_a:86) checkFrame() lastId = 18163 id=18166
2023-11-03 14:42:45.204 12914-12988/com.tbolt.main E/fdsan: attempted to close file descriptor 297, expected to be owned by unique_fd 0x6e6ca9abdc, actually owned by unique_fd 0x6e6ca9d75c
2023-11-03 14:42:45.332 14840-14840/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:45.332 14840-14840/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:45.682 14846-14846/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:45.682 14846-14846/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:45.710 12914-14680/com.tbolt.main E/co_b: (co_a:86) checkFrame() lastId = 18175 id=18178
2023-11-03 14:42:46.049 14852-14852/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:46.049 14852-14852/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:46.368 12914-14687/com.tbolt.main W/DJIV5/co_c@1a50a50: (co_b:99) onOutputFrame() frame index:18194
2023-11-03 14:42:46.429 14859-14859/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:46.429 14859-14859/? A/DEBUG: pid: 12914, tid: 12914, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:46.812 14864-14864/? A/DEBUG: Cmdline: com.tbolt.main
2023-11-03 14:42:46.812 14864-14864/? A/DEBUG: pid: 12914, tid: 12985, name: com.tbolt.main  >>> com.tbolt.main <<<
2023-11-03 14:42:46.856 2299-14876/? W/ActivityManager: crash : com.tbolt.main,10274
2023-11-03 14:42:46.856 2299-14876/? W/ActivityTaskManager:   Force finishing activity com.tbolt.main/.MainActivity
2023-11-03 14:42:46.985 2299-5904/? W/InputManager-JNI: Input channel object 'bebdddd com.tbolt.main/com.tbolt.main.MainActivity (client)' was disposed without first being removed with the input manager!

问题:请问我哪里操作出错了?


问题分析与解决方案

从崩溃日志来看,核心是文件描述符所有权冲突,伴随视频帧校验失败,最终触发SIGSEGV崩溃。结合代码和SDK特性,修复方向如下:

1. 主通道资源冲突

你将PRIMARY_STREAM_CHANNEL同时用于本地预览和推流,部分机型上DJI SDK主通道无法同时承载两路视频消费(本地渲染+推流编码),导致底层资源竞争。

修复:改用次要通道推流,主通道仅用于预览:

liveStreamManager.setVideoChannelType(VideoChannelType.SECONDARY_STREAM_CHANNEL);

同时参照主通道逻辑,初始化并监听次要通道的状态,确保推流前通道已就绪。

2. 文件描述符泄漏/重复操作

日志中的fdsan错误表明文件描述符被重复释放或所有权混乱,多因监听器和资源未及时清理导致。

修复:

  • 在Fragment销毁时移除所有监听器:
@Override
public void onDestroyView() {
    super.onDestroyView();
    if (primaryChannel != null && primaryChannelStateListener != null) {
        primaryChannel.removeVideoChannelStateChangeListener(primaryChannelStateListener);
    }
    MediaDataCenter.getInstance().getVideoStreamManager().removeStreamSourcesListener(/* 对应的监听器实例 */);
}
  • 停止推流时调用liveStreamManager.stopStream(),确保资源释放。

3. 视频帧校验异常

checkFrame()的帧长度、ID跳变错误,与比特率设置或通道资源不足有关。

修复:

  • 关闭比特率自动模式,手动设置固定值:
liveStreamManager.setLiveVideoBitrateMode(LiveVideoBitrateMode.MANUAL);
liveStreamManager.setLiveVideoBitrate(1024); // 匹配SD画质的合理值,避免编码压力过大
  • 确保视频通道状态稳定为ON后再启动推流,不要在连接初期仓促触发。

4. 线程安全问题

推流初始化操作跨线程执行可能引发资源竞争,SDK部分操作需在主线程完成。

修复:将推流的配置和启动逻辑移至主线程:

getActivity().runOnUiThread(() -> {
    // 放置推流初始化和startStream的代码
});

内容的提问来源于stack exchange,提问作者Lillian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 01:54:51