Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RTP streaming issues with the DJI Mini SE #1

Open
kripper opened this issue Feb 25, 2023 · 17 comments
Open

RTP streaming issues with the DJI Mini SE #1

kripper opened this issue Feb 25, 2023 · 17 comments

Comments

@kripper
Copy link

kripper commented Feb 25, 2023

Hi @roguestarslade,

Have you tried Rosetta Drone?
https://github.com/The1only/rosettadrone

I came to your fork because I'm working on fixing the video stream decoding for the Mini.
We are receiving the decoded buffer on onDataRecv() and then send it via RTP.
But I believe we are doing something wrong in this process:
RosettaDrone/rosettadrone#27

@roguestarslade
Copy link
Owner

roguestarslade commented Feb 25, 2023

Hi @roguestarslade,

Have you tried Rosetta Drone? https://github.com/The1only/rosettadrone

I'm aware of the project, but haven't checked it out recently. Its been a couple years, but I think I can catch up when I have free time.

I came to your fork because I'm working on fixing the video stream decoding for the Mini. We are receiving the decoded buffer on onDataRecv() and then send it via RTP. But I believe we are doing something wrong in this process: The1only/rosettadrone#27

Well well well.... I've been encountering this same error working on the DJI side too. Same stack : a project I'm working on has RTSP, and we see some choppiness coming in from the video on the DJI side. (Im working on this same issue in one of my DJI projects actually. So I'll clue you in...)

Here's what you can do :

  • try to find a way to throttle the DJI video stream. I'm not sure how rosettadrone does it, but you need to somehow make DJIs video stream not send so much data.

  • DJI side is basically send waaaay too much data. So you'll need to squeeze off that hose, and see what can be fixed from video.

Unfortunately I can't share source due to proprietary stuff I'm working on :/ Best I can do is share clues from the above.

@kripper
Copy link
Author

kripper commented Feb 26, 2023

Hi @roguestarslade,

I forked your repo and added code for RTP streaming with a minimal commit: RosettaDrone@9d31891

This code is supposed to be working fine for other models, but not for the Mini.

@kripper
Copy link
Author

kripper commented Feb 26, 2023

What I found strange is that the sample code obtains a keyframe using this magical getIframeRawId() function and this keyframe is added only once!

hasIFrameInQueue is set to false only in releaseCodec() and stop().

@kripper
Copy link
Author

kripper commented Feb 26, 2023

I updated the code to enable streaming RTP with Unicast (Multicast didn't work for us).
6924305

In our code, we split the NALs to solve the problem of sending to big UDP packets, which are automatically splitted and received without headers.

In this commit, I added a boolean "splitNALs" that can be modified using the debugger to disable the NAL splitting during runtime.
I discovered that disabling this boolean after the client started to receive the stream, improved the quality significantly, which means that we are probably doing something wrong in the NAL splitting code.
Without NAL splitting, gstreamer was not able to open the stream at all.

@kripper kripper changed the title Join the Rosetta Drone Project RTP streaming issues with the DJI Mini Feb 26, 2023
@roguestarslade
Copy link
Owner

I updated the code to enable streaming RTP with Unicast (Multicast didn't work for us). 6924305

In our code, we split the NALs to solve the problem of sending to big UDP packets, which are automatically splitted and received without headers.

In this commit, I added a boolean "splitNALs" that can be modified using the debugger to disable the NAL splitting during runtime. I discovered that disabling this boolean after the client started to receive the stream, improved the quality significantly, which means that we are probably doing something wrong in the NAL splitting code. Without NAL splitting, gstreamer was not able to open the stream at all.

hey @belveder79 check this out.

@roguestarslade roguestarslade reopened this Mar 2, 2023
@belveder79
Copy link

hmmm... @roguestarslade my assumption is that at this point

the stream from the Drone was received correctly, which means that the buffer contains valid NAL units (and only complete NAL units). What we do next is hand that buffer over to a streaming library, and this library creates a new RTP stream out of that and wraps it into RTSP, therefore the underlying library is responsible for not overshooting the packet size that can be reliably used over TCP or UDP. There is no custom code required to split NAL units... if the splitting in the streaming library itself wouldn't work (respectively the assembly on the receiving end), you would never get a frame at all...

Now what is an obvious issue is that if TCP is not used, the packets might get lost or the order is not preserved, which is a network issue and you can't really do anything about it. Assuming that your receiving device is actually close to the stream destination or you have a good quality of connection between the receiving device (the DJI app) and your final end point, having issues like that are unlikely to occur imho.

What is less obvious (and I did not dive into that too much to be honest) is that my assumption about the status of the stream at the above mentioned position is wrong. Say there are valid NAL units, but there are also incomplete NAL units, as - for whatever reason - it is just a snapshot of the underlying receive buffer from DJI. Whatever is after the last valid NAL unit is discarded then and you would loose some data (namely exactly the unit that falls on the border between two calls to handover message to the streaming library). This is actually a pretty unusual behaviour that would never occur if you get the stream straight from an encoder, but who knows?

JNIEXPORT jboolean Java_com_dji_videostreamdecodingsample_media_NativeHelper_parse(JNIEnv *env, jobject obj, jbyteArray pBuff, int size)

I will have a look at this... probably this is what happens at least on our side...

@kripper
Copy link
Author

kripper commented Mar 3, 2023

Yes, the frames are correctly enqueued, dequeued, decoded and presented on the screen. Even when you discard 59 frames from 60, you will still get a perfect video on the screen.
The NALU splitting seems to be necessary for RTP streaming, because otherwise the receiver (gstreamer) complains of an invalid stream.

Have you tried my fork? What aircraft model are you using?
https://github.com/kripper/DJI-Android-VideoStreamDecodingSample

@belveder79
Copy link

No I did not as I was just on the project about the streaming... what do you mean by discarding 59 out of 60 frames? Are you talking about NAL units?

@kripper
Copy link
Author

kripper commented Mar 3, 2023

We did some tests just ignoring the callback that receives the buffer from the SDK (eg. just processing the data once each 60 times), and the video was still showing almost perfect on the screen.

My understanding is that this buffer contains multiple NAL units and that they must be split before sending them via UDP.

@belveder79
Copy link

sorry, I think that there is a misunderstanding or we talk past each other, because what you are saying does not make any sense to me...

of course you need to split NAL units, even individual ones, such that they can be put into RTP packets meeting the requirements for reliable network transfer... however, you cannot just skip calls to

int parse(JNIEnv *env, jobject obj, uint8_t* pBuff, int videosize, uint64_t pts)

and claim to get a perfect video, otherwise the data would have to be redundant, which it certainly is not...

@kripper
Copy link
Author

kripper commented Mar 4, 2023

We are parsing in the same way as the example. We split and send the NALUs on the message dequeue code just before the buffer is sent to the MediaCodec decoder for the onscreen rendering.

I'm not saying that the data is redundant, but confirming that the video buffer if received correctly, that it is tolerant and that whatever problem we may experience on the RTP receiver is not caused by missing or dropped packets but by some kind of corruption we are introducing probably in the NALU splitting process which may be incompatible with the specific format of the Mini SE (other models work fine).

Please note I don't know how you are RTP streaming and haven't seen your code.
I'm talking about the RTP streaming code I published here:
https://github.com/kripper/DJI-Android-VideoStreamDecodingSample

@belveder79
Copy link

Ah, ok, now I got it...

Quickly browsing through your code I realized that you never call setStreamParameters on the Packetizer. You could try to filter the first NAL unit with type 7 and 8 and pass that as SPS and PPS bytes before sending the first packet, probably the Packetizer needs some information ahead of time...

what does the SetUseDualVideoOut do? It appears to me it sends the data twice over two ports? Is that required?

@kripper
Copy link
Author

kripper commented Mar 4, 2023

SetUseDualVideoOut is used by Rosetta to send the video to two receivers using Unicast. It is not required.

Are you receiving the stream correctly? What model are you testing?

@roguestarslade
Copy link
Owner

Are you receiving the stream correctly? What model are you testing?

We can receive the stream from a Mavic 2 Pro and Mini 2

@kripper
Copy link
Author

kripper commented Mar 8, 2023

Thanks. Can you please confirm you are using my fork (https://github.com/kripper/DJI-Android-VideoStreamDecodingSample) and which gstreamer command line you used to receive the stream?

@kripper
Copy link
Author

kripper commented Mar 14, 2023

@roguestarslade can you please confirm if you are referring to my fork and which gstreamer command line you used for receiving the stream? Thanks.

@kripper
Copy link
Author

kripper commented Mar 16, 2023

@roguestarslade Just in case, I added detailed instructions how to test the RTP Streaming:
https://github.com/kripper/DJI-Android-VideoStreamDecodingSample/blob/develop/README.md

@kripper kripper changed the title RTP streaming issues with the DJI Mini RTP streaming issues with the DJI Mini SE Apr 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants