private void AddVideoParamaterSet(VideoSample sample) { var configpart = VideoParameter.Split(','); // Add SPS sample.BeginUnit(); sample.AddUnitData(Convert.FromBase64String(configpart[0])); sample.EndUnit(); // Add PPS sample.BeginUnit(); sample.AddUnitData(Convert.FromBase64String(configpart[1])); sample.EndUnit(); }
private IRtspSample OnVideoPacket(long sampleTime, RtpPacket packet, bool discontinuity) { if (discontinuity) { // clear fragmented NAL unit _lastVideoSample = null; } var data = packet.PayloadData.ToArray(); if (data.Length < 1) { return(null); } // Interleaved mode is not supported. var nalUnitFlags = data[0] & 0xe0; var nalUnitType = data[0] & 0x1f; if (nalUnitType <= 23) { // NAL unit (one packet, one NAL) //Trace.WriteLine($"RtspHandler::OnVideoPacket(): NALType({nalUnitType}) Timestamp={packet.Timestamp} Length={data.Length}"); var sample = new VideoSample(sampleTime, discontinuity, (nalUnitType == 5)); if (sampleTime == 0) { AddVideoParamaterSet(sample); } sample.BeginUnit(); sample.AddUnitData(data); sample.EndUnit(); sample.Commit(); return(sample); } if (nalUnitType == 24) { // STAP-A (Single-time aggregation packet: one packet, multiple NALs) // TBD Debug.WriteLine("RtspHandler::OnVideoPacket(): STAP-A"); return(null); } if (nalUnitType == 28) { // FU-A (Fragmentation Units: multiple packets, one NAL) //var fuIndicator = data[0]; var fuHeader = data[1]; if ((fuHeader & 0x80) != 0) // check start bit // start of a fragmented NAL unit { var fuNalUnitType = fuHeader & 0x1f; //Trace.WriteLine($"RtspHandler::OnVideoPacket(): FU-A Start NALType({fuNalUnitType}) Timestamp={packet.Timestamp} Length={data.Length - 2}"); if (_lastVideoSample != null) { Debug.WriteLine("RtspHandler::OnVideoPacket(): Invalid fragmented NAL start."); } _lastVideoSample = new VideoSample(sampleTime, discontinuity, (fuNalUnitType == 5)); if (sampleTime == 0) { AddVideoParamaterSet(_lastVideoSample); } _lastVideoSample.BeginUnit(); _lastVideoSample.AddUnitData((byte)(nalUnitFlags | fuNalUnitType)); _lastVideoSample.AddUnitData(data.Skip(2)); return(null); } if (discontinuity) { Debug.WriteLine("RtspHandler::OnVideoPacket(): Ignore middle-started fragmented NAL."); return(null); } if ((fuHeader & 0x40) != 0) // check end bit // end of a fragmented NAL unit //Trace.WriteLine($"RtspHandler::OnVideoPacket(): FU-A End Timestamp={packet.Timestamp} Length={data.Length - 2}"); { if (_lastVideoSample != null) { _lastVideoSample.AddUnitData(data.Skip(2)); _lastVideoSample.EndUnit(); _lastVideoSample.Commit(); var sample = _lastVideoSample; _lastVideoSample = null; return(sample); } else { Debug.WriteLine("RtspHandler::OnVideoPacket(): Invalid fragmented NAL end."); return(null); } } // following FU payload //Trace.WriteLine($"RtspHandler::OnVideoPacket(): FU-A Continue Timestamp={packet.Timestamp} Length={data.Length - 2}"); if (_lastVideoSample != null) { _lastVideoSample.AddUnitData(data.Skip(2)); } else { Debug.WriteLine("RtspHandler::OnVideoPacket(): Invalid fragmented NAL."); } return(null); } Debug.WriteLine($"RtspHandler::OnVideoPacket(): Unknown NALType({nalUnitType})"); return(null); }