Closed js1972 closed 4 years ago
It is possible that the parameters used to create the HLS session are to blame, not the gstreamer parameters.
Are you using SERVER_TIMESTAMP or PRODUCER_TIMESTAMP mode? You probably want PRODUCER_TIMESTAMP.
And what DiscontinuityMode are you using? You probably want ON_DISCONTINUITY.
See https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_reader_GetHLSStreamingSessionURL.html
I have tried setting those values and there is an improvement but I still get the issue every so often. It's hard to say how often. As it will fail a couple of times, then work the next 9 or 10 times in a row.
Interestingly it seems to be the first time I look at a stream in a while. If I stop then start it again it works. Here's my settings from the getHLSStreamingSessionURL
call:
'StreamName': streamName,
'PlaybackMode': 'LIVE',
'DiscontinuityMode': 'ON_DISCONTINUITY',
'HLSFragmentSelector': {
'FragmentSelectorType': 'PRODUCER_TIMESTAMP',
},
On the kvssink side. Would max-latency=60
and fragment-duration=2000
have anything to do with it? If I remove key-frame-fragmentation=false fragment-duration=2000
it definitely performs more poorly. As in - the streaming client wont work maybe 30% of the time.
Thanks for the help.
Maybe I need to reload the entire player in iOS when its not streaming... Kind of a brute-force retry mechanism.
@js1972, can you export this env variable KVS_DEBUG_DUMP_DATA_FILE_DIR=$PWD, and then run this pipeline?
gst-launch-1.0 rtspsrc location={} short-header=true ! rtph264depay ! video/x-h264, format=avc, alignment=au ! h264parse ! kvssink stream-name={}-{} storage-size=128 retention-period=1"
it will dump a mkv file in $PWD, you can send that file to us at kinesis-video-support@amazon.com. Thanks.
@js1972 do you have any update on this?
Sorry have not got back to this yet. Will do now...
So what happens with the improved parameters above is that generally - the first time I try to watch a stream from the hls client on iOS it fails and I just see a blank screen with no error messages. So I can out and go in to watch again and it will work - over and over. So at most if fails one time for each camera stream I may look at.
Have sent the recorded file to: kinesis-video-support@amazon.com
@js1972 thanks for the clip. Looking at the clip I don't see anything that could cause the issue. The frames look normal. The first cluster has a single frame with size 119 - not yet sure whether this could cause the problem.
One more thing...
2020-05-20 12:12:00 [547381821936] ERROR - getKinesisVideoStreamData(): operation returned status code: 0x5200002f
this is not an error, it's getting printed as an error (which is fixed in PIC since) but it's one of the control statuses that's being passed from the lower layer to indicate no more data available to the networking layer. You can ignore that.
@js1972 I have looked at the provided MKV file with mkvinfo
and I see the following at the start of the file:
|+ Cluster
| + Cluster timestamp: 441652:11:38.302000000
| + Cluster position: 0
| + Simple block: track number 1, 1 frame(s), timestamp 441652:11:38.302000000
| + Frame with size 119
|+ Cluster
| + Cluster timestamp: 441652:11:38.381000000
| + Cluster position: 0
| + Simple block: key, track number 1, 1 frame(s), timestamp 441652:11:38.381000000
| + Frame with size 33535
| + Simple block: track number 1, 1 frame(s), timestamp 441652:11:38.497000000
| + Frame with size 243
| + Simple block: track number 1, 1 frame(s), timestamp 441652:11:38.571000000
| + Frame with size 82
| + Simple block: track number 1, 1 frame(s), timestamp 441652:11:38.681000000
| + Frame with size 49
| + Simple block: track number 1, 1 frame(s), timestamp 441652:11:38.748000000
...
The first cluster is starting with a single non-keyframe. Most video players will fail if they receive a cluster like this. Perhaps this is just a result of the KVS_DEBUG_DUMP_DATA_FILE_DIR flag, but I don't think so. You need to make sure you start pulling from the rtsp source starting from a keyframe. Perhaps @MushMal can provide some guidance on how to do that with gstreamer.
Would love to know how to start it on a key frame. Will start researching. The interesting thing is that the hls client works perfectly a lot of the time.
What is it in mkvinfo that tells you the file does not start with a key frame?
Would love to know how to start it on a key frame. Will start researching. The interesting thing is that the hls client works perfectly a lot of the time.
you can do it by setting this to TRUE: https://github.com/awslabs/amazon-kinesis-video-streams-pic/blob/8f0db7900d6e847ae8072ae5e8205ef81551c685/src/client/src/Stream.c#L127
the package is in the submodule.
Setting this to true: pKinesisVideoStream->skipNonKeyFrames = FALSE;
Looks like it will skip ALL non-key frames?? Thats not what we want is it? We just want to start the stream with a key frame.
@js1972 it will skip the non-key frames on startup. This is an internal state variable that's actually used for other purposes. We just want to see whether this is the root cause of the issue you are seeing.
oh ok. So if I change that I need to build the sources again I assume. I have tried setting the kvssink parameter key-frame-fragmentation
true but when I do this I cannot stream from hls at all. Let me change the source and I'll come back.
Resolving due to staleness. Please reopen or cut a new issue with more details if needed
@MushMal Just wanted to let you know tat I finally got around to testing the advice to change the source and set:
you can do it by setting this to TRUE: https://github.com/awslabs/amazon-kinesis-video-streams-pic/blob/8f0db7900d6e847ae8072ae5e8205ef81551c685/src/client/src/Stream.c#L127
It works. On iOS the stream now works first time every time. Before setting this var to TRUE it would only work on iOS on the second attempt which was quite annoying.
Note that it always worked on Android though - so Android must be more tolerant of the first frame being a key frame or not.
You mentioned this was just a test. Can I leave it like this or would you now push a change?
Interesting.. I would imagine that the media pipeline/application would vet out the "bad" frames that would come in first but perhaps initializing the skip indicator to true and skipping all non-key-frames initially is a good default.
In order to land this change we need to:
@js1972 John, could I ask you to attach the first frame (likely an SEI NALu) or the MKV that contains to the GitHub issue so others can look into it as well? I would like to understand what the bits are and whether they might have any downstream effect?
Hi @MushMal is it possible to re-open this incident while the testing is taking place. Also your previous comment - I can't tell if that is asking me to do something or someone called "John" ?
Yeah, of course I will reopen the issue. Sorry, for some odd reason I must have typed the GitHub alias and then added John :) Sorry Jason. Please help us get that first frame so we can see what that is. Blank removing it might break some of the analytics or playback engines down stream. We are trying to see whether removing non-key-frame vs adapting the media pipeline is the best.
How do I get this for you... Save a new mkv file like from here : https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp/issues/441#issuecomment-630437212
Yeah, that will work. We don't preserve the earlier sent files. I can then extract the frame directly from the MKV
Ok I have resent you the mkv file that I previously sent above to this email kinesis-video-support@amazon.com. This is the file that shows that the stream starts without a keyframe.
Perfect, thank you. Let me take a closer look and I will report back
Hi @MushMal any news on this?
Sorry, this has been dropped from the list. Will hopefully look at it at some stage
OK, sorry this was not prioritized somewhat.
Here are the bits of the frame I see:
00 00 00 73 61 e0 00 a0 01 45 71 1f 00 da be 54 b0 13 96 48 80 5b 11 9b d6 01 1e 12 96 3c 5b b0 5f ae dd c6 b4 08 8b 7c 1b 47 0a a8 38 71 9a 28 91 06 c9 44 04 c9 8a 0e e2 4c 1a a9 96 2b 44 f1 21 47 64 ce ee 8b 68 f5 7a c6 17 88 17 59 6f dc 75 66 08 7d 0d 4c e0 2d d1 b0 d2 49 c0 be 0e b6 02 fd 18 8c a8 be 4c b0 c8 16 a1 d2 38 68 45 77 17 24 7a d9 64 c7 e0
The frame is properly packaged but I just can't tell what exactly it represents as its NALu type is 1 which is a Coded slice of a non-IDR picture VCL. I don't have a way of knowing what the encoder has produced. Perhaps you could check the manufacturer spec of your rtsp source.
This said, I think we should not process and skip first non-key frames: https://github.com/awslabs/amazon-kinesis-video-streams-pic/issues/76
I am going to resolve this issue for now as there is a mitigation and we are still unsure what's the NALu type. We are tracking the skipping non-key-frame NALus in a separate issue: https://github.com/awslabs/amazon-kinesis-video-streams-pic/issues/76
The changes are in PIC. Those will trickle to C Producer and CPP Producer SDKs but if anyone needs them ASAP then they can reference this commit: 1988f99fe77a3b37e9ed33643c20190a5c2e1689
@MushMal is there a way for me to tell when theses changes will filter through to master?
We started migration of the changes. Currently, they are in C Producer: https://github.com/awslabs/amazon-kinesis-video-streams-producer-c/commit/81305d2796b5d571a8c19edc59c0463975f97c8c
Hope to move this tomorrow to cpp
Thankyou. pKinesisVideoStream->skipNonKeyFrames = FALSE
is now set to TRUE when I clone master and build.
However I have also found that streaming via HLS to an iOS device is still very flakey unless I also set this property on kvssink:
key-frame-fragmentation=false
This value defaults to true. So it looks like that even with pKinesisVideoStream->skipNonKeyFrames = TRUE
you also need key-frame-fragmentation=false
to ensure streams start with a key frame...
Key frame fragmentation drives an entirely different aspect of the SDK. If it specified as false, the SDK will cut a fragment on a key-frame only after a fragment-duration has passed. This is useful for scenarios like most of the audio encoders where every frame is like an I-frame but we need the SDK to not cut a fragment with every frame. In your case I would recommend understanding how your encoder behaves as for a normal video case the encoder should drive the fragmentation
I am using the kvssink to send a camera stream to kinesis video. The camera is set to 10fps and i-frame interval of 10.
I have a mobile app build in Flutter. The video player is a simple wrapper around iOS AVPlayer. So in the app I get the HLS Streaming URL successfully every time and pass it to the video player. About 1 in every 2 or 3 tries, the video player just shows a white screen and nothing happens. If I exit out and try again it will work and play a stable stream. Every so often I also see the following errors message on ios:
Here is the gstreamer pipeline I am using to send to Kinesis:
I'm dynamically building the location and stream name above as you can see with "{}".
By adding framerate=10 above to match my cameras and also forcing a fragment duration seems to help. Instead of seeing the errors roughly 50% of the time. I no only see them maybe once in 5 times.
Note that if I use the AWS Kinesis Video preview it works fine all the time.
Is there any advice on how to set the kvssink parameters to get stable HLS streaming on iOS ?
ps. The same issues occurs on Android - which makes me think its more of a kinesis thing that an ios/android thing. ;-)