Пример #1
0
        private static AdaptationSet Find(Period p, string language, MediaType type, MediaRole role = MediaRole.Main)
        {
            AdaptationSet missingRole = null;

            foreach (var set in p.Sets)
            {
                if (set.Type.Value != type)
                {
                    continue;
                }

                if (language != "und" && set.Lang != language)
                {
                    continue;
                }

                if (set.HasRole(role))
                {
                    return(set);
                }

                if (set.Roles.Length == 0)
                {
                    missingRole = set;
                }
            }
            return(missingRole);
        }
Пример #2
0
 private void GetAvailableStreams(IEnumerable <AdaptationSet> media, AdaptationSet defaultMedia)
 {
     // Not perfect algorithm.
     // check if default media has many representations. if yes, return as available streams
     // list of default media representation + representations from any media from the same group
     // if no, return all available medias
     // TODO(p.galiszewski): add support for: SupplementalProperty schemeIdUri="urn:mpeg:dash:adaptation-set-switching:2016"
     if (defaultMedia.Representations.Length > 1)
     {
         if (defaultMedia.Group.HasValue)
         {
             availableStreams = media.Where(o => o.Group == defaultMedia.Group)
                                .SelectMany(o => o.Representations, (parent, repr) => new DashStream(parent, repr))
                                .OrderByDescending(o => o.Representation.Bandwidth)
                                .ToList();
         }
         else
         {
             availableStreams = defaultMedia.Representations.Select(o => new DashStream(defaultMedia, o))
                                .OrderByDescending(o => o.Representation.Bandwidth)
                                .ToList();
         }
     }
     else
     {
         availableStreams = media.Select(o => new DashStream(o, o.Representations.First()))
                            .OrderByDescending(o => o.Representation.Bandwidth)
                            .ToList();
     }
 }
Пример #3
0
        private static AdaptationSet Find(MpdParser.Period p, string language, MediaType type, MediaRole role = MediaRole.Main)
        {
            AdaptationSet res = null;

            for (int i = 0; i < p.Sets.Length; i++)
            {
                if (p.Sets[i].Type.Value != type)
                {
                    continue;
                }

                if (language != null)
                {
                    if (p.Sets[i].Lang != language)
                    {
                        continue;
                    }
                }

                if (p.Sets[i].HasRole(role))
                {
                    res = p.Sets[i];
                    break;
                }

                if (p.Sets[i].Roles.Length == 0)
                {
                    res = p.Sets[i];
                    break;
                }
            }

            return(res);
        }
Пример #4
0
        /// <summary>
        /// Performs on-disk post processing of the generated MPD file.
        /// Subtitles are added, useless tags removed, etc.
        /// </summary>
        private MPD PostProcessMpdFile(string filepath, IEnumerable <SubtitleStreamCommand> subtitles)
        {
            MPD.TryLoadFromFile(filepath, out MPD mpd, out Exception ex);
            mpd.ProgramInformation = new ProgramInformation()
            {
                Title = $"DEnc",
                MoreInformationURL = "https://github.com/bloomtom/DEnc"
            };

            // Get the highest used representation ID so we can increment it for new IDs.
            int.TryParse(mpd.Period.Max(x => x.AdaptationSet.Max(y => y.Representation.Max(z => z.Id))), out int representationId);
            representationId++;

            foreach (var period in mpd.Period)
            {
                // Add subtitles to this period.
                foreach (var sub in subtitles)
                {
                    AdaptationSet subtitleSet = GenerateSubtitleAdaptationSet(representationId, sub, out int nextRepresentationId);
                    if (subtitleSet != null)
                    {
                        period.AdaptationSet.Add(subtitleSet);
                        representationId = nextRepresentationId;
                    }
                }
            }

            mpd.SaveToFile(filepath);
            return(mpd);
        }
Пример #5
0
 private void ParseDrms(AdaptationSet newMedia)
 {
     foreach (var descriptor in newMedia.ContentProtections)
     {
         var schemeIdUri = descriptor.SchemeIdUri;
         if (CencUtils.SupportsSchemeIdUri(schemeIdUri))
         {
             ParseCencScheme(descriptor, schemeIdUri);
         }
         else if (string.Equals(schemeIdUri, "http://youtube.com/drm/2012/10/10",
                                StringComparison.CurrentCultureIgnoreCase))
         {
             ParseYoutubeScheme(descriptor);
         }
     }
 }
Пример #6
0
        private static AdaptationSet GetDefaultMedia(ICollection <AdaptationSet> medias)
        {
            AdaptationSet media = null;

            if (medias.Count == 1)
            {
                media = medias.First();
            }
            if (media == null)
            {
                media = medias.FirstOrDefault(o => o.HasRole(MediaRole.Main));
            }
            if (media == null)
            {
                media = medias.FirstOrDefault(o => o.Lang == "en");
            }

            return(media ?? medias.FirstOrDefault());
        }
Пример #7
0
        public async Task DEBUG_MpdParser()
        {
            LoggerBase CreateLogger(string channel, LogLevel level) => new DummyLogger(channel, level);

            LoggerManager.Configure(CreateLogger);
            //string url = "http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)";
            //string url = "http://dash.edgesuite.net/envivio/dashpr/clear/Manifest.mpd";
            string    url = null;
            WebClient wc  = new WebClient();
            String    xml;
            Document  doc;

            try
            {
                xml = wc.DownloadString(url);

                doc = await Document.FromText(xml, url);

                foreach (var period in doc.Periods)
                {
                    AdaptationSet audio = Find(period, "en", MediaType.Audio) ??
                                          Find(period, "und", MediaType.Audio);

                    AdaptationSet video = Find(period, "en", MediaType.Video) ??
                                          Find(period, "und", MediaType.Video);

                    if (audio != null && video != null)
                    {
                        return;
                    }
                }
            }
            catch (Exception ex)
            {
                return;
            }

            return;
        }
