private void UpdateTrace(Data <Frame> frameData, ref PayloadTrace trace)
 {
     if (frameData.Trace != null)
     {
         if (trace == null)
         {
             trace = PayloadTrace.Create(_name, frameData.Trace, 0);
         }
         else
         {
             trace.AddPrevious(frameData.Trace);
         }
     }
 }
        private bool RenderFFMpeg(Frame resultPayload, out PayloadTrace trace)
        {
            bool first = true;

            trace = null;

            var frames = _inputRuntimesSorted.Where(s => s.Description.Visible).
                         Select(s => new { runtime = s, frameData = GetRuntimeOrFixedFrame(s) }).
                         Where(s => s.frameData != null).ToList();

            if (frames.Count == 1)
            {
                resultPayload.CopyContentFromAndSetPts(frames[0].frameData.Payload, _currentFpsTicks);
            }
            else if (frames.Count > 1)
            {
                Frame frameMainCopy = null;
                foreach (var s in frames)
                {
                    var frameData = s.frameData;
                    var runtime   = s.runtime;
                    var frame     = frameData.Payload;
                    UpdateTrace(frameData, ref trace);

                    if (first)
                    {
                        frameMainCopy = _framePool.Rent();
                        frameMainCopy.CopyContentFrom(frame);
                        _helper.Init(frameMainCopy, _setup.WeakOptions.PixelFormatGroup.BlendType);
                        first = false;
                    }
                    else
                    {
                        if (frame.Properties.Height != runtime.SlicesHeight)
                        {
                            runtime.SlicesHeight = frame.Properties.Height;
                            runtime.Slices       = GetSlices(runtime, frame.Properties.Height);
                        }

                        int x = (int)(runtime.Description.Rect.Left * _setup.Width);
                        int y = (int)(runtime.Description.Rect.Top * _setup.Height);

                        if (runtime.Slices == null)
                        {
                            _helper.Add(frame, x, y, 0, frame.Properties.Height);
                        }
                        else
                        {
                            Task.WhenAll(runtime.Slices.Select(s => Task.Run(() => _helper.Add(frame, x, y, s.yOffset, s.yCount))).ToArray()).Wait();
                        }
                    }
                }
                _helper.Get(resultPayload, _currentFpsTicks);
                _framePool.Back(frameMainCopy);
            }

            if (frames.Count > 0)
            {
                if (trace != null)
                {
                    trace = PayloadTrace.Create(_name, trace);
                }

                if (resultPayload.Properties.Width != _setup.Width ||
                    resultPayload.Properties.Height != _setup.Height ||
                    resultPayload.Properties.Format != _setup.OutputPixelFormat)
                {
                    Core.LogWarning($"Ignoring wrongly blended packet " +
                                    $"{resultPayload.Properties.Width}x{resultPayload.Properties.Height}x{resultPayload.Properties.Format} != Setup({_setup.Width}x{_setup.Height}x{_setup.OutputPixelFormat})");
                    return(false);
                }
                return(true);
            }
            return(false);
        }
        private bool RenderDirectX(Frame resultPayload, out PayloadTrace trace)
        {
            trace = null;
            bool hasAnyContent = false;
            var  dx            = _setup.Dx;

            try
            {
                if (dx.IsBrokenAndLog("Blender"))
                {
                    return(false);
                }

                var texture = dx.Pool.Get("Blender", DirectXResource.Desc(_setup.Width, _setup.Height, SharpDX.DXGI.Format.B8G8R8A8_UNorm, BindFlags.ShaderResource | BindFlags.RenderTarget, ResourceUsage.Default, ResourceOptionFlags.None));

                _defferedContext = _defferedContext ?? new DeviceContext(dx.Device);
                //using
                using (var rtv = texture.GetRenderTargetView())
                {
                    int counter = 0;

                    foreach (var runtime in _inputRuntimesSorted)
                    {
                        var frameData = GetRuntimeOrFixedFrame(runtime);
                        if (frameData != null && runtime.Description.Visible)
                        {
                            hasAnyContent = true;

                            UpdateTrace(frameData, ref trace);

                            var xResource = frameData.Payload.DirectXResourceRef.Instance;

                            if (xResource.CommandList != null)
                            {
                                _defferedContext.ExecuteCommandList(xResource.CommandList, false);
                                xResource.CommandList.Dispose();
                                xResource.CommandList = null;
                            }

                            var pipeline = GetPipeline(runtime, texture, xResource);
                            SetDebugColor(pipeline, counter++);
                            UpdatePositionInDxPipeline(runtime, pipeline, xResource.Texture2D.Description.Width, xResource.Texture2D.Description.Height);

                            var filteredResource = runtime.DirectXFilterRuntime.Render(dx, runtime.Description.FilterChain, _defferedContext, xResource);
                            if (ReferenceEquals(filteredResource, xResource))
                            {
                                using (var srv = filteredResource.GetShaderResourceView())
                                    pipeline.Render(_defferedContext, rtv, srv);
                                dx.Flush(_defferedContext, "Blender Flush All");
                            }
                            else
                            {
                                dx.Flush(_defferedContext, "Blender Flush All");
                                using (var srvFiltered = filteredResource.GetShaderResourceView())
                                    pipeline.Render(_defferedContext, rtv, srvFiltered);
                                dx.Flush(_defferedContext, "Blender Flush All");
                                filteredResource.Dispose();
                            }
                        }
                    }
                }

                if (hasAnyContent)
                {
                    if (trace != null)
                    {
                        trace = PayloadTrace.Create(_name, trace);
                    }

                    dx.Flush(_defferedContext, "Blender Flush All");
                    var allFilteredResource = _dxFilterRuntime.Render(dx, _setup.WeakOptions.FilterChain, _defferedContext, texture);
                    dx.Flush(_defferedContext, "Blender Flush All");

                    resultPayload.InitFromDirectX(allFilteredResource, _currentFpsTicks);

                    if (allFilteredResource != texture)
                    {
                        dx.Pool.Back(texture);
                    }
                }
            }
            catch (Exception e)
            {
                dx.Broken(e);
            }

            return(hasAnyContent);
        }
        public ErrorCodes Read(Frame resultPayload, out PayloadTrace resultTrace)
        {
            long now = Core.GetCurrentTime();

            _lastReadTime = now;
            long currentFpsTime    = ToTime(_currentFpsTicks);
            long currentFrameDelay = now - currentFpsTime;

            if (currentFrameDelay > _setup.MaxDelay) //2 sec
            {
                // we too late
                Core.LogError($"Blender skips batch due to high delay from now {currentFrameDelay / 10_000}ms");

                _currentFpsTicks  = ToTicks(now - _setup.ComebackDelay); // -300 ms
                currentFpsTime    = ToTime(_currentFpsTicks);
                currentFrameDelay = now - currentFpsTime;
            }

            bool runtimesReady = currentFrameDelay > 0; // don't go behind real-time. Especially relevant for cases when all _inputRuntimes are Fixed images

            if (currentFrameDelay > 0 && currentFrameDelay <= _delayFromRuntime)
            {
                foreach (var runtime in _inputRuntimes)
                {
                    bool ok = false;
                    if (runtime.Frames.Count > 0)
                    {
                        long first = ToTicks(runtime.Frames.First.Value.Payload.GetPts());
                        long last  = ToTicks(runtime.Frames.Last.Value.Payload.GetPts());

                        if (_currentFpsTicks <= last)
                        {
                            ok = true;
                        }
                    }
                    else if (runtime.FixedFrame != null)
                    {
                        ok = true;
                    }

                    if (!ok)
                    {
                        runtimesReady = false;
                        break;
                    }
                }
            }

            // prepare frame
            if (runtimesReady)
            {
                bool hasAnyContent;
                if (_setup.Dx == null)
                {
                    hasAnyContent = RenderFFMpeg(resultPayload, out resultTrace);
                }
                else
                {
                    hasAnyContent = RenderDirectX(resultPayload, out resultTrace);
                }

                if (hasAnyContent)
                {
                    if (_overloadController == null)
                    {
                        _currentFpsTicks += 1;
                    }
                    else
                    {
                        _overloadController.Increment(ref _currentFpsTicks, 1);
                    }
                    return(ErrorCodes.Ok);
                }
            }
            resultTrace = null;
            return(ErrorCodes.TryAgainLater);
        }
        protected override void ProcessData(Data <Frame> data, ContextVersion <IEncoderContext, EncoderSetup, Packet> currentVersion)
        {
            _statisticKeeper.Data.InFrames++; //unsafe, but ok

            lock (this)
            {
                if (currentVersion == null || currentVersion.Context == null)
                {
                    Streamer.FramePool.Back(data.Payload);
                    return;
                }
                data.Trace?.Received(Name);
                bool enforceIFrame = false;

                if (_makeIFrameNextPacket == data.Version && currentVersion.ContextSetup.SupportsEnforcingIFrame)
                {
                    Core.LogInfo("Trying to enforce IFrame on encoder");
                    _makeIFrameNextPacket = 0;
                    enforceIFrame         = true;
                }

                int writeRes = currentVersion.Context.Instance.Write(data.Payload, enforceIFrame);
                Streamer.FramePool.Back(data.Payload);

                if (Core.IsFailed(writeRes))
                {
                    _statisticKeeper.Data.Errors++;
                    Core.LogError($"Write to {Name}: {Core.GetErrorMessage(writeRes)}", "write to node failed");
                    return;
                }

                while (!currentVersion.IsInterrupted)
                {
                    var resultPayload = Streamer.PacketPool.Rent();
                    var readRes       = currentVersion.Context.Instance.Read(resultPayload);
                    if (readRes == ErrorCodes.TryAgainLater)
                    {
                        Streamer.PacketPool.Back(resultPayload);
                        break;
                    }
                    else if (Core.IsFailed(readRes))
                    {
                        _statisticKeeper.Data.Errors++;
                        Streamer.PacketPool.Back(resultPayload);
                        Core.LogError($"Read from {Name}: {Core.GetErrorMessage(writeRes)}", "read from node failed");
                        break;
                    }
                    else // success
                    {
                        _statisticKeeper.Data.OutFrames++; //unsafe, but ok
                        currentVersion.OutputQueue.Enqueue(new Data <Packet>(resultPayload, currentVersion.Version, data.SequenceNumber, PayloadTrace.Create(Name, data.Trace)));
                    }
                }
            }
        }
        protected override void ProcessData(Data <Frame> data, ContextVersion <IFilterContext, FilterSetup, Frame> currentVersion)
        {
            //if (Name.Name == "FMix" && data.Payload != null)
            //{
            //    Core.LogInfo($"--------------------------------In {Name} {data.SourceId}  {data.Payload.Properties.Pts}");
            //}

            _statisticKeeper.Data.InFrames++; //unsafe, but ok
            if (currentVersion == null)
            {
                Streamer.FramePool.Back(data.Payload);
                return;
            }
            data.Trace?.Received(Name);

            var instance = currentVersion.Context.Instance;
            //using var mem = new TimeMeasurer($"Filter '{Name}'");

            int writeRes = instance.Write(data.Payload, data.SourceId);

            if (writeRes == (int)ErrorCodes.NullFilter)
            {
                _statisticKeeper.Data.OutFrames++; //unsafe, but ok
                currentVersion.OutputQueue.Enqueue(data);
                return;
            }

            Streamer.FramePool.Back(data.Payload);

            if (Core.IsFailed(writeRes))
            {
                _statisticKeeper.Data.Errors++;
                Core.LogError($"Write to {Name} (sid:{data.SourceId}): {Core.GetErrorMessage(writeRes)}", "write to node failed");
                return;
            }

            while (!currentVersion.IsInterrupted)
            {
                var resultPayload = Streamer.FramePool.Rent();
                var readRes       = instance.Read(resultPayload);
                if (readRes == ErrorCodes.TryAgainLater)
                {
                    Streamer.FramePool.Back(resultPayload);
                    break;
                }
                else if (Core.IsFailed(readRes))
                {
                    _statisticKeeper.Data.Errors++;
                    Streamer.FramePool.Back(resultPayload);
                    Core.LogError($"Read from {Name}: {Core.GetErrorMessage((int)readRes)}", "read from node failed");
                    break;
                }
                else // success
                {
                    //if (Name.Name == "FMix" && data.Payload != null)
                    //{
                    //    Core.LogInfo($"----------------------------------Out {Name} -  {resultPayload.Properties.Pts}");
                    //}

                    _statisticKeeper.Data.OutFrames++; //unsafe, but ok
                    currentVersion.OutputQueue.Enqueue(new Data <Frame>(resultPayload, currentVersion.Version, data.SequenceNumber, PayloadTrace.Create(Name, data.Trace)));
                }
            }
        }
