コード例 #1
0
ファイル: HlsProgramManager.cs プロジェクト: henricj/phonesm
        public async Task<IDictionary<long, Program>> LoadAsync(ContentType contentType, CancellationToken cancellationToken)
        {
            var playlists = Playlists;

            foreach (var playlist in playlists)
            {
                try
                {
                    var parser = new M3U8Parser();

                    if (null != _playlistWebReader)
                        _playlistWebReader.Dispose();

                    _playlistWebReader = _webReaderManager.CreateReader(playlist, ContentKind.Playlist, contentType: contentType);

                    var actualPlaylist = await parser.ParseAsync(_playlistWebReader, _retryManager, playlist, cancellationToken)
                        .ConfigureAwait(false);

                    return await LoadAsync(_playlistWebReader, parser, contentType, cancellationToken).ConfigureAwait(false);
                }
                catch (StatusCodeWebException e)
                {
                    // This one didn't work, so try the next playlist url.
                    Debug.WriteLine("HlsProgramManager.LoadAsync: " + e.Message);
                }
            }

            return NoPrograms;
        }
コード例 #2
0
 public static void Parse(this M3U8Parser parser, Uri baseUrl, Stream stream, Encoding encoding = null)
 {
     if (null == encoding)
     {
         encoding = UriExtensions.HasExtension(baseUrl, ".m3u") ? SmEncodings.Latin1 : Encoding.UTF8;
     }
     using (StreamReader streamReader = new StreamReader(stream, encoding))
         M3U8ParserExtensions.Parse(parser, baseUrl, (TextReader)streamReader);
 }
コード例 #3
0
        public static Task <Uri> ParseAsync(this M3U8Parser parser, IWebReader webReader, IRetryManager retryManager, Uri playlist, CancellationToken cancellationToken)
        {
            IRetry retry = RetryManagerExtensions.CreateWebRetry(retryManager, 2, 250);

            return(retry.CallAsync <Uri>((Func <Task <Uri> >)(() => WebReaderExtensions.ReadStreamAsync <Uri>(webReader, playlist, retry, (Func <Uri, Stream, Uri>)((actualPlaylist, stream) =>
            {
                M3U8ParserExtensions.Parse(parser, actualPlaylist, stream, (Encoding)null);
                return actualPlaylist;
            }), cancellationToken)), cancellationToken));
        }
コード例 #4
0
ファイル: PlaylistDefaults.cs プロジェクト: henricj/phonesm
        /// <summary>
        ///     A playlist is dynamic if it does not have an #EXT-X-ENDLIST tag and every segment has an #EXTINF with a valid
        ///     duration.
        /// </summary>
        /// <param name="parser"></param>
        /// <returns></returns>
        public static bool IsDynamicPlayist(M3U8Parser parser)
        {
            if (null != parser.GlobalTags.Tag(M3U8Tags.ExtXEndList))
                return false;

            var validDuration = parser.Playlist.All(
                p =>
                {
                    var extInf = M3U8Tags.ExtXInf.Find(p.Tags);

                    return null != extInf && extInf.Duration >= 0;
                });

            return validDuration;
        }
コード例 #5
0
ファイル: HlsStreamSegments.cs プロジェクト: henricj/phonesm
        public HlsStreamSegments(M3U8Parser parser, IWebReader webReader, IRetryManager retryManager, IPlatformServices platformServices)
        {
            if (null == parser)
                throw new ArgumentNullException(nameof(parser));
            if (null == webReader)
                throw new ArgumentNullException(nameof(webReader));
            if (null == retryManager)
                throw new ArgumentNullException(nameof(retryManager));
            if (null == platformServices)
                throw new ArgumentNullException(nameof(platformServices));

            _parser = parser;
            _webReader = webReader;
            _retryManager = retryManager;
            _platformServices = platformServices;

            _mediaSequence = M3U8Tags.ExtXMediaSequence.GetValue<long>(parser.GlobalTags);
        }