Пример #8
0
 public DashStream(AdaptationSet media, Representation representation)
 {
     Media          = media;
     Representation = representation;
 }
Пример #9
0
        private static Manifest LoadManifest(string manifestString, IFeedbackSink feedback)
        {
            var ns = new XmlNamespaceManager(new NameTable());

            ns.AddNamespace("mpd", MpdNamespace);

            var xml = XDocument.Load(new StringReader(manifestString));

            // Load <MPD>.

            var manifest = new Manifest
            {
                Document   = xml,
                Namespaces = ns,

                AvailabilityStartTime = xml.Root.GetAttributeAsDateTimeOffset("availabilityStartTime"),
                PublishTime           = xml.Root.GetAttributeAsDateTimeOffset("publishTime"),

                PlaybackWindowLength    = xml.Root.GetAttributeAsTimeSpan("timeShiftBufferDepth"),
                ManifestRefreshInterval = xml.Root.GetAttributeAsTimeSpan("minimumUpdatePeriod")
            };

            if (xml.Root.Attribute("type")?.Value != "dynamic")
            {
                throw new NotSupportedException("MPD@type must be 'dynamic'");
            }

            if (manifest.PublishTime.Year < 2018)
            {
                throw new NotSupportedException("MPD@availabilityStartTime must be at least in 2018 because this validator does not yet implement leap second processing.");
            }

            foreach (var clockSyncElement in xml.Root.Elements(UtcTimingName))
            {
                switch (clockSyncElement.Attribute("schemeIdUri").Value)
                {
                case "urn:mpeg:dash:utc:http-iso:2014":
                    manifest.TimeSources.Add(new HttpIsoTimeSource(new Uri(clockSyncElement.Attribute("value").Value, UriKind.Absolute)));
                    break;

                case "urn:mpeg:dash:utc:http-head:2014":
                    manifest.TimeSources.Add(new HttpHeadTimeSource(new Uri(clockSyncElement.Attribute("value").Value, UriKind.Absolute)));
                    break;

                case "urn:mpeg:dash:utc:direct:2014":
                    manifest.TimeSources.Add(new DirectTimeSource(clockSyncElement.Attribute("value").Value));
                    break;

                default:
                    feedback.WillSkipSomeData("Ignoring unsupported clock synchromization method: " + clockSyncElement.Attribute("schemeIdUri").Value);
                    break;
                }
            }

            // Load <Period>.

            foreach (var periodElement in xml.Root.Elements(PeriodName))
            {
                var period = new Period
                {
                    Element  = periodElement,
                    Manifest = manifest,

                    Id = periodElement.Attribute("id")?.Value,

                    StartOffsetFromAst = periodElement.GetAttributeAsTimeSpan("start")
                };

                manifest.Periods.Add(period);
            }

            // Calculate period durations.
            for (var i = 0; i < manifest.Periods.Count; i++)
            {
                if (i == manifest.Periods.Count - 1)
                {
                    // Last period may have explicit duration in manifest. Otherwise infinite duration.
                    if (manifest.Periods[i].Element.Attribute("duration") != null)
                    {
                        manifest.Periods[i].Duration = manifest.Periods[i].Element.GetAttributeAsTimeSpan("duration");
                    }
                }
                else
                {
                    // If it is not the last, we always calculate (even if explicit duration is set).
                    manifest.Periods[i].Duration = manifest.Periods[i + 1].Start - manifest.Periods[i].Start;
                }
            }

            // Load <AdaptationSet>.

            foreach (var period in manifest.Periods)
            {
                foreach (var setElement in period.Element.Elements(AdaptationSetName))
                {
                    var set = new AdaptationSet
                    {
                        Element = setElement,
                        Period  = period,

                        MimeType = setElement.Attribute("mimeType")?.Value,

                        AlignedSegments = setElement.Attribute("segmentAlignment")?.Value == "true"
                    };

                    var templateElement = setElement.Element(SegmentTemplateName);

                    if (templateElement != null)
                    {
                        set.SegmentTemplate = LoadSegmentTemplate(templateElement);
                        set.SegmentTemplate.AdaptationSet = set;
                    }

                    period.AdaptationSets.Add(set);
                }
            }

            // Load <Representation>.

            foreach (var set in manifest.Periods.SelectMany(p => p.AdaptationSets))
            {
                foreach (var repElement in set.Element.Elements(RepresentationName))
                {
                    var rep = new Representation
                    {
                        Element       = repElement,
                        AdaptationSet = set,

                        Id = repElement.Attribute("id")?.Value
                    };

                    var templateElement = repElement.Element(SegmentTemplateName);

                    if (templateElement != null)
                    {
                        if (set.SegmentTemplate != null)
                        {
                            throw new NotSupportedException("This validator only supports validating manifests where SegmentTemplate is under AdaptationSet or Representation but not both together for the same Representation.");
                        }

                        rep.SegmentTemplate = LoadSegmentTemplate(templateElement);
                        rep.SegmentTemplate.Representation = rep;
                    }
                    else
                    {
                        if (set.SegmentTemplate == null)
                        {
                            throw new NotSupportedException("This validator requires a SegmentTemplate under one of the following: AdaptationSet or Representation.");
                        }
                    }

                    set.Representations.Add(rep);
                }
            }

            return(manifest);
        }