public breakschedule() { this.InitializeComponent(); MediaPlaybackItem moviePlaybackItem = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/fishes.wmv"))); MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromSeconds(3)); midrollMediaBreak.PlaybackList.Items.Add( new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv")))); moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak); /*MediaBreak preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); * MediaPlaybackItem prerollAd = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv"))); * prerollAd.CanSkip = false; * preRollMediaBreak.PlaybackList.Items.Add(prerollAd); * moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak;*/ /*midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromSeconds(5)); * MediaPlaybackItem ad = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_3.mp4")), * TimeSpan.FromSeconds(6), * TimeSpan.FromSeconds(10)); * ad.CanSkip = false; * midrollMediaBreak.PlaybackList.Items.Add(ad);*/ _mediaPlayer.Source = moviePlaybackItem; mediaPlayerElement.SetMediaPlayer(_mediaPlayer); _mediaPlayer.AutoPlay = true; _mediaPlayer.BreakManager.BreakStarted += BreakManager_BreakStarted; _mediaPlayer.BreakManager.BreakEnded += BreakManager_BreakEnded; _mediaPlayer.BreakManager.BreakSkipped += BreakManager_BreakSkipped; _mediaPlayer.BreakManager.BreaksSeekedOver += BreakManager_BreaksSeekedOver; }
//http://www.fabrikam.com/ private void CreateMediaBreakSchedule() { // <SnippetMoviePlaybackItem> MediaPlaybackItem moviePlaybackItem = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/movie.mkv"))); // </SnippetMoviePlaybackItem> // <SnippetPreRollBreak> MediaBreak preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); MediaPlaybackItem prerollAd = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/preroll_ad.mp4"))); prerollAd.CanSkip = false; preRollMediaBreak.PlaybackList.Items.Add(prerollAd); moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak; // </SnippetPreRollBreak> // <SnippetPostRollBreak> MediaBreak postrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); MediaPlaybackItem postRollAd = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/postroll_ad.mp4"))); postrollMediaBreak.PlaybackList.Items.Add(postRollAd); moviePlaybackItem.BreakSchedule.PostrollBreak = postrollMediaBreak; // </SnippetPostRollBreak> // <SnippetMidrollBreak> MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10)); midrollMediaBreak.PlaybackList.Items.Add( new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_1.mp4")))); midrollMediaBreak.PlaybackList.Items.Add( new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_2.mp4")))); moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak); // </SnippetMidrollBreak> // <SnippetMidrollBreak2> midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromMinutes(20)); MediaPlaybackItem ad = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_3.mp4")), TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(15)); ad.CanSkip = false; midrollMediaBreak.PlaybackList.Items.Add(ad); // </SnippetMidrollBreak2> // <SnippetPlay> _mediaPlayer = new MediaPlayer(); _mediaPlayer.AutoPlay = true; _mediaPlayer.Source = moviePlaybackItem; mediaPlayerElement.SetMediaPlayer(_mediaPlayer); // </SnippetPlay> }
// </SnippetBreakStarted> // <SnippetGetCurrentBreakItemIndex> public int GetCurrentBreakItemIndex() { MediaBreak mediaBreak = _mediaPlayer.BreakManager.CurrentBreak; if (!(mediaBreak is null)) { return((int)mediaBreak.PlaybackList.CurrentItemIndex); }
// <SnippetBreakStarted> private async void BreakManager_BreakStarted(MediaBreakManager sender, MediaBreakStartedEventArgs args) { MediaBreak currentBreak = sender.CurrentBreak; var currentIndex = currentBreak.PlaybackList.CurrentItemIndex; var itemCount = currentBreak.PlaybackList.Items.Count; await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => statusTextBlock.Text = $"Playing ad {currentIndex + 1} of {itemCount}"); }
private async Task CreateMediaBreakScheduleTest() { //SnippetMoviePlaybackItem MediaPlaybackItem moviePlaybackItem = await GetMoviePlaybackItem(); ///SnippetMoviePlaybackItem> //SnippetPreRollBreak MediaBreak preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); MediaPlaybackItem prerollAd = await GetAdPlaybackItem(); prerollAd.CanSkip = false; preRollMediaBreak.PlaybackList.Items.Add(prerollAd); moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak; ///SnippetPreRollBreak /* * //SnippetPostRollBreak * MediaBreak postrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); * MediaPlaybackItem postRollAd = await GetAdPlaybackItem(); * postrollMediaBreak.PlaybackList.Items.Add(postRollAd); * * moviePlaybackItem.BreakSchedule.PostrollBreak = postrollMediaBreak; * ///SnippetPostRollBreak * * * ///SnippetMidrollBreak * MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromSeconds(10)); * midrollMediaBreak.PlaybackList.Items.Add(await GetAdPlaybackItem()); * midrollMediaBreak.PlaybackList.Items.Add(await GetAdPlaybackItem()); * //MediaPlaybackItem ad = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://myserver/midroll_ad_3.mp4")), * //TimeSpan.FromSeconds(5), * //TimeSpan.FromSeconds(15)); * //MediaPlaybackItem ad = await GetScheduledMediaPlaybackItem(); * //ad.CanSkip = false; * //midrollMediaBreak.PlaybackList.Items.Add(ad); * * moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak); * * ///SnippetMidrollBreak */ //Play _mediaPlayer = new MediaPlayer(); _mediaPlayer.AutoPlay = true; _mediaPlayer.Source = moviePlaybackItem; mediaPlayerElement.SetMediaPlayer(_mediaPlayer); ///Play }
// </SnippetBreakStarted> // <SnippetGetCurrentBreakItemIndex> public int GetCurrentBreakItemIndex() { MediaBreak mediaBreak = _mediaPlayer.BreakManager.CurrentBreak; if (mediaBreak != null) { return((int)mediaBreak.PlaybackList.CurrentItemIndex); } else { { return(-1); } } }
private async void BreakManager_BreakSkipped(MediaBreakManager sender, MediaBreakSkippedEventArgs args) { // Update UI to show that the MediaBreak is no longer playing await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => statusTextBlock.Text = ""); MediaPlaybackItem currentItem = _mediaPlayer.Source as MediaPlaybackItem; if (!(currentItem.BreakSchedule.PrerollBreak is null) && currentItem.BreakSchedule.PrerollBreak == args.MediaBreak) { MediaBreak mediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10)); mediaBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv")))); currentItem.BreakSchedule.InsertMidrollBreak(mediaBreak); } }
/// <summary> /// This function attempts to parse the SCTE-35 payload, then schedule an appropriately offset Ad using the MediaBreak APIs /// </summary> /// <param name="timedMetadataTrack">Track which fired the cue</param> /// <param name="presentation_time_delta"></param> /// <param name="timescale"></param> /// <param name="event_duration"></param> /// <param name="scte35payload"></param> private async void ScheduleAdFromScte35Payload(TimedMetadataTrack timedMetadataTrack, uint presentation_time_delta, uint timescale, uint event_duration, string scte35payload) { // TODO: Parse SCTE-35 // // Ref: // http://www.scte.org/SCTEDocs/Standards/ANSI_SCTE%20214-3%202015.pdf // // Eg: // // <SpliceInfoSection ptsAdjustment="0" scte35:tier="4095"> // <SpliceInsert spliceEventId="147467497" // spliceEventCancelIndicator="false" // outOfNetworkIndicator="false" // uniqueProgramId="0" // availNum="0" // availsExpected="0" // spliceImmediateFlag="false" > // <Program> // <SpliceTime ptsTime="6257853600"/> // </Program> // <BreakDuration autoReturn="true" duration="900000"/> // </SpliceInsert> // </SpliceInfoSection> // // // We use the metadata track object which fired the Cue to walk our way back up the // media object stack to find our original AdaptiveMediaSource. // // The AdaptiveMediaSource is required because the SCTE-35 payload includes // timing offsets which are relative to the original content PTS -- see below. var ams = timedMetadataTrack.PlaybackItem.Source.AdaptiveMediaSource; if (ams != null && timescale != 0) { // ++++ // NOTE: DO NOT PARSE SCTE35 LIKE THIS IN PRODUCTION CODE! // // Reminder: // // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. // // We will not demonstrate proper SCTE35 parsing in this sample, // but instead we search through the xml find the ptsTime if present, // and use it to schedule an ad; keeping in place the various time offsets. // // e.g.: var sampleScte35Payload = "<SpliceInfoSection ptsAdjustment=\"0\" scte35:tier=\"4095\">< SpliceInsert spliceEventId = \"147467497\" spliceEventCancelIndicator = \"false\" outOfNetworkIndicator = \"false\" uniqueProgramId = \"0\" availNum = \"0\" availsExpected = \"0\" spliceImmediateFlag = \"false\" > < Program >< SpliceTime ptsTime = \"6257853600\" /></ Program > < BreakDuration autoReturn = \"true\" duration = \"900000\" /> </ SpliceInsert > </ SpliceInfoSection > "; // var xmlStrings = scte35payload.Split(new string[] { "<", "/", ">", " ", "=", "\"" }, StringSplitOptions.RemoveEmptyEntries); string ptsTime = string.Empty; for (int i = 0; i < xmlStrings.Length; i++) { if (xmlStrings[i] == "ptsTime") { if (i + 1 < xmlStrings.Length) { ptsTime = xmlStrings[i + 1]; break; } } } // ---- // The AdaptiveMediaSource keeps track of the original PTS in an AdaptiveMediaSourceCorrelatedTimes // object that can be retrieved via ams.GetCorrelatedTimes(). All the while, it provids the // media pipeline with a consistent timeline that re-aligns zero at the begining of the SeekableRange // when first joining a Live stream. long pts = 0; long.TryParse(ptsTime, out pts); var timeCorrelation = ams.GetCorrelatedTimes(); if (timeCorrelation.Position.HasValue && timeCorrelation.PresentationTimeStamp.HasValue) { TimeSpan currentPosition; await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { currentPosition = mediaPlayerElement.MediaPlayer.PlaybackSession.Position; }); TimeSpan emsgPresentationTimeDelta = TimeSpan.FromSeconds(presentation_time_delta / timescale); long delayInTicks = timeCorrelation.PresentationTimeStamp.Value.Ticks - pts; TimeSpan correctionForAsyncCalls = currentPosition - timeCorrelation.Position.Value; TimeSpan targetAdPosition = emsgPresentationTimeDelta + TimeSpan.FromTicks(delayInTicks) + correctionForAsyncCalls; Log($"Timing Info: PlaybackSession.Position:{currentPosition} targetAdPosition:{targetAdPosition} Delta:{targetAdPosition-currentPosition} Ams.Position:{timeCorrelation.Position.GetValueOrDefault().Ticks} SCTE ptsTime:{pts} emsgPresentationTimeDelta:{emsgPresentationTimeDelta} Ams.PresentationTimeStamp:{timeCorrelation.PresentationTimeStamp.GetValueOrDefault().Ticks} Ams.ProgramDateTime:{timeCorrelation.ProgramDateTime.GetValueOrDefault()}"); MediaBreakInsertionMethod insertionMethod = ams.IsLive ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt; var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4"); if (targetAdPosition != TimeSpan.Zero && targetAdPosition >= currentPosition) { // Schedule ad in the future: Log($"Ad insertion triggerd by 'emsg'. Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}"); var midRollBreak = new MediaBreak(insertionMethod, targetAdPosition); midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri))); timedMetadataTrack.PlaybackItem.BreakSchedule.InsertMidrollBreak(midRollBreak); } else { // Play now! Log($"Ad inserted immediately. Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}"); var midRollBreak = new MediaBreak(insertionMethod); midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri))); await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { mediaPlayerElement.MediaPlayer.BreakManager.PlayBreak(midRollBreak); }); } } } }
private void CreateMediaBreaksForItem(MediaPlaybackItem item) { if (item != null) { // We have two ads that will be repeated. var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4"); var flowersUri = new Uri("http://az29176.vo.msecnd.net/videocontent/CrocusTL_FramePoolRM_688-580-676_1080_HD_EN-US.mp4"); // One option is to create a separate MediaPlaybackItem for each of your ads. // You might choose to do this if each ad needs different reporting information. // Another option is to re-use MediaPlaybackItems in different MediaBreaks. // This scenario demonstrates both patterns. var ad1 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)); ad1.Source.CustomProperties["contentId"] = "Ad1_ID"; ad1.Source.CustomProperties["description"] = "Red Sky"; ad1.Source.CustomProperties["uri"] = redSkyUri.ToString(); RegisterForMediaSourceEvents(ad1.Source); RegisterForMediaPlaybackItemEvents(ad1); var ad2 = new MediaPlaybackItem(MediaSource.CreateFromUri(flowersUri)); ad2.Source.CustomProperties["contentId"] = "Ad2_ID"; ad2.Source.CustomProperties["description"] = "Flowers"; ad2.Source.CustomProperties["uri"] = flowersUri.ToString(); RegisterForMediaSourceEvents(ad2.Source); RegisterForMediaPlaybackItemEvents(ad2); var ad3 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)); ad3.Source.CustomProperties["contentId"] = "Ad3_ID"; ad3.Source.CustomProperties["description"] = "Red Sky 2"; ad3.Source.CustomProperties["uri"] = redSkyUri.ToString(); RegisterForMediaSourceEvents(ad3.Source); RegisterForMediaPlaybackItemEvents(ad3); // Create a PrerollBreak on your main content. if (item.BreakSchedule.PrerollBreak == null) { item.BreakSchedule.PrerollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); } // Add the ads to the PrerollBreak in the order you want them played item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad1); item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad2); // Add the ads to the MidRoll break at 10% into the main content. // To do this, we need to wait until the main MediaPlaybackItem is fully loaded by the player // so that we know its Duration. This will happen on MediaSource.OpenOperationCompleted. item.Source.OpenOperationCompleted += (sender, args) => { var attachedItem = MediaPlaybackItem.FindFromMediaSource(sender); if (sender.Duration.HasValue) { // For live streaming, the duration will be TimeSpan.MaxValue, which won't work for this scenario, // so we'll assume the total duration is 2 minutes for the purpose of ad insertion. bool isLiveMediaSource = item.Source.AdaptiveMediaSource != null ? item.Source.AdaptiveMediaSource.IsLive : false; long sourceDurationTicks = isLiveMediaSource ? TimeSpan.FromMinutes(2).Ticks : sender.Duration.Value.Ticks; var positionAt10PercentOfMainContent = TimeSpan.FromTicks(sourceDurationTicks / 10); // If the content is live, then the ad break replaces the streaming content. // If the content is not live, then the content pauses for the ad, and then resumes // after the ad is complete. MediaBreakInsertionMethod insertionMethod = isLiveMediaSource ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt; var midRollBreak = new MediaBreak(insertionMethod, positionAt10PercentOfMainContent); midRollBreak.PlaybackList.Items.Add(ad2); midRollBreak.PlaybackList.Items.Add(ad1); attachedItem.BreakSchedule.InsertMidrollBreak(midRollBreak); Log($"Added MidRoll at {positionAt10PercentOfMainContent}"); } }; // Create a PostrollBreak: // Note: for Live content, it will only play once the presentation transitions to VOD. if (item.BreakSchedule.PostrollBreak == null) { item.BreakSchedule.PostrollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); } // Add the ads to the PostrollBreak in the order you want them played item.BreakSchedule.PostrollBreak.PlaybackList.Items.Add(ad3); } }
private void CreateMediaBreaksForItem(MediaPlaybackItem item) { if (item != null) { // We have two ads that will be repeated. var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4"); var flowersUri = new Uri("http://az29176.vo.msecnd.net/videocontent/CrocusTL_FramePoolRM_688-580-676_1080_HD_EN-US.mp4"); // One option is to create a separate MediaPlaybackItem for each of your ads. // You might choose to do this if each ad needs different reporting information. // Another option is to re-use MediaPlaybackItems in different MediaBreaks. // This scenario demonstrates both patterns. var ad1 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)); ad1.Source.CustomProperties["contentId"] = "Ad1_ID"; ad1.Source.CustomProperties["description"] = "Red Sky"; ad1.Source.CustomProperties["uri"] = redSkyUri.ToString(); RegisterForMediaSourceEvents(ad1.Source); RegisterForMediaPlaybackItemEvents(ad1); var ad2 = new MediaPlaybackItem(MediaSource.CreateFromUri(flowersUri)); ad2.Source.CustomProperties["contentId"] = "Ad2_ID"; ad2.Source.CustomProperties["description"] = "Flowers"; ad2.Source.CustomProperties["uri"] = flowersUri.ToString(); RegisterForMediaSourceEvents(ad2.Source); RegisterForMediaPlaybackItemEvents(ad2); var ad3 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)); ad3.Source.CustomProperties["contentId"] = "Ad3_ID"; ad3.Source.CustomProperties["description"] = "Red Sky 2"; ad3.Source.CustomProperties["uri"] = redSkyUri.ToString(); RegisterForMediaSourceEvents(ad3.Source); RegisterForMediaPlaybackItemEvents(ad3); // Create a PrerollBreak on your main content. if (item.BreakSchedule.PrerollBreak == null) { item.BreakSchedule.PrerollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); } // Add the ads to the PrerollBreak in the order you want them played item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad1); item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad2); // Add the ads to the MidRoll break at 10% into the main content. // To do this, we need to wait until the main MediaPlaybackItem is fully loaded by the player // so that we know its Duration. This will happen on MediaSource.OpenOperationCompleted. item.Source.OpenOperationCompleted += (sender, args) => { var attachedItem = MediaPlaybackItem.FindFromMediaSource(sender); if (sender.Duration.HasValue) { // For live streaming, the duration will be TimeSpan.MaxValue, which won't work for this scenario, // so we'll assume the total duration is 2 minutes for the purpose of ad insertion. long sourceDurationTicks = isLiveMediaSource ? TimeSpan.FromMinutes(2).Ticks : sender.Duration.Value.Ticks; var positionAt10PercentOfMainContent = TimeSpan.FromTicks(sourceDurationTicks / 10); // If the content is live, then the ad break replaces the streaming content. // If the content is not live, then the content pauses for the ad, and then resumes // after the ad is complete. MediaBreakInsertionMethod insertionMethod = isLiveMediaSource ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt; var midRollBreak = new MediaBreak(insertionMethod, positionAt10PercentOfMainContent); midRollBreak.PlaybackList.Items.Add(ad2); midRollBreak.PlaybackList.Items.Add(ad1); attachedItem.BreakSchedule.InsertMidrollBreak(midRollBreak); Log($"Added MidRoll at {positionAt10PercentOfMainContent}"); } }; // Create a PostrollBreak: // Note: for Live content, it will only play once the presentation transitions to VOD. if (item.BreakSchedule.PostrollBreak == null) { item.BreakSchedule.PostrollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt); } // Add the ads to the PostrollBreak in the order you want them played item.BreakSchedule.PostrollBreak.PlaybackList.Items.Add(ad3); } }