/// <summary> Stops capturing and processing video frames. </summary>
        /// <returns> A Task. </returns>
        public async Task StopProcessingAsync()
        {
            Logger.LogInformation("Stopping capturing tasks");
            foreach (VideoStreamGrabber vs in _streams)
            {
                await vs.StopProcessingAsync().ConfigureAwait(false);

                vs.Dispose();
            }
            _streams.Clear();


            Logger.LogInformation("Stopping merger");
            if (_merger != null)
            {
                await _merger.StopProcessingAsync().ConfigureAwait(false);

                _merger.Dispose();
                _merger = null;
            }

            Logger.LogInformation("Stopping analyzer");
            if (_analyzer != null)
            {
                await _analyzer.StopProcessingAsync().ConfigureAwait(false);

                _analyzer.Dispose();
                _analyzer = null;
            }

            Logger.LogInformation("Stopping result publisher");
            if (_resultPublisher != null)
            {
                await _resultPublisher.StopProcessingAsync(default).ConfigureAwait(false);
        public async Task StartProcessingAll(CancellationToken cancellationToken)
        {
            Logger.LogInformation("Create processing pipeline");
            CreateCapturingChannels();
            var analysisChannel = CreateMultiFrameChannel();
            var outputChannel   = CreateOutputChannel();

            var inputReaders = _capturingChannels.Select(c => c.Reader).ToList();

            _merger = new SyncedMultiChannelMerger <VideoFrame>(
                inputReaders, analysisChannel.Writer, Logger);
            var mergerTask = _merger.ExecuteProcessingAsync(cancellationToken);

            _analyzer = new DnnDetectorChannelTransformer(_detector,
                                                          _detectionOptions.DetectionThreshold,
                                                          analysisChannel.Reader, outputChannel.Writer, _healthCheck, Logger);
            var analyzerTask = _analyzer.ExecuteProcessingAsync(cancellationToken);

            _resultPublisher = new AnalyzedVideoFrameChannelConsumer(
                outputChannel.Reader, _resultProcessors,
                _detectionOptions.ObjectWhiteList,
                Logger);
            var resultPublisherTask = _resultPublisher.ExecuteProcessingAsync(cancellationToken);

            Logger.LogInformation("Start processing pipeline");
            await StartCapturingAllStreamsAsync(cancellationToken).ConfigureAwait(false);

            //Only start the trigger when we know that all capturing streams have started.
            _trigger = new PeriodicTrigger(Logger, _streams);
            _trigger.Start(TimeSpan.FromSeconds(_streams.Count), _analysisInterval);

            await Task.WhenAll(mergerTask, analyzerTask, resultPublisherTask).ConfigureAwait(false);
        }