protected override Future <object> DoStart()
        {
            var promise = new Promise <object>();

            try
            {
                Pipe              = new NamedPipe(PipeName, Server);
                Pipe.OnConnected += () =>
                {
                    var handler = OnPipeConnected;
                    if (handler != null)
                    {
                        handler();
                    }
                };
                Pipe.OnReadDataBuffer += (dataBuffer) =>
                {
                    RaiseFramePayload(dataBuffer);
                };

                if (StartAsync)
                {
                    Task ready;
                    if (Server)
                    {
                        ready = Pipe.WaitForConnectionAsync();
                    }
                    else
                    {
                        ready = Pipe.ConnectAsync();
                    }

                    Task.Run(async() =>
                    {
                        await ready.ConfigureAwait(false);

                        ReadStreamHeader();

                        Pipe.StartReading(ReadFrameHeader);
                    });

                    promise.Resolve(null);
                }
                else
                {
                    Task.Run(async() =>
                    {
                        try
                        {
                            if (Server)
                            {
                                await Pipe.WaitForConnectionAsync();
                            }
                            else
                            {
                                await Pipe.ConnectAsync();
                            }

                            ReadStreamHeader();

                            Pipe.StartReading(ReadFrameHeader);

                            promise.Resolve(null);
                        }
                        catch (Exception ex)
                        {
                            promise.Reject(ex);
                        }
                    });
                }
            }
            catch (Exception ex)
            {
                promise.Reject(ex);
            }
            return(promise);
        }
Example #2
0
        protected override Task Ready()
        {
            var ready = base.Ready();

            var args = new List <string>
            {
                "-y",
                Options.InputArgs
            };

            if (AudioSource != null)
            {
                var config = AudioSource.Config;

                args.Add($"-map 0:a:0");

                if (Options.AudioMode == FFCaptureMode.LSEncode)
                {
                    var source = AudioSource as PcmNamedPipeAudioSource;
                    args.AddRange(new[]
                    {
                        $"-f s16le",
                        $"-ar {config.ClockRate}",
                        $"-ac {config.ChannelCount}",
                        NamedPipe.GetOSPipeName(source.PipeName)
                    });
                }
                else
                {
                    var source = AudioSource as RtpAudioSource;

                    args.Add($"-f rtp");

                    if (Options.AudioMode == FFCaptureMode.NoEncode)
                    {
                        args.Add($"-c copy");
                    }
                    else
                    {
                        if (RtpAudioFormat.IsOpus)
                        {
                            args.AddRange(new[]
                            {
                                $"-ar {config.ClockRate}",
                                $"-ac {config.ChannelCount}",
                                $"-c libopus",
                                $"-b:a {Options.AudioBitrate}k",
                            });
                        }
                        else if (RtpAudioFormat.IsG722)
                        {
                            args.AddRange(new[]
                            {
                                $"-ar 16000",
                                $"-ac 1",
                                $"-c g722",
                            });
                        }
                        else if (RtpAudioFormat.IsPcmu)
                        {
                            args.AddRange(new[]
                            {
                                $"-ar 8000",
                                $"-ac 1",
                                $"-c pcm_mulaw",
                            });
                        }
                        else if (RtpAudioFormat.IsPcma)
                        {
                            args.AddRange(new[]
                            {
                                $"-ar 8000",
                                $"-ac 1",
                                $"-c pcm_alaw",
                            });
                        }
                        else
                        {
                            throw new InvalidOperationException($"Unexpected audio format '{RtpAudioFormat.Name}'.");
                        }
                    }

                    if (RtpAudioFormat.IsOpus)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}");
                    }
                    else if (RtpAudioFormat.IsG722)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={G722PacketSize}");
                    }
                    else if (RtpAudioFormat.IsPcmu)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={PcmuPacketSize}");
                    }
                    else if (RtpAudioFormat.IsPcma)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={PcmaPacketSize}");
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unexpected audio format '{RtpAudioFormat.Name}'.");
                    }
                }
            }

            var processParameterSets = false;

            if (VideoSource != null)
            {
                args.Add($"-map 0:v:0");

                if (Options.VideoMode == FFCaptureMode.LSEncode)
                {
                    var source = VideoSource as Yuv4MpegNamedPipeVideoSource;
                    args.AddRange(new[]
                    {
                        $"-f yuv4mpegpipe",
                        $"-pix_fmt yuv420p",
                        NamedPipe.GetOSPipeName(source.PipeName)
                    });
                }
                else
                {
                    var source = VideoSource as RtpVideoSource;

                    args.Add($"-f rtp");

                    if (Options.VideoMode == FFCaptureMode.NoEncode)
                    {
                        args.Add($"-c copy");

                        if (RtpVideoFormat.IsH264)
                        {
                            processParameterSets      = true;
                            source.NeedsParameterSets = true;
                            H264SdpFileName           = $"h264_{Utility.GenerateId()}.sdp";
                            args.AddRange(new[]
                            {
                                $"-sdp_file {H264SdpFileName}",
                            });
                        }
                    }
                    else
                    {
                        if (RtpVideoFormat.IsVp8)
                        {
                            args.AddRange(new[]
                            {
                                $"-c libvpx -auto-alt-ref 0",
                                $"-pix_fmt yuv420p",
                                $"-quality realtime",
                                $"-speed 16",
                                $"-crf 10",
                                $"-b:v {Options.VideoBitrate}k",
                                $"-g {Options.KeyFrameInterval}",
                            });
                        }
                        else if (RtpVideoFormat.IsVp9)
                        {
                            args.AddRange(new[]
                            {
                                $"-c libvpx-vp9 -strict experimental",
                                $"-level 0",
                                $"-pix_fmt yuv420p",
                                $"-lag-in-frames 0",
                                $"-deadline realtime",
                                $"-quality realtime",
                                $"-speed 16",
                                $"-b:v {Options.VideoBitrate}k -maxrate {Options.VideoBitrate}k",
                                $"-g {Options.KeyFrameInterval}",
                            });
                        }
                        else if (RtpVideoFormat.IsH264)
                        {
                            args.AddRange(new[]
                            {
                                $"-c libx264",
                                $"-profile:v baseline",
                                $"-level:v 1.3",
                                $"-pix_fmt yuv420p",
                                $"-tune zerolatency",
                                $"-b:v {Options.VideoBitrate}k",
                                $"-g {Options.KeyFrameInterval} -keyint_min {Options.KeyFrameInterval}",
                            });
                        }
                        else
                        {
                            throw new InvalidOperationException($"Unexpected video format '{RtpVideoFormat.Name}'.");
                        }
                    }

                    if (RtpVideoFormat.IsVp8)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={Vp8PacketSize}");
                    }
                    else if (RtpVideoFormat.IsVp9)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={Vp9PacketSize}");
                    }
                    else if (RtpVideoFormat.IsH264)
                    {
                        args.Add($"rtp://127.0.0.1:{source.Port}?pkt_size={H264PacketSize}");
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unexpected video format '{RtpVideoFormat.Name}'.");
                    }
                }
            }

            FFmpeg = FFUtility.FFmpeg(string.Join(" ", args));

            var monitor = new Thread(() =>
            {
                while (!_Done)
                {
                    FFmpeg.WaitForExit();
                    if (!_Done)
                    {
                        Console.Error.WriteLine("FFmpeg exited unexpectedly.");
                        FFmpeg = FFUtility.FFmpeg(string.Join(" ", args));
                    }
                }
            })
            {
                IsBackground = true
            };

            monitor.Start();

            if (processParameterSets)
            {
                ProcessParameterSets();
            }

            return(ready);
        }
