private static void Warmup(ImmutableArray <SourceFile> files) { Console.WriteLine("Warming up..."); var addLock = new object(); var reportLock = new object(); var warmups = new SegmentedList <double>(1 << (int)Math.Ceiling(Math.Log2(files.Length * s_warmupCount))); var nextReport = -1L; var parsed = 0; var total = files.Length * s_warmupCount; var start = Stopwatch.GetTimestamp(); Parallel.ForEach(files, new ParallelOptions { MaxDegreeOfParallelism = s_threadsCount }, (file, _s, idx) => { for (var round = 0; round < s_warmupCount; round++) { var tStart = Stopwatch.GetTimestamp(); _ = LuaSyntaxTree.ParseText(file.Text, path: file.FileName); var tEnd = Stopwatch.GetTimestamp(); lock (addLock) warmups.Add(tEnd - tStart); var ourParsed = Interlocked.Increment(ref parsed); if (nextReport <= Stopwatch.GetTimestamp() && Monitor.TryEnter(reportLock)) { try { var delta = Stopwatch.GetTimestamp() - start; var timePerItem = (double)delta / ourParsed; var remaining = total - ourParsed; var eta = (long)Math.Ceiling(remaining * timePerItem); Console.WriteLine($"Warmup progress: {ourParsed}/{total}. ETA: {TimeSpan.FromTicks(eta)}"); nextReport = Stopwatch.GetTimestamp() + s_reportInterval; } finally { Monitor.Exit(reportLock); } } } }); var statistics = new Statistics(warmups.Take(files.Length * s_warmupCount)); using var writer = new IndentedTextWriter(Console.Out); writer.WriteLine($"Warmup results:"); PrintStatistics(writer, statistics, static d => Duration.Format(ceil(d)));
/// <summary> /// Recursively writes the tree containing all timings to the provided /// <paramref name="builder" />. /// </summary> /// <param name="builder"> /// The <see cref="StringBuilder" /> where all output will be written to. /// </param> /// <param name="indent">The indentation up to this level.</param> /// <param name="isLast"> /// Whether this is the last compiler in it's parent node. /// </param> /// <param name="isRoot">Whether this is the root microprofiler.</param> private void WriteTreeString(StringBuilder builder, string indent = "", bool isLast = true, bool isRoot = false) { builder.Append(indent); if (!isRoot) { builder.Append(isLast ? "└─ " : "├─ "); } builder.AppendLine($"{Name}: {Duration.Format(_stopwatch.ElapsedTicks)}"); if (!isRoot) { indent += isLast ? " " : "| "; } var childResults = _childProfilers; for (var i = 0; i < childResults.Count; i++) { childResults[i].WriteTreeString(builder, indent, i == childResults.Count - 1); } }
/// <summary> /// Initializes a new instance of the <see cref="MediaComponent"/> class. /// </summary> /// <param name="container">The container.</param> /// <param name="streamIndex">Index of the stream.</param> /// <exception cref="ArgumentNullException">container</exception> /// <exception cref="MediaContainerException">The container exception.</exception> protected MediaComponent(MediaContainer container, int streamIndex) { // Parted from: https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffplay.c#L2559 // avctx = avcodec_alloc_context3(NULL); Container = container ?? throw new ArgumentNullException(nameof(container)); CodecContext = ffmpeg.avcodec_alloc_context3(null); RC.Current.Add(CodecContext, $"134: {nameof(MediaComponent)}[{MediaType}].ctor()"); StreamIndex = streamIndex; Stream = container.InputContext->streams[StreamIndex]; StreamInfo = container.MediaInfo.Streams[StreamIndex]; // Set default codec context options from probed stream var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar); if (setCodecParamsResult < 0) { Container.Parent?.Log(MediaLogMessageType.Warning, $"Could not set codec parameters. Error code: {setCodecParamsResult}"); } // We set the packet timebase in the same timebase as the stream as opposed to the tpyical AV_TIME_BASE if (this is VideoComponent && Container.MediaOptions.VideoForcedFps > 0) { var fpsRational = ffmpeg.av_d2q(Container.MediaOptions.VideoForcedFps, 1000000); Stream->r_frame_rate = fpsRational; CodecContext->pkt_timebase = new AVRational { num = fpsRational.den, den = fpsRational.num }; } else { CodecContext->pkt_timebase = Stream->time_base; } // Find the default decoder codec from the stream and set it. var defaultCodec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id); AVCodec *forcedCodec = null; // If set, change the codec to the forced codec. if (Container.MediaOptions.DecoderCodec.ContainsKey(StreamIndex) && string.IsNullOrWhiteSpace(Container.MediaOptions.DecoderCodec[StreamIndex]) == false) { var forcedCodecName = Container.MediaOptions.DecoderCodec[StreamIndex]; forcedCodec = ffmpeg.avcodec_find_decoder_by_name(forcedCodecName); if (forcedCodec == null) { Container.Parent?.Log(MediaLogMessageType.Warning, $"COMP {MediaType.ToString().ToUpperInvariant()}: Unable to set decoder codec to '{forcedCodecName}' on stream index {StreamIndex}"); } } // Check we have a valid codec to open and process the stream. if (defaultCodec == null && forcedCodec == null) { var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}"; CloseComponent(); throw new MediaContainerException(errorMessage); } var codecCandidates = new AVCodec *[] { forcedCodec, defaultCodec }; AVCodec *selectedCodec = null; var codecOpenResult = 0; foreach (var codec in codecCandidates) { if (codec == null) { continue; } // Pass default codec stuff to the codec contect CodecContext->codec_id = codec->id; if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) != 0) { CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_TRUNCATED; } if ((codec->capabilities & ffmpeg.AV_CODEC_FLAG2_CHUNKS) != 0) { CodecContext->flags |= ffmpeg.AV_CODEC_FLAG2_CHUNKS; } // Process the decoder options { var decoderOptions = Container.MediaOptions.DecoderParams; // Configure the codec context flags if (decoderOptions.EnableFastDecoding) { CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST; } if (decoderOptions.EnableLowDelay) { CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_LOW_DELAY; } // process the low res option if (decoderOptions.EnableLowRes && codec->max_lowres > 0) { decoderOptions.LowResIndex = codec->max_lowres.ToString(CultureInfo.InvariantCulture); } // Ensure ref counted frames for audio and video decoding if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO) { decoderOptions.RefCountedFrames = "1"; } } // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto // decoding is very fast in most scenarios. var codecOptions = Container.MediaOptions.DecoderParams.GetStreamCodecOptions(Stream->index); // Enable Hardware acceleration if requested if (this is VideoComponent && container.MediaOptions.VideoHardwareDevice != null) { HardwareAccelerator.Attach(this as VideoComponent, container.MediaOptions.VideoHardwareDevice); } // Open the CodecContext. This requires exclusive FFmpeg access lock (CodecOpenLock) { fixed(AVDictionary **codecOptionsRef = &codecOptions.Pointer) codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, codecOptionsRef); } // Check if the codec opened successfully if (codecOpenResult < 0) { Container.Parent?.Log(MediaLogMessageType.Warning, $"Unable to open codec '{FFInterop.PtrToStringUTF8(codec->name)}' on stream {streamIndex}"); continue; } // If there are any codec options left over from passing them, it means they were not consumed var currentEntry = codecOptions.First(); while (currentEntry != null && currentEntry?.Key != null) { Container.Parent?.Log(MediaLogMessageType.Warning, $"Invalid codec option: '{currentEntry.Key}' for codec '{FFInterop.PtrToStringUTF8(codec->name)}', stream {streamIndex}"); currentEntry = codecOptions.Next(currentEntry); } selectedCodec = codec; break; } if (selectedCodec == null) { CloseComponent(); throw new MediaContainerException($"Unable to find suitable decoder codec for stream {streamIndex}. Error code {codecOpenResult}"); } // Startup done. Set some options. Stream->discard = AVDiscard.AVDISCARD_DEFAULT; MediaType = (MediaType)CodecContext->codec_type; // Compute the start time if (Stream->start_time == ffmpeg.AV_NOPTS_VALUE) { StartTimeOffset = Container.MediaStartTimeOffset; } else { StartTimeOffset = Stream->start_time.ToTimeSpan(Stream->time_base); } // compute the duration if (Stream->duration == ffmpeg.AV_NOPTS_VALUE || Stream->duration == 0) { Duration = Container.InputContext->duration.ToTimeSpan(); } else { Duration = Stream->duration.ToTimeSpan(Stream->time_base); } CodecId = Stream->codec->codec_id; CodecName = FFInterop.PtrToStringUTF8(selectedCodec->name); Bitrate = Stream->codec->bit_rate < 0 ? 0 : Convert.ToUInt64(Stream->codec->bit_rate); Container.Parent?.Log(MediaLogMessageType.Debug, $"COMP {MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTimeOffset.Format()}; Duration: {Duration.Format()}"); }
/// <summary> /// Initializes a new instance of the <see cref="MediaComponent"/> class. /// </summary> /// <param name="container">The container.</param> /// <param name="streamIndex">Index of the stream.</param> /// <exception cref="System.ArgumentNullException">container</exception> /// <exception cref="System.Exception"></exception> protected MediaComponent(MediaContainer container, int streamIndex) { Container = container ?? throw new ArgumentNullException(nameof(container)); CodecContext = ffmpeg.avcodec_alloc_context3(null); RC.Current.Add(CodecContext, $"134: {nameof(MediaComponent)}[{MediaType}].ctor()"); StreamIndex = streamIndex; Stream = container.InputContext->streams[StreamIndex]; // Set codec options var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar); if (setCodecParamsResult < 0) { Container.Logger?.Log(MediaLogMessageType.Warning, $"Could not set codec parameters. Error code: {setCodecParamsResult}"); } // We set the packet timebase in the same timebase as the stream as opposed to the tpyical AV_TIME_BASE ffmpeg.av_codec_set_pkt_timebase(CodecContext, Stream->time_base); // Find the codec and set it. var codec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id); if (codec == null) { var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}"; CloseComponent(); throw new MediaContainerException(errorMessage); } CodecContext->codec_id = codec->id; // Process the low res index option var lowResIndex = ffmpeg.av_codec_get_max_lowres(codec); if (Container.MediaOptions.EnableLowRes) { ffmpeg.av_codec_set_lowres(CodecContext, lowResIndex); CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE; } else { lowResIndex = 0; } // Configure the codec context flags if (Container.MediaOptions.EnableFastDecoding) { CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST; } if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_DR1) != 0) { CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE; } if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) != 0) { CodecContext->flags |= ffmpeg.AV_CODEC_CAP_TRUNCATED; } if ((codec->capabilities & ffmpeg.CODEC_FLAG2_CHUNKS) != 0) { CodecContext->flags |= ffmpeg.CODEC_FLAG2_CHUNKS; } // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto // decoding is very fast in most scenarios. var codecOptions = Container.MediaOptions.CodecOptions.FilterOptions(CodecContext->codec_id, Container.InputContext, Stream, codec); if (codecOptions.HasKey(CodecOption.Threads) == false) { codecOptions[CodecOption.Threads] = "auto"; } if (lowResIndex != 0) { codecOptions[CodecOption.LowRes] = lowResIndex.ToString(CultureInfo.InvariantCulture); } if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO) { codecOptions[CodecOption.RefCountedFrames] = 1.ToString(CultureInfo.InvariantCulture); } // Open the CodecContext var codecOpenResult = 0; fixed(AVDictionary **reference = &codecOptions.Pointer) codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, reference); if (codecOpenResult < 0) { CloseComponent(); throw new MediaContainerException($"Unable to open codec. Error code {codecOpenResult}"); } // If there are any codec options left over from passing them, it means they were not consumed if (codecOptions.First() != null) { Container.Logger?.Log(MediaLogMessageType.Warning, $"Codec Option '{codecOptions.First().Key}' not found."); } // Startup done. Set some options. Stream->discard = AVDiscard.AVDISCARD_DEFAULT; MediaType = (MediaType)CodecContext->codec_type; // Compute the start time if (Stream->start_time == Utils.FFmpeg.AV_NOPTS) { StartTimeOffset = Container.MediaStartTimeOffset; } else { StartTimeOffset = Stream->start_time.ToTimeSpan(Stream->time_base); } // compute the duration if (Stream->duration == Utils.FFmpeg.AV_NOPTS || Stream->duration == 0) { Duration = Container.InputContext->duration.ToTimeSpan(); } else { Duration = Stream->duration.ToTimeSpan(Stream->time_base); } CodecId = Stream->codec->codec_id; CodecName = ffmpeg.avcodec_get_name(CodecId); Bitrate = (int)Stream->codec->bit_rate; Container.Logger?.Log(MediaLogMessageType.Debug, $"COMP {MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTimeOffset.Format()}; Duration: {Duration.Format()}"); }
/// <summary> /// Initializes a new instance of the <see cref="MediaComponent"/> class. /// </summary> /// <param name="container">The container.</param> /// <param name="streamIndex">Index of the stream.</param> /// <exception cref="ArgumentNullException">container.</exception> /// <exception cref="MediaContainerException">The container exception.</exception> public MediaComponent(MediaContainer container, int streamIndex) { // Ported from: https://github.com/FFmpeg/FFmpeg/blob/master/fftools/ffplay.c#L2559 Container = container ?? throw new ArgumentNullException(nameof(container)); m_LoggingHandler = ((ILoggingSource)Container).LoggingHandler; m_CodecContext = new IntPtr(ffmpeg.avcodec_alloc_context3(null)); RC.Current.Add(CodecContext); StreamIndex = streamIndex; m_Stream = new IntPtr(container.InputContext->streams[streamIndex]); StreamInfo = container.MediaInfo.Streams[streamIndex]; // Set default codec context options from probed stream var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar); if (setCodecParamsResult < 0) { this.LogWarning(Aspects.Component, $"Could not set codec parameters. Error code: {setCodecParamsResult}"); } // We set the packet timebase in the same timebase as the stream as opposed to the typical AV_TIME_BASE if (this is VideoComponent && Container.MediaOptions.VideoForcedFps > 0) { var fpsRational = ffmpeg.av_d2q(Container.MediaOptions.VideoForcedFps, 1000000); Stream->r_frame_rate = fpsRational; CodecContext->pkt_timebase = new AVRational { num = fpsRational.den, den = fpsRational.num }; } else { CodecContext->pkt_timebase = Stream->time_base; } // Find the default decoder codec from the stream and set it. var defaultCodec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id); AVCodec *forcedCodec = null; // If set, change the codec to the forced codec. if (Container.MediaOptions.DecoderCodec.ContainsKey(StreamIndex) && string.IsNullOrWhiteSpace(Container.MediaOptions.DecoderCodec[StreamIndex]) == false) { var forcedCodecName = Container.MediaOptions.DecoderCodec[StreamIndex]; forcedCodec = ffmpeg.avcodec_find_decoder_by_name(forcedCodecName); if (forcedCodec == null) { this.LogWarning(Aspects.Component, $"COMP {MediaType.ToString().ToUpperInvariant()}: " + $"Unable to set decoder codec to '{forcedCodecName}' on stream index {StreamIndex}"); } } // Check we have a valid codec to open and process the stream. if (defaultCodec == null && forcedCodec == null) { var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}"; CloseComponent(); throw new MediaContainerException(errorMessage); } var codecCandidates = new[] { forcedCodec, defaultCodec }; AVCodec *selectedCodec = null; var codecOpenResult = 0; foreach (var codec in codecCandidates) { if (codec == null) { continue; } // Pass default codec stuff to the codec context CodecContext->codec_id = codec->id; // Process the decoder options { var decoderOptions = Container.MediaOptions.DecoderParams; // Configure the codec context flags if (decoderOptions.EnableFastDecoding) { CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST; } if (decoderOptions.EnableLowDelayDecoding) { CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_LOW_DELAY; } // process the low res option if (decoderOptions.LowResolutionIndex != VideoResolutionDivider.Full && codec->max_lowres > 0) { var lowResOption = Math.Min((byte)decoderOptions.LowResolutionIndex, codec->max_lowres) .ToString(CultureInfo.InvariantCulture); decoderOptions.LowResIndexOption = lowResOption; } // Ensure ref counted frames for audio and video decoding if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO) { decoderOptions.RefCountedFrames = "1"; } CodecContext->thread_count = 4; } // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto // decoding is very fast in most scenarios. var codecOptions = Container.MediaOptions.DecoderParams.GetStreamCodecOptions(Stream->index); // Enable Hardware acceleration if requested (this as VideoComponent)?.AttachHardwareDevice(container.MediaOptions.VideoHardwareDevice); // Open the CodecContext. This requires exclusive FFmpeg access lock (CodecLock) { var codecOptionsRef = codecOptions.Pointer; codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, &codecOptionsRef); codecOptions.UpdateReference(codecOptionsRef); } // Check if the codec opened successfully if (codecOpenResult < 0) { this.LogWarning(Aspects.Component, $"Unable to open codec '{Utilities.PtrToStringUTF8(codec->name)}' on stream {streamIndex}"); continue; } // If there are any codec options left over from passing them, it means they were not consumed var currentEntry = codecOptions.First(); while (currentEntry?.Key != null) { this.LogWarning(Aspects.Component, $"Invalid codec option: '{currentEntry.Key}' for codec '{Utilities.PtrToStringUTF8(codec->name)}', stream {streamIndex}"); currentEntry = codecOptions.Next(currentEntry); } selectedCodec = codec; break; } if (selectedCodec == null) { CloseComponent(); throw new MediaContainerException($"Unable to find suitable decoder codec for stream {streamIndex}. Error code {codecOpenResult}"); } // Startup done. Set some options. Stream->discard = AVDiscard.AVDISCARD_DEFAULT; MediaType = (MediaType)CodecContext->codec_type; switch (MediaType) { case MediaType.Audio: case MediaType.Video: BufferCountThreshold = 25; BufferDurationThreshold = TimeSpan.FromSeconds(1); DecodePacketFunction = DecodeNextAVFrame; break; default: throw new NotSupportedException($"A component of MediaType '{MediaType}' is not supported"); } var contentDisposition = StreamInfo.Disposition; IsStillPictures = MediaType == MediaType.Video && ((contentDisposition & ffmpeg.AV_DISPOSITION_ATTACHED_PIC) != 0 || (contentDisposition & ffmpeg.AV_DISPOSITION_STILL_IMAGE) != 0 || (contentDisposition & ffmpeg.AV_DISPOSITION_TIMED_THUMBNAILS) != 0); if (IsStillPictures) { BufferCountThreshold = 0; BufferDurationThreshold = TimeSpan.Zero; } // Compute the start time StartTime = Stream->start_time == ffmpeg.AV_NOPTS_VALUE ? Container.MediaInfo.StartTime == TimeSpan.MinValue ? TimeSpan.Zero : Container.MediaInfo.StartTime : Stream->start_time.ToTimeSpan(Stream->time_base); // Compute the duration Duration = (Stream->duration == ffmpeg.AV_NOPTS_VALUE || Stream->duration <= 0) ? Container.MediaInfo.Duration : Stream->duration.ToTimeSpan(Stream->time_base); CodecId = Stream->codec->codec_id; CodecName = Utilities.PtrToStringUTF8(selectedCodec->name); BitRate = Stream->codec->bit_rate < 0 ? 0 : Stream->codec->bit_rate; this.LogDebug(Aspects.Component, $"{MediaType.ToString().ToUpperInvariant()} - Start Time: {StartTime.Format()}; Duration: {Duration.Format()}"); // Begin processing with a flush packet SendFlushPacket(); }
public override string ToString() => $"{NobreakState}; De propósito: {OnPurpose.SimNao()}; Duração: {Duration.Format()}";
/// <summary> /// Initializes a new instance of the <see cref="MediaComponent"/> class. /// </summary> /// <param name="container">The container.</param> /// <param name="streamIndex">Index of the stream.</param> /// <exception cref="ArgumentNullException">container</exception> /// <exception cref="MediaContainerException">The container exception.</exception> protected MediaComponent(MediaContainer container, int streamIndex) { Container = container ?? throw new ArgumentNullException(nameof(container)); CodecContext = ffmpeg.avcodec_alloc_context3(null); RC.Current.Add(CodecContext, $"134: {nameof(MediaComponent)}[{MediaType}].ctor()"); StreamIndex = streamIndex; Stream = container.InputContext->streams[StreamIndex]; StreamInfo = container.MediaInfo.Streams[StreamIndex]; // Set codec options var setCodecParamsResult = ffmpeg.avcodec_parameters_to_context(CodecContext, Stream->codecpar); if (setCodecParamsResult < 0) { Container.Parent?.Log(MediaLogMessageType.Warning, $"Could not set codec parameters. Error code: {setCodecParamsResult}"); } // We set the packet timebase in the same timebase as the stream as opposed to the tpyical AV_TIME_BASE if (this is VideoComponent && Container.MediaOptions.VideoForcedFps != null) { ffmpeg.av_codec_set_pkt_timebase(CodecContext, Container.MediaOptions.VideoForcedFps.Value); ffmpeg.av_stream_set_r_frame_rate(Stream, Container.MediaOptions.VideoForcedFps.Value); } else { ffmpeg.av_codec_set_pkt_timebase(CodecContext, Stream->time_base); } // Find the codec and set it. var codec = ffmpeg.avcodec_find_decoder(Stream->codec->codec_id); if (codec == null) { var errorMessage = $"Fatal error. Unable to find suitable decoder for {Stream->codec->codec_id.ToString()}"; CloseComponent(); throw new MediaContainerException(errorMessage); } CodecContext->codec_id = codec->id; // Process the low res index option var lowResIndex = ffmpeg.av_codec_get_max_lowres(codec); if (Container.MediaOptions.EnableLowRes) { ffmpeg.av_codec_set_lowres(CodecContext, lowResIndex); CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE; } else { lowResIndex = 0; } // Configure the codec context flags if (Container.MediaOptions.EnableFastDecoding) { CodecContext->flags2 |= ffmpeg.AV_CODEC_FLAG2_FAST; } if (Container.MediaOptions.EnableLowDelay) { CodecContext->flags |= ffmpeg.AV_CODEC_FLAG_LOW_DELAY; } if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_DR1) != 0) { CodecContext->flags |= ffmpeg.CODEC_FLAG_EMU_EDGE; } if ((codec->capabilities & ffmpeg.AV_CODEC_CAP_TRUNCATED) != 0) { CodecContext->flags |= ffmpeg.AV_CODEC_CAP_TRUNCATED; } if ((codec->capabilities & ffmpeg.CODEC_FLAG2_CHUNKS) != 0) { CodecContext->flags |= ffmpeg.CODEC_FLAG2_CHUNKS; } // Setup additional settings. The most important one is Threads -- Setting it to 1 decoding is very slow. Setting it to auto // decoding is very fast in most scenarios. var codecOptions = Container.MediaOptions.CodecOptions.FilterOptions(CodecContext->codec_id, Container.InputContext, Stream, codec); if (codecOptions.HasKey(MediaCodecOptions.Names.Threads) == false) { codecOptions[MediaCodecOptions.Names.Threads] = "auto"; } if (lowResIndex != 0) { codecOptions[MediaCodecOptions.Names.LowRes] = lowResIndex.ToString(CultureInfo.InvariantCulture); } if (CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_VIDEO || CodecContext->codec_type == AVMediaType.AVMEDIA_TYPE_AUDIO) { codecOptions[MediaCodecOptions.Names.RefCountedFrames] = 1.ToString(CultureInfo.InvariantCulture); } // Enable Hardware acceleration if requested if (this is VideoComponent && container.MediaOptions.EnableHardwareAcceleration) { HardwareAccelerator.Cuda.AttachDevice(this as VideoComponent); } // Open the CodecContext. This requires exclusive FFmpeg access var codecOpenResult = 0; lock (CodecOpenLock) { fixed(AVDictionary **reference = &codecOptions.Pointer) codecOpenResult = ffmpeg.avcodec_open2(CodecContext, codec, reference); } // Check if the codec opened successfully if (codecOpenResult < 0) { CloseComponent(); throw new MediaContainerException($"Unable to open codec. Error code {codecOpenResult}"); } // If there are any codec options left over from passing them, it means they were not consumed var currentEntry = codecOptions.First(); while (currentEntry != null && currentEntry?.Key != null) { Container.Parent?.Log(MediaLogMessageType.Warning, $"Invalid codec option: '{currentEntry.Key}'"); currentEntry = codecOptions.Next(currentEntry); } // Startup done. Set some options. Stream->discard = AVDiscard.AVDISCARD_DEFAULT; MediaType = (MediaType)CodecContext->codec_type; // Compute the start time if (Stream->start_time == ffmpeg.AV_NOPTS_VALUE) { StartTimeOffset = Container.MediaStartTimeOffset; } else { StartTimeOffset = Stream->start_time.ToTimeSpan(Stream->time_base); } // compute the duration if (Stream->duration == ffmpeg.AV_NOPTS_VALUE || Stream->duration == 0) { Duration = Container.InputContext->duration.ToTimeSpan(); } else { Duration = Stream->duration.ToTimeSpan(Stream->time_base); } CodecId = Stream->codec->codec_id; CodecName = ffmpeg.avcodec_get_name(CodecId); Bitrate = Stream->codec->bit_rate < 0 ? 0 : Convert.ToUInt64(Stream->codec->bit_rate); Container.Parent?.Log(MediaLogMessageType.Debug, $"COMP {MediaType.ToString().ToUpperInvariant()}: Start Offset: {StartTimeOffset.Format()}; Duration: {Duration.Format()}"); }