private void AddPreviousGap(double gapDuration, Stream gapManifestStream, CompositeManifestInfo compositeManifestInfo) { if (gapDuration == 0) { return; } const double Timescale = 10000000.0; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(gapManifestStream); gapManifestStream.Seek(0, SeekOrigin.Begin); double gapVideoCount = gapDuration / (parser.ManifestInfo.ManifestDuration / Timescale); int completeVideos = (int)gapVideoCount; double partialVideoProportion = gapVideoCount - (int)gapVideoCount; ulong clipEnd = parser.ManifestInfo.ManifestDuration; var customAttributes = new Dictionary <string, string> { { "CMSId", this.gapCmsId }, { "AzureId", this.gapAzureId } }; for (int i = 0; i < completeVideos; i++) { compositeManifestInfo.AddClip(this.gapUri, 0, clipEnd, customAttributes, true, parser.ManifestInfo); } clipEnd = (ulong)(clipEnd * partialVideoProportion); if (clipEnd != 0) { compositeManifestInfo.AddClip(this.gapUri, 0, clipEnd, customAttributes, true, parser.ManifestInfo); } }
private static void WritePlayByPlay(XmlWriter writer, CompositeManifestInfo manifestInfo) { if (manifestInfo.PlayByPlayEvents.Count > 0) { StreamInfo streamInfo = WriteCompositeManifestStandardStreamIndex(manifestInfo.PlayByPlayDataStreamName, manifestInfo.PlayByPlayEvents.Count); for (int i = 0; i < manifestInfo.PlayByPlayEvents.Count; i++) { PlayByPlay pbp = manifestInfo.PlayByPlayEvents[i]; StringBuilder output = new StringBuilder(); XmlWriter tempWriter = CreateWriter(output, true, true); if (tempWriter != null) { tempWriter.WriteStartElement("InStreamEnvelope"); tempWriter.WriteAttributeString("Id", pbp.ID.ToString()); tempWriter.WriteAttributeString("Action", "Add"); tempWriter.WriteAttributeString("TargetID", string.Empty); tempWriter.WriteAttributeString("Priority", "1"); tempWriter.WriteStartElement("PlayByPlay"); tempWriter.WriteAttributeString("ID", pbp.ID.ToString()); tempWriter.WriteAttributeString("Time", pbp.Time.ToString(CultureInfo.InvariantCulture)); tempWriter.WriteAttributeString("IsTimelineMarker", "True"); tempWriter.WriteAttributeString("IsNavigable", "True"); tempWriter.WriteAttributeString("EditorialType", string.Empty); tempWriter.WriteAttributeString("Type", string.Empty); tempWriter.WriteCData(pbp.Text); tempWriter.WriteEndElement(); tempWriter.Close(); byte[] envelopeBytes = Encoding.UTF8.GetBytes(output.ToString()); string encodedEnvelope = Convert.ToBase64String(envelopeBytes); ulong?duration = null; if (i == manifestInfo.PlayByPlayEvents.Count - 1) { duration = 10000000; } Chunk chunk = new Chunk(null, (ulong)pbp.Time, duration, encodedEnvelope); streamInfo.Chunks.Add(chunk); } } WriteStreamIndex(writer, streamInfo, true); } }
private static void WriteAdOpportunities(XmlWriter writer, CompositeManifestInfo manifestInfo) { if (manifestInfo.AdOpportunities.Count > 0) { StreamInfo streamInfo = WriteCompositeManifestStandardStreamIndex(manifestInfo.AdsDataStreamName, manifestInfo.AdOpportunities.Count); for (int i = 0; i < manifestInfo.AdOpportunities.Count; i++) { AdOpportunity adOpportunity = manifestInfo.AdOpportunities[i]; StringBuilder output = new StringBuilder(); XmlWriter tempWriter = CreateWriter(output, true, true); if (tempWriter != null) { tempWriter.WriteStartElement("InStreamEnvelope"); tempWriter.WriteAttributeString("Id", adOpportunity.ID.ToString()); tempWriter.WriteAttributeString("Action", "Add"); tempWriter.WriteAttributeString("TargetID", string.Empty); tempWriter.WriteAttributeString("Priority", "1"); tempWriter.WriteStartElement("AdOpportunity"); tempWriter.WriteAttributeString("ID", adOpportunity.ID.ToString()); tempWriter.WriteAttributeString("Time", adOpportunity.Time.ToString(CultureInfo.InvariantCulture)); tempWriter.WriteAttributeString("TemplateType", adOpportunity.TemplateType); tempWriter.WriteEndElement(); tempWriter.Close(); byte[] envelopeBytes = Encoding.UTF8.GetBytes(output.ToString()); string encodedEnvelope = Convert.ToBase64String(envelopeBytes); ulong?duration = null; if (i == manifestInfo.AdOpportunities.Count - 1) { duration = 10000000; } Chunk chunk = new Chunk(null, (ulong)adOpportunity.Time, duration, encodedEnvelope); streamInfo.Chunks.Add(chunk); } } WriteStreamIndex(writer, streamInfo, true); } }
private void AddRubberBandingPoints(TimelineElement element, CompositeManifestInfo compositeManifestInfo) { const ulong Timescale = 10000000; List <Point> elementVolumeCollection = element.VolumeNodeCollection; foreach (Point point in elementVolumeCollection) { double volume = 1 - point.Y; long frames = (long)point.X; double totalSeconds = TimeCode.FromFrames(frames, this.sequenceRegistry.CurrentSequenceModel.CurrentPosition.FrameRate).TotalSeconds + element.Position.TotalSeconds; long ticks = (long)(totalSeconds * Timescale); compositeManifestInfo.AddRubberBandingPoint(ticks, volume); } }
private void AddTransitions(TimelineElement shot, CompositeManifestInfo compositeManifestInfo) { const double Timescale = 10000000.0; if (!(shot.Asset is VideoAsset) && !(shot.Asset is AudioAsset)) { return; } AssetType assetType = (shot.Asset is VideoAsset) ? AssetType.Video : AssetType.Audio; ulong position = (ulong)(shot.Position.TotalSeconds * Timescale); AddTransition(SmoothStreamingManifestGenerator.Models.TransitionType.FadeIn, assetType, position, shot.InTransition.Duration, compositeManifestInfo); position = (ulong)((shot.Position.TotalSeconds + shot.Duration.TotalSeconds - shot.OutTransition.Duration) * Timescale); AddTransition(SmoothStreamingManifestGenerator.Models.TransitionType.FadeOut, assetType, position, shot.OutTransition.Duration, compositeManifestInfo); }
private void AddRubberBandingPoints(Shot shot, CompositeManifestInfo compositeManifestInfo) { const ulong Timescale = 10000000; List <VolumeLevelNode> volumeNodes = shot.VolumeNodeCollection; foreach (VolumeLevelNode volumeNode in volumeNodes) { double volume = volumeNode.Volume; long frames = (long)volumeNode.Position; SmpteFrameRate frameRate; SmpteFrameRate.TryParse(this.project.SmpteFrameRate, true, out frameRate); double totalSeconds = TimeCode.FromFrames(frames, frameRate).TotalSeconds + shot.TrackAnchor.MarkIn.Value; long ticks = (long)(totalSeconds * Timescale); compositeManifestInfo.AddRubberBandingPoint(ticks, volume); } }
private void AddTransitions(Shot shot, CompositeManifestInfo compositeManifestInfo) { const double Timescale = 10000000.0; SubClipItem subclipItem = shot.Source as SubClipItem; Item itemForTransition = subclipItem != null ? subclipItem.RelatedItem : shot.Source; if (!(itemForTransition is VideoItem) && !(itemForTransition is AudioItem)) { return; } AssetType assetType = (itemForTransition is VideoItem) ? AssetType.Video : AssetType.Audio; ulong position = (ulong)(shot.TrackAnchor.MarkIn * Timescale); compositeManifestInfo.AddTransition(SmoothStreamingManifestGenerator.Models.TransitionType.FadeIn, assetType, position, shot.InTransition.Duration); position = (ulong)((shot.TrackAnchor.MarkIn + (shot.SourceAnchor.MarkOut - shot.SourceAnchor.MarkIn) - shot.OutTransition.Duration) * Timescale); compositeManifestInfo.AddTransition(SmoothStreamingManifestGenerator.Models.TransitionType.FadeOut, assetType, position, shot.OutTransition.Duration); }
public string GetSubClipManifest(Uri manifestUri, double markIn, double markOut) { string manifest = null; DownloaderManager downloaderManager = new DownloaderManager(); Stream manifestStream = downloaderManager.DownloadManifest(manifestUri, true, null); if (manifestStream != null) { SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(manifestStream); SmoothStreamingManifestWriter writer = new SmoothStreamingManifestWriter(); CompositeManifestInfo compositeManifestInfo = new CompositeManifestInfo(parser.ManifestInfo.MajorVersion, parser.ManifestInfo.MinorVersion); compositeManifestInfo.AddClip(manifestUri, (ulong)markIn, (ulong)markOut, parser.ManifestInfo); manifest = writer.GenerateCompositeManifest(compositeManifestInfo, false); } return manifest; }
private void AddOverlay(TimelineElement shot, CompositeManifestInfo compositeManifestInfo) { var overlayAsset = shot.Asset as OverlayAsset; if (overlayAsset != null) { var dict = new Dictionary <string, object>(); overlayAsset.Metadata.ForEach(mf => dict.Add(mf.Name, mf.Value)); const double Timescale = 10000000.0; compositeManifestInfo.AddOverlay( overlayAsset.Title, overlayAsset.PositionX, overlayAsset.PositionY, overlayAsset.Height, overlayAsset.Width, dict, overlayAsset.XamlResource, (ulong)(shot.Position.TotalSeconds * Timescale), (ulong)((shot.Position.TotalSeconds + shot.Duration.TotalSeconds) * Timescale)); } }
private void AddOverlay(Shot shot, CompositeManifestInfo compositeManifestInfo) { var overlayItem = shot.Source as OverlayItem; if (overlayItem != null) { var dict = new Dictionary <string, object>(); overlayItem.Metadata.ForEach(mf => dict.Add(mf.Name, mf.Value)); const double Timescale = 10000000.0; compositeManifestInfo.AddOverlay( overlayItem.Title, overlayItem.X, overlayItem.Y, overlayItem.Height, overlayItem.Width, dict, overlayItem.XamlTemplate, (ulong)((shot.SourceAnchor.MarkIn + shot.TrackAnchor.MarkIn) * Timescale), (ulong)(((shot.SourceAnchor.MarkIn + shot.TrackAnchor.MarkIn) + (shot.SourceAnchor.MarkOut - shot.SourceAnchor.MarkIn)) * Timescale)); } }
/// <summary> /// Generates a composite manifest based on the given <see cref="CompositeManifestInfo"/>. /// </summary> /// <param name="manifestInfo">The composite manifest info that contains all the information about the manifest go generate.</param> /// <param name="writeSourceDataStreams">Defines whether if the composite manifest should include the source data streams.</param> /// <param name="compressManifest">Defines whether if the composite manifest should be compressed.</param> /// <returns>The generated Smooth Streaming composite manifest.</returns> public string GenerateCompositeManifest(CompositeManifestInfo manifestInfo, bool writeSourceDataStreams, bool compressManifest) { StringBuilder output = new StringBuilder(); XmlWriter writer = CreateWriter(output, false, true); if (writer != null) { writer.WriteProcessingInstruction("xml", "version=\"1.0\""); writer.WriteStartElement("SmoothStreamingMedia"); WriteHeader(writer, manifestInfo, compressManifest); foreach (Clip clip in manifestInfo.Clips) { WriteClip(writer, clip, compressManifest); } if (writeSourceDataStreams) { foreach (StreamInfo streamInfo in manifestInfo.Streams) { WriteClipSparseStreamIndex(writer, streamInfo, manifestInfo.MajorVersion); } } WriteAdOpportunities(writer, manifestInfo); WritePlayByPlay(writer, manifestInfo); writer.WriteEndElement(); writer.Close(); } return(output.ToString()); }
public void ShouldMaintainFrameAccuracy2WhenGeneratingCompositeSmoothStreamingManifestVersion2() { string expectedManifest; using (var expectedManifestStream = new FileStream(@".\Content\frame2.csm", FileMode.Open, FileAccess.Read)) { using (StreamReader reader = new StreamReader(expectedManifestStream)) { expectedManifest = reader.ReadToEnd(); } } var manifestStream = new FileStream(@".\Content\frame2.xml", FileMode.Open, FileAccess.Read); var manifestParser = new SmoothStreamingManifestParser(manifestStream); var manifestWriter = new SmoothStreamingManifestWriter(); CompositeManifestInfo manifestInfo = new CompositeManifestInfo(manifestParser.ManifestInfo.MajorVersion, manifestParser.ManifestInfo.MinorVersion); Clip clip = new Clip(this.manifestUri, 394311093750, 395006410000); foreach (StreamInfo streamInfo in manifestParser.ManifestInfo.Streams) { clip.Streams.Add(streamInfo); } manifestInfo.Clips.Add(clip); string output = manifestWriter.GenerateCompositeManifest(manifestInfo, true); XDocument expectedDocument = XDocument.Parse(expectedManifest); XDocument outputDocument = XDocument.Parse(output); Assert.AreEqual(expectedDocument.ToString(), outputDocument.ToString()); }
public void ShouldNotOverflowOnSourceManifestWithDuration2() { string expectedManifest; using (var expectedManifestStream = new FileStream(@".\Content\interstitial2.csm", FileMode.Open, FileAccess.Read)) { using (StreamReader reader = new StreamReader(expectedManifestStream)) { expectedManifest = reader.ReadToEnd(); } } var manifestStream = new FileStream(@".\Content\interstitial2.xml", FileMode.Open, FileAccess.Read); var manifestParser = new SmoothStreamingManifestParser(manifestStream); var manifestWriter = new SmoothStreamingManifestWriter(); CompositeManifestInfo manifestInfo = new CompositeManifestInfo(manifestParser.ManifestInfo.MajorVersion, manifestParser.ManifestInfo.MinorVersion); Clip clip = new Clip(this.manifestUri, 611540, 23391570); foreach (StreamInfo streamInfo in manifestParser.ManifestInfo.Streams) { clip.Streams.Add(streamInfo); } manifestInfo.Clips.Add(clip); string output = manifestWriter.GenerateCompositeManifest(manifestInfo, true); XDocument expectedDocument = XDocument.Parse(expectedManifest); XDocument outputDocument = XDocument.Parse(output); Assert.AreEqual(expectedDocument.ToString(), outputDocument.ToString()); }
public void ShouldGenerateCompositeSmoothStreamingManifestVersion1() { string expectedManifest; using (var expectedManifestStream = new FileStream(@".\Content\VideoAudioCompositeSampleManifest_version1.ismc", FileMode.Open, FileAccess.Read)) { using (StreamReader reader = new StreamReader(expectedManifestStream)) { expectedManifest = reader.ReadToEnd(); } } var manifestStream = new FileStream(@".\Content\SampleManifest_version1.ismc", FileMode.Open, FileAccess.Read); var manifestParser = new SmoothStreamingManifestParser(manifestStream); var manifestWriter = new SmoothStreamingManifestWriter(); CompositeManifestInfo manifestInfo = new CompositeManifestInfo(manifestParser.ManifestInfo.MajorVersion, manifestParser.ManifestInfo.MinorVersion); Clip clip = new Clip(this.manifestUri, 400000000, 900000000); foreach (StreamInfo streamInfo in manifestParser.ManifestInfo.Streams) { clip.Streams.Add(streamInfo); } manifestInfo.Clips.Add(clip); string output = manifestWriter.GenerateCompositeManifest(manifestInfo, true); XDocument expectedDocument = XDocument.Parse(expectedManifest); XDocument outputDocument = XDocument.Parse(output); Assert.AreEqual(expectedDocument.ToString(), outputDocument.ToString()); }
private IEnumerable <string> GetManifests(string pbpDataStreamName, string adsDataStreamName, bool compressManifest, string gapUriString, string gapCmsId, string gapAzureId, int sequenceNumber) { List <string> manifests = new List <string>(); this.gapUri = new Uri(gapUriString); DownloaderManager manager = new DownloaderManager(); string manifest = string.Empty; if (this.project.Sequences != null && this.project.Sequences.Count >= 1) { Stream gapStream = manager.DownloadManifest(this.gapUri, true); byte[] gapResult = null; using (BinaryReader reader = new BinaryReader(gapStream)) { gapResult = reader.ReadBytes((int)manager.LastResponseLength); } MemoryStream gapMemoryStream = null; try { gapMemoryStream = new MemoryStream(gapResult); Sequence sequence = this.project.Sequences[0]; if (this.project.Sequences.Count > sequenceNumber) { sequence = this.project.Sequences[sequenceNumber]; } foreach ( var track in sequence.Tracks.Where( t => (t.TrackType.Equals("visual", StringComparison.InvariantCultureIgnoreCase) || t.TrackType.Equals("audio", StringComparison.InvariantCultureIgnoreCase)) && t.Shots.Count > 0)) { CompositeManifestInfo compositeManifestInfo = new CompositeManifestInfo(2, 0); compositeManifestInfo.PlayByPlayDataStreamName = pbpDataStreamName; compositeManifestInfo.AdsDataStreamName = adsDataStreamName; compositeManifestInfo.RubberBandingDataStreamName = "RubberBanding"; compositeManifestInfo.TransitionDataStreamName = "Transition"; IDictionary <Shot, double> gapDurations = CalculateGapsDuration(track); foreach (Shot shot in track.Shots) { Resource resource = shot.Source.Resources.SingleOrDefault(x => !string.IsNullOrEmpty(x.Ref)); Uri assetUri; if (resource != null && Uri.TryCreate(resource.Ref, UriKind.Absolute, out assetUri)) { Stream manifestStream = manager.DownloadManifest(assetUri, true); MemoryStream stream = new MemoryStream(); if (manifestStream != null) { byte[] buffer = ReadFully(manifestStream); if (buffer != null) { var binaryWriter = new BinaryWriter(stream); binaryWriter.Write(buffer); } stream.Seek(0, SeekOrigin.Begin); } this.AddPreviousGap(gapDurations[shot], gapMemoryStream, gapCmsId, gapAzureId, compositeManifestInfo); AddClipToCompositeManifestInfo(shot, stream, compositeManifestInfo); this.AddRubberBandingPoints(shot, compositeManifestInfo); this.AddTransitions(shot, compositeManifestInfo); stream.Close(); if (track.TrackType.Equals("visual", StringComparison.InvariantCultureIgnoreCase)) { compositeManifestInfo.OverlayDataStreamName = "Overlay"; var overlaysTrack = sequence.Tracks.First(t => t.TrackType.Equals("Overlay")); foreach (Shot s in overlaysTrack.Shots) { this.AddOverlay(s, compositeManifestInfo); } if (sequence.AdOpportunities != null) { foreach ( RCE.Services.Contracts.AdOpportunity adOpportunity in sequence.AdOpportunities) { compositeManifestInfo.AddAdOpportunity( adOpportunity.ID, adOpportunity.TemplateType, adOpportunity.Time); } } if (sequence.MarkerCollection != null) { foreach (Marker marker in sequence.MarkerCollection) { compositeManifestInfo.AddPlayByPlay(marker.ID, marker.Text, marker.Time); } } } } } SmoothStreamingManifestWriter writer = new SmoothStreamingManifestWriter(); manifest = writer.GenerateCompositeManifest(compositeManifestInfo, false, compressManifest); manifests.Add(manifest); } } finally { if (gapMemoryStream != null) { gapMemoryStream.Close(); } } } return(manifests); }
public string GetManifest(string projectXml, string pbpDataStreamName, string adsDataStreamName) { CompositeManifestInfo compositeManifestInfo = new CompositeManifestInfo(2, 0); compositeManifestInfo.PlayByPlayDataStreamName = pbpDataStreamName; compositeManifestInfo.AdsDataStreamName = adsDataStreamName; DownloaderManager manager = new DownloaderManager(); const ulong Timescale = 10000000; Project project; try { project = Deserialize<Project>(projectXml); } catch { return Resources.Resources.InvalidRCEProjectXml; } if (project.Timeline != null) { Track track = project.Timeline.SingleOrDefault(x => x.TrackType.ToUpperInvariant() == "VISUAL"); if (track != null && track.Shots != null) { foreach (Shot shot in track.Shots) { if (shot.Source != null && shot.Source is VideoItem && shot.Source.Resources.Count > 0 && shot.SourceAnchor != null) { Resource resource = shot.Source.Resources.SingleOrDefault(x => !String.IsNullOrEmpty(x.Ref)); Uri assetUri; if (resource != null && Uri.TryCreate(resource.Ref, UriKind.Absolute, out assetUri)) { Stream manifestStream = manager.DownloadManifest(assetUri, true, null); if (manifestStream != null) { double startPosition = (shot.Source is SmoothStreamingVideoItem) ? ((SmoothStreamingVideoItem)shot.Source).StartPosition : 0; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(manifestStream); ulong clipBegin = (ulong)((shot.SourceAnchor.MarkIn.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); ulong clipEnd = (ulong)((shot.SourceAnchor.MarkOut.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); compositeManifestInfo.AddClip(assetUri, clipBegin, clipEnd, parser.ManifestInfo); } } } //if (shot.Source != null && shot.Source is ImageItem && shot.Source.Resources.Count > 0 && shot.SourceAnchor != null) //{ // Resource resource = shot.Source.Resources.SingleOrDefault(x => !String.IsNullOrEmpty(x.Ref)); // Uri assetUri; // if (resource != null && Uri.TryCreate(resource.Ref, UriKind.Absolute, out assetUri)) // { // Stream imageStream = manager.DownloadManifest(assetUri, true, null); // if (imageStream != null) // { // double startPosition = shot.SourceAnchor.MarkIn.GetValueOrDefault(); // //double startPosition = (shot.Source is SmoothStreamingVideoItem) ? ((SmoothStreamingVideoItem)shot.Source).StartPosition : 0; // SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(imageStream); // ulong clipBegin = (ulong)((shot.SourceAnchor.MarkIn.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); // ulong clipEnd = (ulong)((shot.SourceAnchor.MarkOut.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); // compositeManifestInfo.AddClip(assetUri, clipBegin, clipEnd, parser.ManifestInfo); // } // } } } } }
private void GenerateManifest() { IDictionary <Track, string> manifestByTrack = new Dictionary <Track, string>(); var tracks = this.sequenceRegistry.CurrentSequenceModel.Tracks.Where( t => (t.TrackType == TrackType.Visual || t.TrackType == TrackType.Audio) && t.Shots.Count > 0); foreach (var track in tracks) { CompositeManifestInfo compositeManifestInfo = new CompositeManifestInfo(2, 0); compositeManifestInfo.RubberBandingDataStreamName = "RubberBanding"; compositeManifestInfo.TransitionDataStreamName = "Transition"; IDictionary <TimelineElement, double> gapDurations = CalculateGapsDuration(track); foreach (TimelineElement shot in track.Shots) { if (this.streamsByUri.ContainsKey(shot.Asset.Source)) { Stream manifestStream = this.streamsByUri[shot.Asset.Source]; if (manifestStream != null) { if (!this.treatGapsAsError) { this.AddPreviousGap(gapDurations[shot], this.streamsByUri[this.gapUri], compositeManifestInfo); } AddClipToCompositeManifestInfo(shot, manifestStream, compositeManifestInfo); this.AddRubberBandingPoints(shot, compositeManifestInfo); this.AddTransitions(shot, compositeManifestInfo); } } } if (track.TrackType == TrackType.Visual) { compositeManifestInfo.OverlayDataStreamName = "Overlay"; var overlaysTrack = this.sequenceRegistry.CurrentSequenceModel.Tracks.First(t => t.TrackType == TrackType.Overlay); foreach (TimelineElement shot in overlaysTrack.Shots) { this.AddOverlay(shot, compositeManifestInfo); } } var userSettings = this.userSettingsService.GetSettings(); SmoothStreamingManifestWriter writer = new SmoothStreamingManifestWriter(); string manifest = writer.GenerateCompositeManifest( compositeManifestInfo, false, false, userSettings.MinBitrate, userSettings.MaxBitrate, userSettings.IsSingleBitrate); manifestByTrack[track] = manifest; } this.dispatcher.BeginInvoke(() => this.actionCallback(manifestByTrack)); }
private static void AddTransition(SmoothStreamingManifestGenerator.Models.TransitionType transitionType, AssetType assetType, ulong position, double duration, CompositeManifestInfo compositeManifestInfo) { compositeManifestInfo.AddTransition(transitionType, assetType, position, duration); }
private static void AddClipToCompositeManifestInfo(TimelineElement shot, Stream manifestStream, CompositeManifestInfo compositeManifestInfo) { const ulong Timescale = 10000000; ulong startPosition = 0; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(manifestStream); manifestStream.Seek(0, SeekOrigin.Begin); var subClipAsset = shot.Asset as VideoAssetInOut; var adaptiveAsset = subClipAsset != null && subClipAsset.IsAdaptiveAsset ? (IAdaptiveAsset)subClipAsset.VideoAsset : shot.Asset as IAdaptiveAsset; // the timeline elements holds the in/out position, instead of creating an ISubClipAsset double markIn = shot.InPosition.TotalSeconds; double markOut = shot.OutPosition.TotalSeconds; if (adaptiveAsset != null) { startPosition = GetStartPositionFromManifest(parser); } if (!string.IsNullOrEmpty(shot.SelectedAudioStream)) { var audioStreamsToRemove = parser.ManifestInfo.Streams.Where(s => s.StreamType.Equals("Audio", StringComparison.CurrentCultureIgnoreCase) && !s.Attributes["Name"].Equals(shot.SelectedAudioStream)).ToList(); if (audioStreamsToRemove != null) { foreach (var audioStream in audioStreamsToRemove) { parser.ManifestInfo.Streams.Remove(audioStream); } } } if (subClipAsset != null) { if (!string.IsNullOrEmpty(subClipAsset.SequenceVideoCamera)) { var videoStream = parser.ManifestInfo.Streams.First(s => s.StreamType.Equals("Video", StringComparison.CurrentCultureIgnoreCase)); var qualityLevelsToRemove = videoStream.QualityLevels.Where(q => !q.CustomAttributes.ContainsKey("cameraAngle") || !q.CustomAttributes["cameraAngle"].Equals(subClipAsset.SequenceVideoCamera)).ToList(); foreach (var qualityLevel in qualityLevelsToRemove) { videoStream.QualityLevels.Remove(qualityLevel); } } startPosition = GetStartPositionFromManifest(parser); } ulong clipBegin = (ulong)(Convert.ToUInt64(markIn * Timescale) + startPosition); ulong clipEnd = (ulong)(Convert.ToUInt64(markOut * Timescale) + startPosition); var customAttributes = new Dictionary <string, string> { { "CMSId", shot.Asset.CMSId }, { "AzureId", shot.Asset.AzureId } }; compositeManifestInfo.AddClip(shot.Asset.Source, clipBegin, clipEnd, customAttributes, parser.ManifestInfo); }
public void ShouldGenerateSimpleCompositeManifestVersion1() { string expectedManifest; using (var manifestStream = new FileStream(@".\Content\SimpleCompositeSampleManifest_version1.csm", FileMode.Open, FileAccess.Read)) { using (var reader = new StreamReader(manifestStream)) { expectedManifest = reader.ReadToEnd(); } } CompositeManifestInfo manifestInfo = new CompositeManifestInfo(1, 0); Clip clip = new Clip(new Uri("http://server/stream1.isml/Manifest"), 6400000000, 6510000000); StreamInfo streamInfo = new StreamInfo("video"); streamInfo.AddAttribute("Chunks", "0"); streamInfo.AddAttribute("Type", "video"); streamInfo.AddAttribute("SubType", "WVC1"); streamInfo.AddAttribute("Url", "QualityLevels({bitrate})/Fragments(video={start time})"); ulong[] bitrates = { 350000, 1050000, 600000, 1450000 }; int[][] sizes = { new[] { 320, 176 }, new[] { 592, 336 }, new[] { 424, 240 }, new[] { 848, 476 } }; for (int i = 0; i < bitrates.Length; i++) { QualityLevel qualityLevel = new QualityLevel(); qualityLevel.AddAttribute("Bitrate", bitrates[i].ToString()); qualityLevel.AddAttribute("FourCC", "WVC1"); qualityLevel.AddAttribute("Width", sizes[i][0].ToString()); qualityLevel.AddAttribute("Height", sizes[i][1].ToString()); qualityLevel.AddAttribute("CodecPrivateData", "250000010FCBA01270A58A12782968045080A00AE020C00000010E5A47F840"); streamInfo.QualityLevels.Add(qualityLevel); } for (int i = 0; i < 325; i++) { ulong time = ((ulong)i * 20000000) + 20000000; ulong?duration = null; if (i == 324) { duration = 17500001; } Chunk chunk = new Chunk(null, time, duration); streamInfo.Chunks.Add(chunk); } clip.Streams.Add(streamInfo); manifestInfo.Clips.Add(clip); var manifestWriter = new SmoothStreamingManifestWriter(); string output = manifestWriter.GenerateCompositeManifest(manifestInfo, true); XDocument expectedDocument = XDocument.Parse(expectedManifest); XDocument outputDocument = XDocument.Parse(output); Assert.AreEqual(expectedDocument.ToString(), outputDocument.ToString()); }
private static void AddClipToCompositeManifestInfo(Shot shot, Stream manifestStream, CompositeManifestInfo compositeManifestInfo) { const ulong Timescale = 10000000; ulong startPosition = 0; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(manifestStream); manifestStream.Seek(0, SeekOrigin.Begin); var subClipAsset = shot.Source as SubClipItem; var smoothStreamingVideoItem = shot.Source as SmoothStreamingVideoItem; var smoothStreamingAudioItem = shot.Source as SmoothStreamingAudioItem; // the timeline elements holds the in/out position, instead of creating an ISubClipAsset double markIn = shot.SourceAnchor.MarkIn.Value; double markOut = shot.SourceAnchor.MarkOut.Value; if (smoothStreamingVideoItem != null || smoothStreamingAudioItem != null) { startPosition = GetStartPositionFromManifest(parser); } if (!string.IsNullOrEmpty(shot.SequenceAudioStream)) { var audioStreamsToRemove = parser.ManifestInfo.Streams.Where(s => s.StreamType.Equals("Audio", StringComparison.CurrentCultureIgnoreCase) && !s.Attributes["Name"].Equals(shot.SequenceAudioStream)).ToList(); if (audioStreamsToRemove != null) { foreach (var audioStream in audioStreamsToRemove) { parser.ManifestInfo.Streams.Remove(audioStream); } } } if (subClipAsset != null) { if (!string.IsNullOrEmpty(subClipAsset.SequenceVideoStream)) { var videoStream = parser.ManifestInfo.Streams.First(s => s.StreamType.Equals("Video", StringComparison.CurrentCultureIgnoreCase)); var qualityLevelsToRemove = videoStream.QualityLevels.Where(q => !q.CustomAttributes.ContainsKey("cameraAngle") || !q.CustomAttributes["cameraAngle"].Equals(subClipAsset.SequenceVideoStream)).ToList(); foreach (var qualityLevel in qualityLevelsToRemove) { videoStream.QualityLevels.Remove(qualityLevel); } } startPosition = GetStartPositionFromManifest(parser); } ulong clipBegin = (ulong)(Convert.ToUInt64(markIn * Timescale) + startPosition); ulong clipEnd = (ulong)(Convert.ToUInt64(markOut * Timescale) + startPosition); Resource resource = shot.Source.Resources.SingleOrDefault(x => !string.IsNullOrEmpty(x.Ref)); Uri assetUri; Uri.TryCreate(resource.Ref, UriKind.Absolute, out assetUri); var customAttributes = new Dictionary <string, string> { { "CMSId", shot.Source.CMSId }, { "AzureId", shot.Source.AzureId } }; compositeManifestInfo.AddClip(assetUri, clipBegin, clipEnd, customAttributes, parser.ManifestInfo); }
public CreateTrainingSetResponse CreateTrainingSet(CreateTrainingSetRequest request) { var response = new CreateTrainingSetResponse(); try { var downloadManager = new DownloaderManager(); var compositeManifestInfo = new CompositeManifestInfo(2, 0); var videoRepository = serviceLocator.GetInstance <IVideoRepository>(); var catalogRepository = serviceLocator.GetInstance <ICatalogRepository>(); var templateRepository = serviceLocator.GetInstance <ITrainingSetTemplateRepository>(); var totalDuration = TimeSpan.Zero; foreach (var videoPart in request.TrainingSet.VideoParts) { var video = videoRepository.Get(videoPart.VideoId); var manifestStream = downloadManager.DownloadManifest(video.StreamUri, true, null); if (manifestStream != null) { var parser = new SmoothStreamingManifestParser(manifestStream); double startPosition = videoPart.From.TotalSeconds; double endPosition = videoPart.To.TotalSeconds; compositeManifestInfo.AddClip(video.StreamUri, (ulong)(startPosition * Timescale), (ulong)(endPosition * Timescale), parser.ManifestInfo); totalDuration = totalDuration.Add(videoPart.To.Subtract(videoPart.From)); } } var writer = new SmoothStreamingManifestWriter(); var manifest = writer.GenerateCompositeManifest(compositeManifestInfo, false, false); string csmPath = HttpContext.Current.Server.MapPath("csm"); if (!Directory.Exists(csmPath)) { Directory.CreateDirectory(csmPath); } var uniqueName = Guid.NewGuid().ToString(); string tmpFilePath = Path.Combine(csmPath, string.Format("{0}.tmpcsm", uniqueName)); string finalFilePath = Path.Combine(csmPath, string.Format("{0}.csm", uniqueName)); File.WriteAllText(tmpFilePath, manifest, Encoding.UTF8); if (File.Exists(tmpFilePath)) { if (File.Exists(finalFilePath)) { File.Delete(finalFilePath); } File.Move(tmpFilePath, finalFilePath); } var userService = serviceLocator.GetInstance <IApplicationUserService>(); var user = userService.RetrieveApplicationUser(new ApplicationUserFindCriteria() { Username = request.User }); var template = templateRepository.Get(request.TrainingSet.TrainingSetTemplateId); //var _telemetry = new List<Telemetry>(); var timer = TimeSpan.Zero; var recordingInterval = TimeSpan.FromSeconds(2); var telemetryFile = new StringBuilder().AppendLine("\"Minutes\",\"Torq(N-m)\",\"Km/h\",\"Watts\",\"Km\",\"Cadence\",\"Hrate\",\"ID\",\"Altitude(m)\""); foreach (var interval in template.Intervals) { var numberOfElements = interval.Duration.TotalSeconds / recordingInterval.TotalSeconds; for (int i = 0; i < numberOfElements; i++) { var telemetry = new Telemetry(); telemetry.PercentageThreshold = Convert.ToDouble(interval.Effort) / 100; telemetry.Watts = ((telemetry.PercentageThreshold) * user.FTP.GetValueOrDefault()); telemetry.TimePosition = timer; timer = timer.Add(recordingInterval); telemetryFile.AppendLine(telemetry.ToDelimitedString(',')); //telemetry.PercentageThreshold = Convert.ToDouble(interval.Effort); //telemetry.TimePosition = timer; //telemetryFile.AppendLine(telemetry.ToDelimitedString(',')); } } string telemetryPath = HttpContext.Current.Server.MapPath("telemetry"); if (!Directory.Exists(telemetryPath)) { Directory.CreateDirectory(telemetryPath); } string filePath = Path.Combine(telemetryPath, string.Format("{0}.csv", uniqueName)); File.WriteAllText(filePath, telemetryFile.ToString()); //var context = System.ServiceModel.OperationContext.Current; //RemoteEndpointMessageProperty property = (RemoteEndpointMessageProperty)context.IncomingMessageProperties[RemoteEndpointMessageProperty.Name]; string host = "www.indoorworx.com";// property.Address; //var host = "localhost"; //now create the video var workout = new Video(); workout.StreamUri = new Uri(string.Format("http://{0}/IndoorWorx/csm/{1}.csm", host, uniqueName), UriKind.Absolute); workout.Title = request.TrainingSet.Title; workout.Description = template.Description; workout.Duration = totalDuration; workout.TelemetryInfo.TelemetryUri = new Uri(string.Format("http://{0}/IndoorWorx/telemetry/{1}.csv", host, uniqueName), UriKind.Absolute); foreach (var text in template.VideoText) { workout.VideoText.Add(text.Clone()); } workout.Intervals = template.Intervals.Select(x => new VideoInterval(x.Duration, x.Effort, x.Sequence)).ToList(); var savedWorkout = videoRepository.Save(workout); userService.AddVideoToLibrary(new AddVideoRequest() { User = request.User, VideoId = savedWorkout.Id }); response.Status = CreateTrainingSetStatus.Success; response.TrainingSet = savedWorkout; } catch (Exception ex) { response.Status = CreateTrainingSetStatus.Error; response.Message = ex.StackTrace; //response.Message = ex.Message; } return(response); }
public void CreateCompositeStream(Contracts.Project project) { CompositeManifestInfo compositeManifestInfo = new CompositeManifestInfo(2, 1); compositeManifestInfo.PlayByPlayDataStreamName = "PBP"; compositeManifestInfo.AdsDataStreamName = "ADS"; DownloaderManager manager = new DownloaderManager(); const ulong Timescale = 10000000; if (project.Timeline != null) { Track track = project.Timeline.SingleOrDefault(x => x.TrackType.ToUpperInvariant() == "VISUAL"); if (track != null && track.Shots != null) { foreach (Shot shot in track.Shots) { if (shot.Source != null && shot.Source is VideoItem && shot.Source.Resources.Count > 0 && shot.SourceAnchor != null) { Resource resource = shot.Source.Resources.SingleOrDefault(x => !String.IsNullOrEmpty(x.Ref)); Uri assetUri; if (resource != null && Uri.TryCreate(resource.Ref, UriKind.Absolute, out assetUri)) { Stream manifestStream = manager.DownloadManifest(assetUri, true, null); if (manifestStream != null) { double startPosition = (shot.Source is SmoothStreamingVideoItem) ? ((SmoothStreamingVideoItem)shot.Source).StartPosition : 0; SmoothStreamingManifestParser parser = new SmoothStreamingManifestParser(manifestStream); ulong clipBegin = (ulong)((shot.SourceAnchor.MarkIn.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); ulong clipEnd = (ulong)((shot.SourceAnchor.MarkOut.GetValueOrDefault() * Timescale) + (startPosition * Timescale)); compositeManifestInfo.AddClip(assetUri, clipBegin, clipEnd, parser.ManifestInfo); } } } } } } if (project.Titles != null) { foreach (var title in project.Titles) { //compositeManifestInfo } } if (project.AdOpportunities != null) { foreach (RCE.Services.Contracts.AdOpportunity adOpportunity in project.AdOpportunities) { compositeManifestInfo.AddAdOpportunity(adOpportunity.ID, adOpportunity.TemplateType, adOpportunity.Time); } } if (project.Markers != null) { foreach (Marker marker in project.Markers) { compositeManifestInfo.AddPlayByPlay(marker.ID, marker.Text, marker.Time); } } SmoothStreamingManifestWriter writer = new SmoothStreamingManifestWriter(); string manifest = writer.GenerateCompositeManifest(compositeManifestInfo, false); string csmPath = HttpContext.Current.Server.MapPath("csm"); if (!Directory.Exists(csmPath)) { Directory.CreateDirectory(csmPath); } string datetime = DateTime.Now.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture); string tmpFilePath = Path.Combine(csmPath, string.Format(CultureInfo.InvariantCulture, "{0}-{1}.tmpcsm", project.Title.ToString(), datetime)); string finalFilePath = Path.Combine(csmPath, string.Format(CultureInfo.InvariantCulture, "{0}-{1}.csm", project.Title.ToString(), datetime)); File.WriteAllText(tmpFilePath, manifest, Encoding.UTF8); if (File.Exists(tmpFilePath)) { if (File.Exists(finalFilePath)) { File.Delete(finalFilePath); } File.Move(tmpFilePath, finalFilePath); } }