/// <summary> /// Uses input file and returns the output stream. Make sure to use a streaming format (like flv). /// </summary> /// <param name="inputFilename">Input video file name/path</param> /// <param name="options">Output options</param> /// <param name="process">FFmpeg process</param> /// <param name="inputArguments">Input arguments (such as -f, -v:c, -video_size, -ac, -ar...)</param> /// <param name="showOutput">Show output to terminal. Error stream will not be redirected if this is set to true.</param> /// <param name="ffmpegExecutable">Name or path to the ffmpeg executable</param> public static Stream FileToStream(string inputFilename, EncoderOptions options, out Process process, string inputArguments = "", bool showOutput = false, string ffmpegExecutable = "ffmpeg") { var output = FFmpegWrapper.OpenOutput(ffmpegExecutable, $"{inputArguments} -i \"{inputFilename}\" " + $"-c:v {options.EncoderName} {options.EncoderArguments} -f {options.Format} -", out process, showOutput); return(output); }
/// <summary> /// Load video metadata into memory. /// </summary> public async Task LoadMetadataAsync(bool ignoreStreamErrors = false) { if (LoadedMetadata) { throw new InvalidOperationException("Video metadata is already loaded!"); } var r = FFmpegWrapper.OpenOutput(ffprobe, $"-i \"{Filename}\" -v quiet -print_format json=c=1 -show_format -show_streams"); try { var metadata = await JsonSerializer.DeserializeAsync <VideoMetadata>(r); try { var videoStream = metadata.Streams.Where(x => x.CodecType.ToLower().Trim() == "video").FirstOrDefault(); if (videoStream != null) { metadata.Width = videoStream.Width.Value; metadata.Height = videoStream.Height.Value; metadata.PixelFormat = videoStream.PixFmt; metadata.Codec = videoStream.CodecName; metadata.CodecLongName = videoStream.CodecLongName; metadata.BitRate = videoStream.BitRate == null ? -1 : int.Parse(videoStream.BitRate); metadata.BitDepth = videoStream.BitsPerRawSample == null? tryParseBitDepth(videoStream.PixFmt) : int.Parse(videoStream.BitsPerRawSample); metadata.Duration = videoStream.Duration == null? double.Parse(metadata.Format.Duration ?? "0", CultureInfo.InvariantCulture) : double.Parse(videoStream.Duration, CultureInfo.InvariantCulture); metadata.SampleAspectRatio = videoStream.SampleAspectRatio; metadata.AvgFramerateText = videoStream.AvgFrameRate; metadata.AvgFramerate = videoStream.AvgFrameRateNumber; metadata.PredictedFrameCount = (int)(metadata.AvgFramerate * metadata.Duration); } } catch (Exception ex) { // failed to interpret video stream settings if (!ignoreStreamErrors) { throw new InvalidDataException("Failed to parse video stream data! " + ex.Message); } } LoadedMetadata = true; Metadata = metadata; } catch (JsonException ex) { throw new InvalidOperationException("Failed to interpret ffprobe video metadata output! " + ex.Message); } }
/// <summary> /// Play video in background and return the process associated with it /// </summary> /// <param name="runPureBackground">Detach the player from this VideoPlayer control. Player won't be killed on disposing.</param> /// <param name="extraInputParameters">Extra FFmpeg input parameters to be passed</param> public Process PlayInBackground(bool runPureBackground = false, string extraInputParameters = "") { if (!runPureBackground && OpenedForWriting) { throw new InvalidOperationException("Player is already opened for writing frames!"); } if (string.IsNullOrEmpty(Filename)) { throw new InvalidOperationException("No filename was specified!"); } FFmpegWrapper.OpenOutput(ffplay, $"{extraInputParameters} -i \"{Filename}\"", out Process p); if (!runPureBackground) { ffplayp = p; } return(ffplayp); }
/// <summary> /// Play audio in background and return the process associated with it /// </summary> /// <param name="showWindow">Show player window</param> /// <param name="runPureBackground">Detach the player from this AudioPlayer control. Player won't be killed on disposing.</param> public Process PlayInBackground(bool showWindow = false, bool runPureBackground = false) { if (!runPureBackground && OpenedForWriting) { throw new InvalidOperationException("Player is already opened for writing samples!"); } if (string.IsNullOrEmpty(Filename)) { throw new InvalidOperationException("No filename was specified!"); } FFmpegWrapper.OpenOutput(ffplay, $"-i \"{Filename}\"" + (showWindow ? "" : " -nodisp"), out Process p); if (!runPureBackground) { ffplayp = p; } return(ffplayp); }
/// <summary> /// Load the audio and prepare it for reading frames. /// </summary> /// <param name="bitDepth">frame bit rate in which the audio will be processed (16, 24, 32)</param> public void Load(int bitDepth = 16) { if (bitDepth != 16 && bitDepth != 24 && bitDepth != 32) { throw new InvalidOperationException("Acceptable bit depths are 16, 24 and 32"); } if (OpenedForReading) { throw new InvalidOperationException("Audio is already loaded!"); } if (!MetadataLoaded) { throw new InvalidOperationException("Please load the audio metadata first!"); } // we will be reading audio in S16LE format (for best accuracy, could use S32LE) DataStream = FFmpegWrapper.OpenOutput(ffmpeg, $"-i \"{Filename}\" -f s{bitDepth}le -"); loadedBitDepth = bitDepth; OpenedForReading = true; }
/// <summary> /// Load the video for reading frames and seeks to given offset in seconds. /// </summary> /// <param name="offsetSeconds">Offset in seconds to which to seek to</param> public void Load(double offsetSeconds) { if (OpenedForReading) { throw new InvalidOperationException("Video is already loaded!"); } if (!LoadedMetadata) { throw new InvalidOperationException("Please load the video metadata first!"); } if (Metadata.Width == 0 || Metadata.Height == 0) { throw new InvalidDataException("Loaded metadata contains errors!"); } // we will be reading video in RGB24 format DataStream = FFmpegWrapper.OpenOutput(ffmpeg, $"{(offsetSeconds <= 0 ? "" : $"-ss {offsetSeconds:0.00}")} -i \"{Filename}\"" + $" -pix_fmt rgb24 -f rawvideo -"); OpenedForReading = true; }
/// <summary> /// Load audio metadata into memory. /// </summary> public async Task LoadMetadata(bool ignoreStreamErrors = false) { if (MetadataLoaded) { throw new InvalidOperationException("Video metadata is already loaded!"); } var r = FFmpegWrapper.OpenOutput(ffprobe, $"-i \"{Filename}\" -v quiet -print_format json=c=1 -show_format -show_streams"); try { var metadata = await JsonSerializer.DeserializeAsync <AudioMetadata>(r); try { var audioStream = metadata.Streams.Where(x => x.CodecType.ToLower().Trim() == "audio").FirstOrDefault(); if (audioStream != null) { metadata.Channels = audioStream.Channels; metadata.Codec = audioStream.CodecName; metadata.CodecLongName = audioStream.CodecLongName; metadata.SampleFormat = audioStream.SampleFmt; metadata.SampleRate = audioStream.SampleRate == null ? -1 : int.Parse(audioStream.SampleRate); metadata.Duration = audioStream.Duration == null? double.Parse(metadata.Format.Duration ?? "-1") : double.Parse(audioStream.Duration); metadata.BitRate = audioStream.BitRate == null ? -1 : int.Parse(audioStream.BitRate); metadata.BitDepth = audioStream.BitsPerSample; metadata.PredictedSampleCount = (int)Math.Round(metadata.Duration * metadata.SampleRate); if (metadata.BitDepth == 0) { // try to parse it from format if (metadata.SampleFormat.Contains("64")) { metadata.BitDepth = 64; } else if (metadata.SampleFormat.Contains("32")) { metadata.BitDepth = 32; } else if (metadata.SampleFormat.Contains("24")) { metadata.BitDepth = 24; } else if (metadata.SampleFormat.Contains("16")) { metadata.BitDepth = 16; } else if (metadata.SampleFormat.Contains("8")) { metadata.BitDepth = 8; } } } } catch (Exception ex) { // failed to interpret video stream settings if (!ignoreStreamErrors) { throw new InvalidDataException("Failed to parse audio stream data! " + ex.Message); } } MetadataLoaded = true; Metadata = metadata; } catch (JsonException ex) { throw new InvalidOperationException("Failed to interpret ffprobe audio metadata output! " + ex.Message); } }