/// <summary> /// Pushes a set of frames to IIS. Will trigger a connect if needed. /// </summary> private void PushStream(MediaStream stream, FileRoot TargetMp4fFile) { if (stream == null || stream.Frames == null) { return; // no frames. } SanitiseStream(stream); if (stream.Frames.Count < 1) { return; // no frames. } if (!PushServer.IsConnected(stream.TrackId)) { ConnectAndPushHeaders(stream, TargetMp4fFile); } // set start-of-fragment time from PTS stream.Offset = stream.Frames[0].FramePresentationTime - stream.Frames[0].FrameDuration; // Push the fragment var fragment_handler = TargetMp4fFile.GenerateFragment(stream); PushServer.PushData(stream.TrackId, fragment_handler.MoofData()); PushServer.PushData(stream.TrackId, fragment_handler.MdatData()); }
/// <summary> /// Used once per connection, this opens a long-life HTTP stream /// and pushes the very basic MP4 parts needed to get IIS working. /// </summary> private void ConnectAndPushHeaders(MediaStream stream, FileRoot TargetMp4fFile) { SmilGenerator smil = new SmilGenerator("HCS Encoder by Iain Ballard.", stream); smil.ApproxBitrate = stream.Bitrate; MP4_Mangler.ExtraBoxes.SmoothSmil ssmil = new MP4_Mangler.ExtraBoxes.SmoothSmil(smil.Generate()); PushServer.Connect(stream.TrackId); // This pushes to the subpath: Streams({id}-stream{index}) // push headers (only done once per track) // each one needs it's own HTTP Chunk, so don't concat! PushServer.PushData(stream.TrackId, TargetMp4fFile.GenerateFileSpec()); PushServer.PushData(stream.TrackId, ssmil.deepData()); PushServer.PushData(stream.TrackId, TargetMp4fFile.GenerateHeaders()); }
/// <summary> /// Shut down the streams and close connections. /// </summary> public void Close() { byte[] EOS = Mp4fFile.GenerateFooters(); // End-Of-Stream signal // Close off all streams, taking them out of live mode: foreach (var stream in Streams) { try { PushServer.PushData(stream.TrackId, EOS); } catch { } } // Final close: PushServer.Close(); }