コード例 #6
0
ファイル: Program.cs プロジェクト: henricj/phonesm
        public IDictionary<long, Program> Load(Uri playlist)
        {
            using (var f = new WebClient().OpenRead(playlist))
            {
                var parser = new M3U8Parser();

                parser.Parse(playlist, f);

                var audioStreams = new Dictionary<string, MediaGroup>();

                foreach (var gt in parser.GlobalTags)
                {
                    if (M3U8Tags.ExtXMedia == gt.Tag)
                    {
                        try
                        {
                            var audioAttribute = gt.Attribute(ExtMediaSupport.AttrType, "AUDIO");

                            if (null != audioAttribute)
                            {
                                var group = gt.Attribute(ExtMediaSupport.AttrGroupId).Value;

                                var urlAttribute = gt.AttributeObject(ExtMediaSupport.AttrUri);

                                Uri playlistUrl = null;

                                if (null != urlAttribute)
                                    playlistUrl = new Uri(playlist, new Uri(urlAttribute, UriKind.RelativeOrAbsolute));

                                var audioStream = new PlaylistSubStream
                                                  {
                                                      Name = group,
                                                      Playlist = playlistUrl
                                                  };

                                MediaGroup mediaGroup;
                                if (!audioStreams.TryGetValue(group, out mediaGroup))
                                {
                                    mediaGroup = new MediaGroup { Default = audioStream };

                                    audioStreams[group] = mediaGroup;
                                }

                                var isDefault = 0 == string.CompareOrdinal("YES", gt.Attribute(ExtMediaSupport.AttrDefault).Value);

                                if (isDefault)
                                    mediaGroup.Default = audioStream;

                                var name = gt.Attribute(ExtMediaSupport.AttrName).Value;

                                mediaGroup.Streams[name] = audioStream;
                            }
                        }
                        catch (NullReferenceException)
                        {
                            // DynamicObject isn't welcome on the phone or this would be a binding exception.
                        }
                    }
                }

                var programs = new Dictionary<long, Program>();
                SimpleSubProgram simpleSubProgram = null;

                foreach (var p in parser.Playlist)
                {
                    var streamInf = p.Tags.FirstOrDefault(t => M3U8Tags.ExtXStreamInf == t.Tag);

                    var programId = long.MinValue;
                    MediaGroup audioGroup = null;

                    if (null != streamInf)
                    {
                        var programIdAttribute = streamInf.Attribute(ExtStreamInfSupport.AttrProgramId);

                        if (null != programIdAttribute)
                            programId = programIdAttribute.Value;

                        var audioAttribute = streamInf.AttributeObject(ExtStreamInfSupport.AttrAudio);

                        if (null != audioAttribute)
                            audioStreams.TryGetValue(audioAttribute, out audioGroup);

                        var subProgram = new PlaylistSubProgram
                                         {
                                             Bandwidth = streamInf.Attribute(ExtStreamInfSupport.AttrBandwidth).Value,
                                             Playlist = new Uri(playlist, new Uri(p.Uri, UriKind.RelativeOrAbsolute)),
                                             Audio = audioGroup
                                         };

                        Program program;

                        if (!programs.TryGetValue(programId, out program))
                        {
                            program = new Program { ProgramId = programId };

                            programs[programId] = program;
                        }

                        program.SubPrograms.Add(subProgram);
                    }
                    else
                    {
                        var extInf = (ExtinfTagInstance)p.Tags.FirstOrDefault(t => M3U8Tags.ExtXInf == t.Tag);

                        if (null != extInf)
                        {
                            if (null == simpleSubProgram)
                            {
                                simpleSubProgram = new SimpleSubProgram();

                                var program = new Program { ProgramId = long.MinValue };

                                program.SubPrograms.Add(simpleSubProgram);

                                programs[program.ProgramId] = program;
                            }

                            simpleSubProgram.Segments.Add(new XSegment
                                                          {
                                                              Url = new Uri(playlist, new Uri(p.Uri, UriKind.RelativeOrAbsolute)),
                                                              Duration = TimeSpan.FromSeconds((double)extInf.Duration)
                                                          });
                        }
                    }
                }

                return programs;
            }
        }
コード例 #7
0
ファイル: Program.cs プロジェクト: henricj/phonesm
        public override IEnumerable<XSegment> GetPlaylist(SubStream audio = null)
        {
            var playlist = Playlist;

            if (null == playlist)
                yield break;

            var parser = new M3U8Parser();

            using (var f = new WebClient().OpenRead(playlist))
            {
                parser.Parse(playlist, f);

                Uri previous = null;

                foreach (var p in parser.Playlist)
                {
                    var url = new Uri(playlist, new Uri(p.Uri, UriKind.RelativeOrAbsolute));

                    if (null != previous && url == previous)
                        continue;

                    yield return new XSegment { Url = url };

                    previous = url;
                }
            }
        }
