/// <summary> /// Prepares for writing. /// </summary> /// <param name="showFFmpegOutput">Show output to terminal. Error stream will not be redirected if this is set to true.</param> /// <param name="thread_queue_size">Max. number of queued packets when reading from file/stream. /// Should be set to higher when dealing with high rate/low latency streams.</param> public void OpenWrite(bool showFFmpegOutput = false, int thread_queue_size = 4096) { if (OpenedForWriting) { throw new InvalidOperationException("File/Stream was already opened for writing!"); } var manual = new ManualResetEvent(false); socket = new Socket(SocketType.Stream, ProtocolType.Tcp); socket.Bind(new IPEndPoint(IPAddress.Loopback, 0)); socket.Listen(4); var port = ((IPEndPoint)socket.LocalEndPoint).Port; socket.BeginAccept(r => { connected_socket = socket.EndAccept(r); InputDataStreamAudio = new NetworkStream(connected_socket); manual.Set(); }, null); var cmd = $"-f s{AudioBitDepth}le -channels {AudioChannels} -sample_rate {AudioSampleRate} " + $"-thread_queue_size {thread_queue_size} -i \"tcp://{IPAddress.Loopback}:{port}\" " + $"-f rawvideo -video_size {VideoWidth}:{VideoHeight} -r {VideoFramerate} " + $"-thread_queue_size {thread_queue_size} -pixel_format rgb24 -i - " + $"-map 0 -c:a {AudioEncoderOptions.EncoderName} {AudioEncoderOptions.EncoderArguments} " + $"-map 1 -c:v {VideoEncoderOptions.EncoderName} {VideoEncoderOptions.EncoderArguments} " + $"-f {VideoEncoderOptions.Format}"; if (UseFilename) { if (File.Exists(Filename)) { File.Delete(Filename); } InputDataStreamVideo = FFmpegWrapper.OpenInput(ffmpeg, $"{cmd} \"{Filename}\"", out ffmpegp, showFFmpegOutput); } else { csc = new CancellationTokenSource(); // using stream (InputDataStreamVideo, OutputDataStream) = FFmpegWrapper.Open(ffmpeg, $"{cmd} -", out ffmpegp, showFFmpegOutput); _ = OutputDataStream.CopyToAsync(DestinationStream, csc.Token); } manual.WaitOne(); OpenedForWriting = true; }
/// <summary> /// Closes output video. /// </summary> public void CloseWrite() { if (!OpenedForWriting) { throw new InvalidOperationException("File is not opened for writing!"); } try { InputDataStreamAudio?.Dispose(); InputDataStreamVideo?.Dispose(); connected_socket?.Shutdown(SocketShutdown.Both); connected_socket?.Close(); socket?.Close(); ffmpegp.WaitForExit(); csc?.Cancel(); if (!UseFilename) { OutputDataStream?.Dispose(); } try { if (ffmpegp?.HasExited == false) { ffmpegp.Kill(); } } catch { } } finally { OpenedForWriting = false; } }
/// <summary>Sends a message of type RPY.</summary> /// <param name="stream">Data to send in the form of <code>OutputDataStream</code>.</param> /// <seealso cref="OutputDataStream"></seealso> /// <seealso cref="MessageStatus"></seealso> /// <returns>MessageStatus</returns> /// /// <exception cref="BEEPException">if an error is encoutered or if messageType is /// not MESSAGE_TYPE_MSG.</exception> public virtual MessageStatus sendRPY(OutputDataStream stream) { throw new BEEPException(NOT_MESSAGE_TYPE_MSG); }
/// <summary>Sends a 'synchronous' request on this <code>SharedChannel</code>.</summary> /// <param name="ds"><code>DataStream</code> to send as this request's payload.</param> /// <returns>Reply Caller may block using this object to retrieve the reply /// to this request.</returns> /// <exception cref="BEEPException" /> public virtual Reply sendRequest(OutputDataStream ds) { Reply r = new Reply(); channel.sendMSG(ds, r); return r; }
/// <summary>Send a message of type MSG. Sends <code>stream</code> as message's /// payload.</summary> /// <param name="stream"><code>DataStream</code> that is read to send data.</param> /// <param name="replyListener"></param> /// <returns>MessageStatus Can be queried to get status information about the /// message.</returns> /// <seealso cref="OutputDataStream"></seealso> /// <seealso cref="MessageStatus"></seealso> /// <exception cref="BEEPException" /> public virtual MessageStatus sendMSG(OutputDataStream stream, ReplyListener replyListener) { return channel.sendMSG(stream, replyListener); }