从 DJI 无人机到本地服务器直播的最佳设置是什么?



我需要使用 Android Mobile SDKDJI 无人机的视频直播数据流式传输到本地服务器。来自服务器的视频数据将由其他软件处理(人工识别(。证明最佳流媒体质量的推荐方法是什么?我们使用 Mavic 2 进行开发,使用 Matrice 210 v2 RTK 进行生产。因此,答案应该主要集中在经纬 M210 v2 RTK 的可能性上。

目前我们使用DJI的直播管理器是这样的

DJISDKManager.getInstance().getLiveStreamManager().setLiveUrl( rtmpURL );
DJISDKManager.getInstance().getLiveStreamManager().startStream(); 

我们使用带有rtmp模块的nginx Webserver作为流式处理端点,将流推送到网络并同时将流记录到磁盘。这有效,但我们看到此流的质量很差。该流经常滞后,并且它像素化为更快的无人机运动。

由于我不熟悉视频处理,我需要建议如何解决此要求。我的问题如下: -我是否需要使用 ffmpeg 库以某种方式预处理流? -后端服务器有没有比nginx+rtmp模块更好的解决方案? -是否可以利用矩阵遥控器的输出来提供更高的质量?

- 我需要使用 ffmpeg 库以某种方式预处理流吗?

如果你想自己处理流,你需要使用 ffmpeg 将原始直播解码为实际的图片帧。请参阅我对问题3的回答。

-后端服务器有没有比nginx+rtmp模块更好的解决方案?

这在很大程度上取决于用例。如果您对视频质量不满意,使用 ffmpeg 自己解码流会更可靠。我实际上不知道nginx + rtmp自动做了多少,因为我从未使用过它。

-是否可以利用矩阵遥控器的输出来提供更高的质量?

可以使用 SDK 访问的原始直播是原始 h264 或 h265 流(NAL 单位(,具体取决于所使用的无人机型号。

在我的应用程序中,我使用相机组件Key在onComponentChange方法中注册VideoDataCallback,并通过LocalBroadcastManager将其发送出去。 然后,只需订阅广播,即可在应用程序中的任何位置访问直播。

private VideoFeeder.VideoDataListener videoDataCallback = (videoBuffer, size) -> {
        Intent intent = new Intent("videoStream");
        intent.putExtra("content", videoBuffer);
        intent.putExtra("size", size);
        LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
    };

通过网络发送直播的一种简单方法是使用 TCP 套接字:启动一个线程并使用 IP 和端口打开一个套接字:

this.s = new Socket(this.ipAddress, this.port);
this.s.setKeepAlive(true);
this.s.setTcpNoDelay(true);
this.dos = new DataOutputStream(this.s.getOutputStream());

如果连接/发送失败,请放置一个循环以重新连接它。 在 BroadcastReceiver 中,通过分析大小来累积字节(bos 是一个简单的 ByteArrayOutputStream(:

private BroadcastReceiver frameReceiverNAL = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
        try {
            int frameSize = intent.getIntExtra("size", 0);
            if(frameSize == 2032) {
                bos.write(intent.getByteArrayExtra("content"), 0, frameSize);
            } else {
                bos.write(intent.getByteArrayExtra("content"), 0, frameSize);
                final byte[] sendUnit = bos.toByteArray();
                bos.reset();
                if(numAsyncTasks < MAX_NUMBER_ASYNCTASKS) {
                    numAsyncTasks++;
                    AsyncTask.execute(() -> sendNAL(sendUnit));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        }
    };
private void sendNAL(byte[] sendUnit){
        try {
            if(dos != null) {
                dos.write(sendUnit);
                dos.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        numAsyncTasks--;
    }

MAX_NUMBER_ASYNCTASKS用作上限,以防止应用程序在无法足够快地发送 NAL 时崩溃(导致崩溃前有 500+ 个未完成的 AsyncTasks(。就我而言,我将数字设置为 128。

在服务器端,您需要创建一个 ServerSocket 来接收字节流。根据编程语言的不同,您可以直接使用 ffmpeg 或使用本机接口,例如 bytedeco 从流中创建帧。

另一种方法是将智能手机上的流解码为 YUV 图像(每个 2.8MB(,并可选择将它们转换为 jpeg 以减小单个帧的大小(每个 ~100KB(。然后可以使用 TCP 套接字将 YUV 或 jpeg 图像发送到服务器。SDK 提供了一种在 DJICodecManager 类中创建 YUV 图像的方法,教程包含将它们转换为 JPEG 的示例。

最新更新