public void FullTest( ) { var array = 0; var element = 0; IBufferStack stack = new BufferStack(source); while (stack.NextBuffer()) { Assert.AreEqual(array, stack.Index, $"failed Index [{array}]:[{stack.Index}]"); Assert.AreEqual(-1, stack.Element, $"failed Element [{array},{element}]:[{stack.Index},{stack.Element}]"); var expectedArray = source[array]; CollectionAssert.AreEqual(expectedArray, stack.Current, $"failed collection [{array}]"); while (stack.MoveNext()) { Assert.AreEqual(expectedArray[element], ((IByteStack)stack).Current, $"failed Current [{expectedArray[element]}]:[{((IByteStack)stack).Current}]"); ++element; } ++array; element = 0; } }
public void ExecuteNextBuffer( ) { IBufferStack stack = new BufferStack(source); // NextBuffer will position the stack at the first array, first element Assert.IsTrue(stack.NextBuffer(), "failed first NextBuffer"); Assert.AreEqual(0, stack.Index, $"failed first Index [0]:[{stack.Index}]"); Assert.AreEqual(-1, stack.Element, $"failed first Element [-1]:[{stack.Element}]"); // second array, 2nd element Assert.IsTrue(stack.NextBuffer(), "failed second NextBuffer"); Assert.AreEqual(1, stack.Index, $"failed second Index [0]:[{stack.Index}]"); Assert.AreEqual(-1, stack.Element, $"failed second Element [-1]:[{stack.Element}]"); }
public void ExecuteMoveNext( ) { IBufferStack stack = new BufferStack(source); // MoveNext will position the stack at first array, first element Assert.IsTrue(stack.MoveNext(), "failed first MoveNext"); Assert.AreEqual(0, stack.Index, $"failed first Index [0]:[{stack.Index}]"); Assert.AreEqual(0, stack.Element, $"failed first Element [0]:[{stack.Element}]"); // first array, 2nd element Assert.IsTrue(stack.MoveNext(), "failed second MoveNext"); Assert.AreEqual(0, stack.Index, $"failed second Index [0]:[{stack.Index}]"); Assert.AreEqual(1, stack.Element, $"failed second Element [1]:[{stack.Element}]"); }
/// <summary> /// Create an empty raw texture with an optional <see cref="BufferStack{T}"/>. backing. /// </summary> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="bufferStack">The buffer stack to retrieve the byte[] from.</param> public RawTexture(int width, int height, BufferStack <byte> bufferStack = null) { int size = width * height * 4; Width = width; Height = height; if (bufferStack != null) { this.bufferStack = bufferStack; Data = this.bufferStack.ReserveBuffer(size); } else { Data = new byte[size]; } }
private void decodingLoop(CancellationToken cancellationToken) { var packet = ffmpeg.av_packet_alloc(); const int max_pending_frames = 3; var bufferStack = new BufferStack <Rgba32>(max_pending_frames * 2); try { while (true) { if (cancellationToken.IsCancellationRequested) { return; } if (decodedFrames.Count < max_pending_frames && bufferStack.BuffersInUse < max_pending_frames * 2) { int readFrameResult = ffmpeg.av_read_frame(formatContext, packet); if (readFrameResult >= 0) { state = DecoderState.Running; if (packet->stream_index == stream->index) { if (ffmpeg.avcodec_send_packet(stream->codec, packet) < 0) { throw new Exception("Error sending packet."); } var result = ffmpeg.avcodec_receive_frame(stream->codec, frame); if (result == 0) { var frameTime = (frame->best_effort_timestamp - stream->start_time) * timeBaseInSeconds * 1000; if (!skipOutputUntilTime.HasValue || skipOutputUntilTime.Value < frameTime) { skipOutputUntilTime = null; SwsContext *swsCtx = null; try { swsCtx = ffmpeg.sws_getContext(codecParams.width, codecParams.height, (AVPixelFormat)frame->format, codecParams.width, codecParams.height, AVPixelFormat.AV_PIX_FMT_RGBA, 0, null, null, null); ffmpeg.sws_scale(swsCtx, frame->data, frame->linesize, 0, frame->height, frameRgb->data, frameRgb->linesize); } finally { ffmpeg.sws_freeContext(swsCtx); } if (!availableTextures.TryDequeue(out var tex)) { tex = new Texture(codecParams.width, codecParams.height, true); } var rawTex = new BufferStackTextureUpload(tex.Width, tex.Height, bufferStack); // todo: can likely make this more efficient var videoText = new Span <Rgba32>(frameRgb->data[0], uncompressedFrameSize / 4); videoText.CopyTo(rawTex.RawData); tex.SetData(rawTex); decodedFrames.Enqueue(new DecodedFrame { Time = frameTime, Texture = tex }); } lastDecodedFrameTime = (float)frameTime; } } } else if (readFrameResult == ffmpeg.AVERROR_EOF) { if (Looping) { Seek(0); } else { state = DecoderState.EndOfStream; } } else { state = DecoderState.Ready; Thread.Sleep(1); } } else { // wait until existing buffers are consumed. state = DecoderState.Ready; Thread.Sleep(1); } while (!decoderCommands.IsEmpty) { if (cancellationToken.IsCancellationRequested) { return; } if (decoderCommands.TryDequeue(out var cmd)) { cmd(); } } } } catch (Exception) { state = DecoderState.Faulted; } finally { ffmpeg.av_packet_free(&packet); if (state != DecoderState.Faulted) { state = DecoderState.Stopped; } } }
public FrameStatisticsDisplay(GameThread thread, TextureAtlas atlas) { Name = thread.Thread.Name; monitor = thread.Monitor; Origin = Anchor.TopRight; AutoSizeAxes = Axes.Both; Alpha = alpha_when_active; bool hasCounters = monitor.ActiveCounters.Any(b => b); Child = new Container { AutoSizeAxes = Axes.Both, Children = new[] { new Container { Origin = Anchor.TopRight, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Children = new[] { labelText = new SpriteText { Text = Name, Origin = Anchor.BottomCentre, Anchor = Anchor.CentreLeft, Rotation = -90, }, !hasCounters ? new Container { Width = 2 } : new Container { Masking = true, CornerRadius = 5, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Margin = new MarginPadding { Right = 2, Left = 2 }, Children = new Drawable[] { counterBarBackground = new Sprite { Texture = atlas.Add(1, HEIGHT), RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 1), }, new FillFlowContainer { Direction = FillDirection.Horizontal, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, ChildrenEnumerable = from StatisticsCounterType t in Enum.GetValues(typeof(StatisticsCounterType)) where monitor.ActiveCounters[(int)t] select counterBars[t] = new CounterBar { Colour = getColour(t), Label = t.ToString(), }, }, } } } }, mainContainer = new Container { Size = new Vector2(WIDTH, HEIGHT), Children = new[] { timeBarsContainer = new Container { Masking = true, CornerRadius = 5, RelativeSizeAxes = Axes.Both, Children = timeBars = new[] { new TimeBar(atlas), new TimeBar(atlas), }, }, fpsDisplay = new FpsDisplay(monitor.Clock) { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, }, overlayContainer = new Container { RelativeSizeAxes = Axes.Both, Alpha = 0, Children = new[] { new FillFlowContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5, 1), Padding = new MarginPadding { Right = 5 }, ChildrenEnumerable = from PerformanceCollectionType t in Enum.GetValues(typeof(PerformanceCollectionType)) select legendMapping[(int)t] = new SpriteText { Colour = getColour(t), Text = t.ToString(), Alpha = 0 }, }, new SpriteText { Padding = new MarginPadding { Left = 4 }, Text = $@"{visible_ms_range}ms" }, new SpriteText { Padding = new MarginPadding { Left = 4 }, Text = @"0ms", Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft } } } } } } }; textureBufferStack = new BufferStack <byte>(timeBars.Length * WIDTH); }
public TextureUpload(int size, BufferStack <byte> bufferStack = null) { this.bufferStack = bufferStack ?? global_buffer_stack; Data = this.bufferStack.ReserveBuffer(size); }
/// <summary> /// Create an empty raw texture with an optional <see cref="BufferStack{T}"/>. backing. /// </summary> /// <param name="width">The width of the texture.</param> /// <param name="height">The height of the texture.</param> /// <param name="bufferStack">The buffer stack to retrieve the Rgba32[] from.</param> public BufferStackTextureUpload(int width, int height, BufferStack <Rgba32> bufferStack) { this.bufferStack = bufferStack; RawData = bufferStack.ReserveBuffer(width * height); }
public FrameTimeDisplay(string name, PerformanceMonitor monitor) { Name = name; this.monitor = monitor; textureBufferStack = new BufferStack <byte>(timeBars.Length * WIDTH); }
public FrameStatisticsDisplay(string name, PerformanceMonitor monitor, TextureAtlas atlas) { Name = name; this.monitor = monitor; Origin = Anchor.TopRight; AutoSizeAxes = Axes.Both; Alpha = alpha_when_inactive; bool hasCounters = false; for (int i = 0; i < (int)StatisticsCounterType.AmountTypes; ++i) { if (monitor.Counters[i] != null) { hasCounters = true; } } Children = new Drawable[] { new Container { AutoSizeAxes = Axes.Both, Children = new[] { new Container { Origin = Anchor.TopRight, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Position = new Vector2(-2, 0), Children = new[] { labelText = new SpriteText { Text = Name, Origin = Anchor.BottomCentre, Anchor = Anchor.CentreLeft, Rotation = -90, Position = new Vector2(-2, 0), }, !hasCounters ? new Container() : new Container { Masking = true, CornerRadius = 5, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Children = new Drawable[] { counterBarBackground = new Sprite { Texture = atlas.Add(1, HEIGHT), RelativeSizeAxes = Axes.Both, Size = new Vector2(1, 1), }, new FlowContainer { Direction = FlowDirection.HorizontalOnly, AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Children = from StatisticsCounterType t in Enum.GetValues(typeof(StatisticsCounterType)) where t < StatisticsCounterType.AmountTypes && monitor.Counters[(int)t] != null select counterBars[t] = new CounterBar { Colour = getColour(t), Label = t.ToString(), }, }, } } } }, mainContainer = new Container { Size = new Vector2(WIDTH, HEIGHT), Children = new[] { timeBarsContainer = new Container { Masking = true, CornerRadius = 5, RelativeSizeAxes = Axes.Both, Children = timeBars = new[] { new TimeBar(atlas), new TimeBar(atlas), }, }, fpsDisplay = new FpsDisplay(monitor.Clock) { Anchor = Anchor.BottomRight, Origin = Anchor.BottomRight, }, overlayContainer = new Container { RelativeSizeAxes = Axes.Both, Alpha = 0, Children = new [] { new FlowContainer { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5, 1), Padding = new MarginPadding { Right = 5 }, Children = from PerformanceCollectionType t in Enum.GetValues(typeof(PerformanceCollectionType)) where t < PerformanceCollectionType.Empty select legendMapping[(int)t] = new SpriteText { Colour = getColour(t), Text = t.ToString(), Alpha = 0 }, }, new SpriteText { Padding = new MarginPadding { Left = 4 }, Text = $@"{VISIBLE_MS_RANGE}ms" }, new SpriteText { Padding = new MarginPadding { Left = 4 }, Text = @"0ms", Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft } } } } } } }, }; textureBufferStack = new BufferStack <byte>(timeBars.Length * WIDTH); }