Example #3
0
        protected override async Task Ready()
        {
            await base.Ready();

            var args = new List <string>
            {
                "-y"
            };

            if (AudioSink != null)
            {
                var config = AudioSink.Config;

                if (Options.AudioMode == FFRenderMode.LSDecode)
                {
                    var sink = AudioSink as PcmNamedPipeAudioSink;

                    args.AddRange(new[]
                    {
                        $"-guess_layout_max 0",
                        $"-f s16le",
                        $"-ar {config.ClockRate}",
                        $"-ac {config.ChannelCount}",
                        $"-i {NamedPipe.GetOSPipeName(sink.PipeName)}",
                    });
                }
                else
                {
                    var sink = AudioSink as RtpAudioSink;

                    sink.IPAddress   = "127.0.0.1";
                    sink.Port        = LockedRandomizer.Next(49162, 65536);
                    sink.PayloadType = 96;

                    var sdpMediaDescription = new Sdp.MediaDescription(new Sdp.Media(Sdp.MediaType.Audio, sink.Port, Sdp.Rtp.Media.RtpAvpTransportProtocol, sink.PayloadType.ToString()));
                    sdpMediaDescription.AddMediaAttribute(new Sdp.SendReceiveAttribute());

                    if (RtpAudioFormat.IsOpus)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, AudioFormat.OpusName, Opus.Format.DefaultClockRate, Opus.Format.DefaultChannelCount.ToString()));
                        sdpMediaDescription.AddMediaAttribute(new Sdp.FormatParametersAttribute(sink.PayloadType, "useinbandfec=1"));
                    }
                    else if (RtpAudioFormat.IsG722)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, AudioFormat.G722Name, G722.Format.DefaultClockRate, G722.Format.DefaultChannelCount.ToString()));
                    }
                    else if (RtpAudioFormat.IsPcmu)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, AudioFormat.PcmuName, G711.Format.DefaultClockRate, G711.Format.DefaultChannelCount.ToString()));
                    }
                    else if (RtpAudioFormat.IsPcma)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, AudioFormat.PcmaName, G711.Format.DefaultClockRate, G711.Format.DefaultChannelCount.ToString()));
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unexpected audio format '{RtpAudioFormat.Name}'.");
                    }

                    if (Options.AudioBitrate.HasValue && !RtpAudioFormat.IsFixedBitrate)
                    {
                        sdpMediaDescription.AddBandwidth(new Sdp.Bandwidth(Sdp.BandwidthType.ApplicationSpecific, Options.AudioBitrate.Value));
                    }

                    var sdpMessage = new Sdp.Message(new Sdp.Origin("127.0.0.1"), "liveswitch-audio")
                    {
                        ConnectionData = new Sdp.ConnectionData("127.0.0.1")
                    };
                    if (sdpMediaDescription != null)
                    {
                        sdpMessage.AddMediaDescription(sdpMediaDescription);
                    }

                    var sdp = sdpMessage.ToString();

                    AudioSdpFileName = $"audio_{Utility.GenerateId()}.sdp";

                    File.WriteAllText(AudioSdpFileName, sdp);

                    Console.Error.WriteLine($"Audio SDP:{Environment.NewLine}{sdp}");

                    args.AddRange(new[]
                    {
                        $"-protocol_whitelist file,crypto,udp,rtp",
                        $"-i {AudioSdpFileName}"
                    });
                }
            }

            if (VideoSink != null)
            {
                if (Options.VideoMode == FFRenderMode.LSDecode)
                {
                    var sink = VideoSink as Yuv4MpegNamedPipeVideoSink;

                    args.AddRange(new[]
                    {
                        $"-f yuv4mpegpipe",
                        $"-i {NamedPipe.GetOSPipeName(sink.PipeName)}",
                    });
                }
                else
                {
                    var sink = VideoSink as RtpVideoSink;

                    sink.IPAddress   = "127.0.0.1";
                    sink.Port        = LockedRandomizer.Next(49162, 65536);
                    sink.PayloadType = 97;

                    var sdpMediaDescription = new Sdp.MediaDescription(new Sdp.Media(Sdp.MediaType.Video, sink.Port, Sdp.Rtp.Media.RtpAvpTransportProtocol, sink.PayloadType.ToString()));
                    sdpMediaDescription.AddMediaAttribute(new Sdp.SendReceiveAttribute());
                    if (Options.VideoFrameRate.HasValue)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.FrameRateAttribute(Options.VideoFrameRate.ToString()));
                    }

                    if (RtpVideoFormat.IsVp8)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, VideoFormat.Vp8Name, VideoFormat.DefaultClockRate));
                    }
                    else if (RtpVideoFormat.IsVp9)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, VideoFormat.Vp9Name, VideoFormat.DefaultClockRate));
                    }
                    else if (RtpVideoFormat.IsH264)
                    {
                        sdpMediaDescription.AddMediaAttribute(new Sdp.Rtp.MapAttribute(sink.PayloadType, VideoFormat.H264Name, VideoFormat.DefaultClockRate));
                        sdpMediaDescription.AddMediaAttribute(new Sdp.FormatParametersAttribute(sink.PayloadType, "profile-level-id=42001f;level-asymmetry-allowed=1;packetization-mode=1"));
                    }
                    else
                    {
                        throw new InvalidOperationException($"Unexpected video format '{RtpVideoFormat.Name}'.");
                    }

                    if (Options.VideoBitrate.HasValue && !RtpVideoFormat.IsFixedBitrate)
                    {
                        sdpMediaDescription.AddBandwidth(new Sdp.Bandwidth(Sdp.BandwidthType.ApplicationSpecific, Options.VideoBitrate.Value));
                    }

                    var sdpMessage = new Sdp.Message(new Sdp.Origin("127.0.0.1"), "liveswitch-video")
                    {
                        ConnectionData = new Sdp.ConnectionData("127.0.0.1")
                    };
                    if (sdpMediaDescription != null)
                    {
                        sdpMessage.AddMediaDescription(sdpMediaDescription);
                    }

                    var sdp = sdpMessage.ToString();

                    VideoSdpFileName = $"video_{Utility.GenerateId()}.sdp";

                    File.WriteAllText(VideoSdpFileName, sdp);

                    Console.Error.WriteLine($"Video SDP:{Environment.NewLine}{sdp}");

                    if (Options.VideoFrameRate.HasValue)
                    {
                        args.Add($"-r {Options.VideoFrameRate}");
                    }

                    args.AddRange(new[]
                    {
                        $"-protocol_whitelist file,crypto,udp,rtp",
                        $"-i {VideoSdpFileName}",
                    });
                }
            }

            args.Add(Options.OutputArgs);

            FFmpeg = FFUtility.FFmpeg(string.Join(" ", args), ProcessFFmpegOutput);

            var monitor = new Thread(() =>
            {
                while (!_Done)
                {
                    FFmpeg.WaitForExit();
                    Deactivate();
                    if (!_Done)
                    {
                        Console.Error.WriteLine("FFmpeg exited unexpectedly.");
                        FFmpeg = FFUtility.FFmpeg(string.Join(" ", args), ProcessFFmpegOutput);
                    }
                }
            })
            {
                IsBackground = true
            };

            monitor.Start();
        }