/// <summary> /// Creates media frame data segments. /// </summary> /// <param name="mediaFrame">Media frame.</param> /// <param name="metadataRequired">Indicates whether to include metadata.</param> /// <returns>An array of data segments.</returns> private static ArraySegment <byte>[] CreateDataSegments(RawFrame mediaFrame, bool metadataRequired) { if (!metadataRequired) { return new[] { new byte[] { 0 }, mediaFrame.FrameSegment } } ; var codecName = mediaFrame switch { RawAACFrame _ => "AAC", RawG711AFrame _ => "G711A", RawG711UFrame _ => "G711U", RawG726Frame _ => "G726", RawPCMFrame _ => "PCM", RawH264IFrame _ => "H264", RawH264PFrame _ => "H264", RawJpegFrame _ => "MJPEG", _ => string.Empty }; var bitsPerCodedUnit = mediaFrame switch { RawG726Frame rawG726Frame => rawG726Frame.BitsPerCodedSample, _ => 0 }; var configSegment = mediaFrame switch { RawAACFrame rawAacFrame => rawAacFrame.ConfigSegment, RawH264IFrame rawH264IFrame => rawH264IFrame.SpsPpsSegment, _ => default }; var codecBytes = Encoding.UTF8.GetBytes(codecName); Array.Resize(ref codecBytes, 10); var metaSegment = new byte[19]; using var stream = new MemoryStream(metaSegment); using var writer = new EndianBinaryWriter(stream); writer.Write((byte)1); writer.Write(codecBytes); writer.Write(bitsPerCodedUnit); writer.Write(configSegment.Count); return(configSegment.Count > 0 ? new[] { metaSegment, configSegment, mediaFrame.FrameSegment } : new[] { metaSegment, mediaFrame.FrameSegment }); }
protected void streamingThreadLoop() { try { CancellationToken cancellationToken = streamingCancelTokenSource.Token; Uri serverUri = new Uri(Url); ConnectionParameters connectionParameters; if (!string.IsNullOrWhiteSpace(Username)) { connectionParameters = new ConnectionParameters(serverUri, new NetworkCredential(Username, Password)); } else { connectionParameters = new ConnectionParameters(serverUri); } connectionParameters.RtpTransport = RtpTransportProtocol.TCP; string openH264DllPath = Globals.ApplicationDirectoryBase + "openh264-1.8.0-win" + (Environment.Is64BitProcess ? "64" : "32") + ".dll"; using (OpenH264Lib.Decoder decoder = new OpenH264Lib.Decoder(openH264DllPath)) using (RtspClient rtspClient = new RtspClient(connectionParameters)) { rtspClient.FrameReceived += (sender2, frame) => { //process (e.g. decode/save to file) encoded frame here or //make deep copy to use it later because frame buffer (see FrameSegment property) will be reused by client if (frame is RawH264IFrame) { RawH264IFrame iFrame = frame as RawH264IFrame; DecodeFrame(decoder, iFrame.SpsPpsSegment.ToArray(), frame.Timestamp); DecodeFrame(decoder, iFrame.FrameSegment.ToArray(), frame.Timestamp); } else if (frame is RawH264PFrame) { DecodeFrame(decoder, frame.FrameSegment.ToArray(), frame.Timestamp); } }; rtspClient.ConnectAsync(cancellationToken).Wait(); rtspClient.ReceiveAsync(cancellationToken).Wait(); } } catch (ThreadAbortException) { } catch (TaskCanceledException) { Stop(); } catch (Exception ex) { if (ex is AggregateException) { AggregateException aex = ex as AggregateException; if (aex.InnerExceptions.Count == 1 && aex.InnerException is TaskCanceledException) { return; } } Logger.Debug(ex); OnError(this, ex); Stop(); } }