コード例 #8
0
 public IHlsStreamSegments Create(M3U8Parser parser, IWebReader webReader)
 {
     return new HlsStreamSegments(parser, webReader, _retryManager, _platformServices);
 }
コード例 #9
0
ファイル: HlsSegmentsFactory.cs プロジェクト: henricj/phonesm
        public Task<ICollection<ISegment>> CreateSegmentsAsync(M3U8Parser parser, IWebReader webReader, CancellationToken cancellationToken)
        {
            var streamSegments = _streamSegmentsFactory.Create(parser, webReader);

            return streamSegments.CreateSegmentsAsync(cancellationToken);
        }
コード例 #10
0
ファイル: HlsProgramStream.cs プロジェクト: henricj/phonesm
        async Task<M3U8Parser> FetchPlaylistAsync(CancellationToken cancellationToken)
        {
            var urls = Urls;

            if (null == urls || urls.Count < 1)
                return null;

            foreach (var playlist in urls)
            {
                UpdateSubPlaylistCache(playlist);

                cancellationToken.ThrowIfCancellationRequested();

                WebResponse webResponse = null;

                if (null == StreamMetadata)
                    webResponse = new WebResponse();

                var parsedPlaylist = await _subPlaylistCache.ReadAsync(
                    (actualUri, bytes) =>
                    {
                        cancellationToken.ThrowIfCancellationRequested();

                        if (bytes.Length < 1)
                            return null;

                        var parser = new M3U8Parser();

                        using (var ms = new MemoryStream(bytes))
                        {
                            parser.Parse(actualUri, ms);
                        }

                        return parser;
                    }, cancellationToken, webResponse)
                    .ConfigureAwait(false);


                if (null != parsedPlaylist)
                {
                    if (null != webResponse)
                        StreamMetadata = _webMetadataFactory.CreateStreamMetadata(webResponse);

                    return parsedPlaylist;
                }
            }

            return null;
        }
コード例 #11
0
ファイル: HlsProgramStream.cs プロジェクト: henricj/phonesm
 async Task UpdateAsync(M3U8Parser parser, CancellationToken cancellationToken)
 {
     _segments = await _segmentsFactory.CreateSegmentsAsync(parser, _subPlaylistCache.WebReader, cancellationToken).ConfigureAwait(false);
     _isDynamicPlaylist = HlsPlaylistSettings.Parameters.IsDynamicPlaylist(parser);
     _actualUrl = parser.BaseUrl;
 }
コード例 #12
0
ファイル: HlsStreamSegments.cs プロジェクト: henricj/phonesm
        ISegment CreateStreamSegment(M3U8Parser.M3U8Uri uri, CancellationToken cancellationToken)
        {
            var url = _parser.ResolveUrl(uri.Uri);

            var segment = new SubStreamSegment(url, _parser.BaseUrl);

            if (_mediaSequence.HasValue)
                segment.MediaSequence = _mediaSequence + _segmentIndex;

            ++_segmentIndex;

            var tags = uri.Tags;

            if (null == tags || 0 == tags.Length)
                return segment;

            var info = M3U8Tags.ExtXInf.Find(tags);

            if (null != info)
                segment.Duration = TimeSpan.FromSeconds((double)info.Duration);

            var byteRange = M3U8Tags.ExtXByteRange.Find(tags);
            if (null != byteRange)
                HandleByteRange(segment, byteRange);

            var extKeys = M3U8Tags.ExtXKey.FindAll(tags);

            if (null != extKeys)
                HandleKey(segment, extKeys, cancellationToken);

            return segment;
        }
