private int GetLastProducedIndex(StreamSource streamCfg)
        {
            var chunksRoot = Path.Combine(
                _ffmpegCfg.ChunkStorageDir,
                streamCfg.Name);

            if (!Directory.Exists(chunksRoot))
            {
                return(-1);
            }

            var files = Directory.GetFiles(
                chunksRoot,
                "*.ts",
                SearchOption.AllDirectories);

            var mostRecent = files.OrderByDescending(File.GetCreationTime)
                             .FirstOrDefault();

            if (mostRecent == null)
            {
                return(-1);
            }

            File.Delete(mostRecent);
            var mostRecentChunk = ChunkFileLoader.Load(mostRecent);

            return(mostRecentChunk.index);
        }
Example #2
0
        public ChunkFile[] GetNextBatch(ChunksCollectorModelByLast model)
        {
            var streamCfg =
                _streamsConfigs.StreamSources
                .FirstOrDefault(x => x.Name == model.Channel);

            if (streamCfg == null)
            {
                throw new NoSuchChannelException(model.Channel);
            }

            model.channelRoot = Path.Combine(
                _chunkerConfig.ChunkStorageDir,
                streamCfg.Name);
            model.streamSource = streamCfg;

            var chunkTime     = streamCfg.ChunkTime;
            var lastChunk     = ChunkFileLoader.Load(model.LastChunkPath);
            var lastChunkTime =
                TimeTools.SecsToDateWithOffset(lastChunk.timeSeconds);

            var files = GetFilesInsideTimeRange(
                model.channelRoot,
                lastChunkTime.AddSeconds(-chunkTime * 1),
                lastChunkTime.AddSeconds(
                    chunkTime * (model.HlsListSize + safeHlsLstDelta + 1))
                );

            var minTimeS = lastChunk.timeSeconds;
            var chunks   = files
                           .Select(x => ChunkFileLoader.Load(x))
                           .Where(x => x.timeSeconds >= minTimeS - streamCfg.ChunkTime)
                           .OrderBy(x => x.timeSeconds)
                           .Take(model.HlsListSize + safeHlsLstDelta)
                           .ToArray();

            if (chunks.Length != model.HlsListSize + safeHlsLstDelta)
            {
                throw new NoAvailableFilesException(string.Format(
                                                        "{0}/{1} (+{2})",
                                                        (chunks.Length),
                                                        (model.HlsListSize + safeHlsLstDelta),
                                                        safeHlsLstDelta
                                                        ));
            }

            ApplyDisconinuityMarks(chunks, streamCfg.ChunkTime);
            return(chunks.Skip(1).Take(model.HlsListSize).ToArray());
        }
Example #3
0
        public ChunkFile GetClosestChunk(ChunksCollectorModelByTime model)
        {
            var streamCfg =
                _streamsConfigs.StreamSources
                .FirstOrDefault(x => x.Name == model.Channel);

            if (streamCfg == null)
            {
                throw new NoSuchChannelException(model.Channel);
            }

            model.channelRoot = Path.Combine(
                _chunkerConfig.ChunkStorageDir,
                streamCfg.Name);
            model.streamSource = streamCfg;

            var chunkTime = streamCfg.ChunkTime;
            var minTime   = GetMinChunkTimeSpan(model);
            var minTimeS  = minTime
                            .Add(-DateTimeOffset.Now.Offset)
                            .ToUnixTimeSeconds();

            var testTime = TimeTools.SecsToDateWithOffset((int)minTimeS);

            var files = GetFilesInsideTimeRange(
                model.channelRoot,
                minTime.AddSeconds(-2.2 * 1 * chunkTime),
                minTime.AddSeconds(
                    1 * chunkTime * (model.HlsListSize + safeHlsLstDelta + 1))
                );

            var result = files
                         .Select(x => ChunkFileLoader.Load(x))
                         .Where(x => x.timeSeconds > minTimeS - streamCfg.ChunkTime)
                         .OrderBy(x => x.timeSeconds)
                         .FirstOrDefault();

            if (result == null)
            {
                throw new NoAvailableFilesException();
            }

            return(result);
        }
Example #4
0
        /// <summary>
        /// Get the closest possible time to the target time, depending
        /// on the number of chunks and the newest file.
        /// If it's live, then the newest file - (n + 1) * chunkTime will
        /// be returned. Note +1 because the newest is still being created.
        ///
        /// Otherwise, the received time is returned.
        /// </summary>
        private DateTime GetMinChunkTimeSpan(ChunksCollectorModelByTime model)
        {
            var mostRecent =
                Directory.GetFiles(
                    model.channelRoot,
                    "*.ts",
                    SearchOption.AllDirectories
                    ).OrderByDescending(File.GetCreationTime).FirstOrDefault();

            if (mostRecent == null)
            {
                throw new NoAvailableFilesException($"0/{model.HlsListSize}");
            }

            var targetTime =
                model.RequestedTime
                .AddSeconds(
                    -model.streamSource.ChunkTime * model.HlsListSize);

            var newestChunk    = ChunkFileLoader.Load(mostRecent);
            var newestDateTime =
                TimeTools.SecsToDateWithOffset(newestChunk.timeSeconds);

            var totalRequiredSec =
                (model.HlsListSize + safeHlsLstDelta + 1) *
                (model.streamSource.ChunkTime);

            if (targetTime.AddSeconds(totalRequiredSec) > newestDateTime)
            {
                var delta = newestDateTime - targetTime;
                return(newestDateTime.AddSeconds(-totalRequiredSec)
                       .Add(-delta));
            }
            else
            {
                return(targetTime);
            }
        }