Exemple #7
0
        protected override void ProcessData(Data <Packet> data, ContextVersion <IDecoderContext, DecoderSetup, Frame> currentVersion)
        {
            _statisticKeeper.Data.InFrames++; //unsafe, but ok
            if (currentVersion == null)
            {
                Streamer.PacketPool.Back(data.Payload);
                return;
            }
            data.Trace?.Received(Name);

            int writeRes = currentVersion.Context.Instance.Write(data.Payload);

            Streamer.PacketPool.Back(data.Payload);

            if (Core.IsFailed(writeRes))
            {
                _statisticKeeper.Data.Errors++;
                Core.LogError($"Write to {Name}: {Core.GetErrorMessage(writeRes)}", "write to node failed");
                return;
            }

            while (!currentVersion.IsInterrupted)
            {
                var resultPayload = Streamer.FramePool.Rent();
                var readRes       = currentVersion.Context.Instance.Read(resultPayload);
                if (readRes == ErrorCodes.TryAgainLater)
                {
                    Streamer.FramePool.Back(resultPayload);
                    break;
                }
                else if (Core.IsFailed(readRes))
                {
                    _statisticKeeper.Data.Errors++;
                    Streamer.FramePool.Back(resultPayload);
                    Core.LogError($"Read from {Name}: {Core.GetErrorMessage(writeRes)}", "read from node failed");
                    break;
                }
                else // success
                {
                    _statisticKeeper.Data.OutFrames++; //unsafe, but ok
                    currentVersion.OutputQueue.Enqueue(new Data <Frame>(resultPayload, currentVersion.Version, data.SequenceNumber, PayloadTrace.Create(Name, data.Trace)));
                }
            }
        }