コード例 #13
0
ファイル: HlsProgramManager.cs プロジェクト: henricj/phonesm
        async Task<IDictionary<long, Program>> LoadAsync(IWebReader webReader, M3U8Parser parser, ContentType contentType, CancellationToken cancellationToken)
        {
            var audioStreams = new Dictionary<string, MediaGroup>();

            foreach (var gt in parser.GlobalTags)
            {
                if (M3U8Tags.ExtXMedia == gt.Tag)
                {
                    try
                    {
                        var audioAttribute = gt.Attribute(ExtMediaSupport.AttrType, "AUDIO");

                        if (null != audioAttribute)
                            AddMedia(parser.BaseUrl, gt, audioStreams);
                    }
                    catch (NullReferenceException)
                    {
                        // DynamicObject isn't welcome on the phone or this would be a binding exception.
                    }
                }
            }

            var programs = new Dictionary<long, Program>();
            var hasSegments = false;

            foreach (var p in parser.Playlist)
            {
                if (null == p.Tags || p.Tags.Length < 1)
                {
                    hasSegments = true;
                    continue;
                }

                var streamInf = M3U8Tags.ExtXStreamInf.Find(p.Tags);

                var programId = long.MinValue;
                MediaGroup audioGroup = null;

                if (null != streamInf)
                {
                    var programIdAttribute = streamInf.Attribute(ExtStreamInfSupport.AttrProgramId);

                    if (null != programIdAttribute)
                        programId = programIdAttribute.Value;

                    var audioAttribute = streamInf.AttributeObject(ExtStreamInfSupport.AttrAudio);

                    if (null != audioAttribute)
                        audioStreams.TryGetValue(audioAttribute, out audioGroup);

                    var playlistUrl = parser.ResolveUrl(p.Uri);

                    var bandwidth = streamInf.Attribute(ExtStreamInfSupport.AttrBandwidth);

                    var resolution = streamInf.AttributeInstance<ResolutionAttributeInstance>(ExtStreamInfSupport.AttrResolution);

                    var programUrl = parser.BaseUrl;

                    var program = GetProgram(programs, programId, programUrl);

                    var hlsProgramStream = _programStreamFactory.Create(new[] { playlistUrl }, webReader, ContentType, StreamContentType);

                    var subProgram = new PlaylistSubProgram(program, hlsProgramStream)
                    {
                        Bandwidth = null == bandwidth ? 0 : bandwidth.Value,
                        Playlist = playlistUrl,
                        AudioGroup = audioGroup
                    };

                    if (null != resolution)
                    {
                        subProgram.Width = resolution.X;
                        subProgram.Height = resolution.Y;
                    }

                    program.SubPrograms.Add(subProgram);
                }
                else
                    hasSegments = true;
            }

            if (hasSegments)
            {
                var program = GetProgram(programs, long.MinValue, parser.BaseUrl);

                var hlsProgramStream = _programStreamFactory.Create(new[] { webReader.RequestUri }, webReader, ContentType, StreamContentType);

                await hlsProgramStream.SetParserAsync(parser, cancellationToken).ConfigureAwait(false);

                var subProgram = new PlaylistSubProgram(program, hlsProgramStream);

                program.SubPrograms.Add(subProgram);
            }

            return programs;
        }
コード例 #14
0
 public static void Parse(this M3U8Parser parser, Uri baseUrl, TextReader textReader)
 {
     parser.Parse(baseUrl, M3U8ParserExtensions.GetExtendedLines(textReader));
 }
コード例 #15
0
ファイル: Program.cs プロジェクト: henricj/phonesm
        static void Main(string[] args)
        {
            if (args.Length < 1)
                return;

            try
            {
                using (var programManager = new ProgramManager())
                {
                    foreach (var arg in args)
                    {
                        var programs = programManager.Load(new Uri(arg));

                        foreach (var program in programs.Values)
                        {
                            foreach (var subProgram in program.SubPrograms)
                            {
                                foreach (var segment in subProgram.GetPlaylist())
                                {
                                    Debug.WriteLine("Segment: {0}", segment.Url);
                                }
                            }
                        }

                        Console.WriteLine("Reading {0}", arg);

                        var url = new Uri(arg);

                        using (var f = new WebClient().OpenRead(url))
                        {
                            var parser = new M3U8Parser();

                            parser.Parse(url, f);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }
コード例 #16
0
ファイル: HlsProgramStream.cs プロジェクト: henricj/phonesm
        public Task SetParserAsync(M3U8Parser parser, CancellationToken cancellationToken)
        {
            UpdateSubPlaylistCache(parser.BaseUrl);

            return UpdateAsync(parser, cancellationToken);
        }
コード例 #17
0
 public static Uri ResolveUrl(this M3U8Parser parser, string url)
 {
     return(parser.ResolveUrl(new Uri(url, UriKind.RelativeOrAbsolute)));
 }