private async Task AcquireResources(StreamState state, CancellationTokenSource cancellationTokenSource) { if (state.VideoType == VideoType.Iso && state.IsoType.HasValue && IsoManager.CanMount(state.MediaPath)) { state.IsoMount = await IsoManager.Mount(state.MediaPath, cancellationTokenSource.Token).ConfigureAwait(false); } if (state.MediaSource.RequiresOpening && string.IsNullOrWhiteSpace(state.Request.LiveStreamId)) { var liveStreamResponse = await MediaSourceManager.OpenLiveStream(new LiveStreamRequest { OpenToken = state.MediaSource.OpenToken }, cancellationTokenSource.Token).ConfigureAwait(false); EncodingHelper.AttachMediaSourceInfo(state, liveStreamResponse.MediaSource, state.RequestedUrl); if (state.VideoRequest != null) { EncodingHelper.TryStreamCopy(state); } } if (state.MediaSource.BufferMs.HasValue) { await Task.Delay(state.MediaSource.BufferMs.Value, cancellationTokenSource.Token).ConfigureAwait(false); } }
/// <summary> /// Starts the FFMPEG. /// </summary> /// <param name="state">The state.</param> /// <param name="outputPath">The output path.</param> /// <returns>Task.</returns> protected async Task StartFfMpeg(StreamState state, string outputPath) { var parentPath = Path.GetDirectoryName(outputPath); Directory.CreateDirectory(parentPath); var video = state.Item as Video; if (video != null && video.VideoType == VideoType.Iso && video.IsoType.HasValue && IsoManager.CanMount(video.Path)) { state.IsoMount = await IsoManager.Mount(video.Path, CancellationToken.None).ConfigureAwait(false); } var process = new Process { StartInfo = new ProcessStartInfo { CreateNoWindow = true, UseShellExecute = false, // Must consume both stdout and stderr or deadlocks may occur RedirectStandardOutput = true, RedirectStandardError = true, FileName = MediaEncoder.EncoderPath, WorkingDirectory = Path.GetDirectoryName(MediaEncoder.EncoderPath), Arguments = GetCommandLineArguments(outputPath, state, true), WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false }, EnableRaisingEvents = true }; ApiEntryPoint.Instance.OnTranscodeBeginning(outputPath, TranscodingJobType, process, video != null, state.Request.StartTimeTicks, state.Item.Path, state.Request.DeviceId); Logger.Info(process.StartInfo.FileName + " " + process.StartInfo.Arguments); var logFilePath = Path.Combine(ApplicationPaths.LogDirectoryPath, "ffmpeg-" + Guid.NewGuid() + ".txt"); // FFMpeg writes debug/error info to stderr. This is useful when debugging so let's put it in the log directory. state.LogFileStream = FileSystem.GetFileStream(logFilePath, FileMode.Create, FileAccess.Write, FileShare.Read, true); process.Exited += (sender, args) => OnFfMpegProcessExited(process, state); try { process.Start(); } catch (Exception ex) { Logger.ErrorException("Error starting ffmpeg", ex); ApiEntryPoint.Instance.OnTranscodeFailedToStart(outputPath, TranscodingJobType); state.LogFileStream.Dispose(); throw; } // MUST read both stdout and stderr asynchronously or a deadlock may occurr process.BeginOutputReadLine(); // Important - don't await the log task or we won't be able to kill ffmpeg when the user stops playback process.StandardError.BaseStream.CopyToAsync(state.LogFileStream); // Wait for the file to exist before proceeeding while (!File.Exists(outputPath)) { await Task.Delay(100).ConfigureAwait(false); } // Allow a small amount of time to buffer a little if (state.Item is Video) { await Task.Delay(500).ConfigureAwait(false); } // This is arbitrary, but add a little buffer time when internet streaming if (state.Item.LocationType == LocationType.Remote) { await Task.Delay(2000).ConfigureAwait(false); } }