public Subclipping(CloudMediaContext context, MediaServiceContextForDynManifest contextdynmanifest, List <IAsset> assetlist, Mainform mainform) { InitializeComponent(); buttonJobOptions.Initialize(context); this.Icon = Bitmaps.Azure_Explorer_ico; _context = context; _contextdynmanifest = contextdynmanifest; _parentassetmanifestdata = new ManifestTimingData(); _selectedAssets = assetlist; _mainform = mainform; if (_selectedAssets.Count == 1 && _selectedAssets.FirstOrDefault() != null) // one asset only { var myAsset = assetlist.FirstOrDefault(); textBoxAssetName.Text = myAsset.Name; // let's try to read asset timing _parentassetmanifestdata = AssetInfo.GetManifestTimingData(myAsset); if (!_parentassetmanifestdata.Error) // we were able to read asset timings and not live { _timescale = timeControlStart.TimeScale = timeControlEnd.TimeScale = _parentassetmanifestdata.TimeScale; timeControlStart.ScaledFirstTimestampOffset = timeControlEnd.ScaledFirstTimestampOffset = _parentassetmanifestdata.TimestampOffset; textBoxOffset.Text = _parentassetmanifestdata.TimestampOffset.ToString(); labelOffset.Visible = textBoxOffset.Visible = true; textBoxFilterTimeScale.Text = _timescale.ToString(); textBoxFilterTimeScale.Visible = labelAssetTimescale.Visible = true; timeControlStart.Max = timeControlEnd.Max = new TimeSpan(AssetInfo.ReturnTimestampInTicks(_parentassetmanifestdata.AssetDuration, _parentassetmanifestdata.TimeScale)); labelassetduration.Visible = textBoxAssetDuration.Visible = true; textBoxAssetDuration.Text = timeControlStart.Max.ToString(@"d\.hh\:mm\:ss") + (_parentassetmanifestdata.IsLive ? " (LIVE)" : ""); // let set duration and active track bat timeControlStart.ScaledTotalDuration = timeControlEnd.ScaledTotalDuration = _parentassetmanifestdata.AssetDuration; timeControlStart.DisplayTrackBar = true; timeControlEnd.DisplayTrackBar = true; timeControlEnd.SetTimeStamp(timeControlEnd.Max); } else // one asset but not able to read asset timings { timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = false; timeControlStart.TimeScale = timeControlEnd.TimeScale = _timescale; timeControlStart.Max = timeControlEnd.Max = TimeSpan.MaxValue; //timeControlEnd.SetTimeStamp(timeControlEnd.Max); } } else // several assets { groupBoxTrimming.Enabled = panelAssetInfo.Visible = false; // no trimming and no asset info radioButtonAssetFilter.Enabled = false; // no asset filter option timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = false; timeControlStart.TimeScale = timeControlEnd.TimeScale = _timescale; timeControlStart.Max = timeControlEnd.Max = TimeSpan.MaxValue; //timeControlEnd.SetTimeStamp(timeControlEnd.Max); } }
// return the exact timespan on GOP static public TimeSpan ReturnTimeSpanOnGOP(ManifestTimingData data, TimeSpan ts) { var response = ts; ulong timestamp = (ulong)(ts.TotalSeconds * data.TimeScale); int i = 0; foreach (var t in data.TimestampList) { if (t < timestamp && i < (data.TimestampList.Count - 1) && timestamp < data.TimestampList[i + 1]) { response = TimeSpan.FromSeconds((double)t / (double)data.TimeScale); break; } i++; } return(response); }
public Subclipping(AMSClientV3 context, List <Asset> assetlist, Mainform mainform) { InitializeComponent(); this.Icon = Bitmaps.Azure_Explorer_ico; _amsClientV3 = context; _parentassetmanifestdata = new ManifestTimingData(); _selectedAssets = assetlist; _mainform = mainform; buttonShowEDL.Initialize(); buttonShowEDL.EDLChanged += ButtonShowEDL_EDLChanged; buttonShowEDL.Offset = new TimeSpan(0); // temp locator creation if (_selectedAssets.Count == 1 && MessageBox.Show("A temporary clear locator of 1 hour is going to be created to access content timing information. It will be deleted when you close the subclipping window.", "Locator creation", MessageBoxButtons.OKCancel, MessageBoxIcon.Information) == DialogResult.OK) { try { _tempStreamingLocator = Task.Run(() => AssetInfo.CreateTemporaryOnDemandLocatorAsync(_selectedAssets.First(), _amsClientV3)).GetAwaiter().GetResult(); } catch { } } if (_selectedAssets.Count == 1 && _selectedAssets.FirstOrDefault() != null) // one asset only { var myAsset = assetlist.FirstOrDefault(); textBoxAssetName.Text = myAsset.Name; // let's try to read asset timing _parentassetmanifestdata = Task.Run(() => AssetInfo.GetManifestTimingDataAsync(myAsset, _amsClientV3, _tempStreamingLocator?.Name)).GetAwaiter().GetResult(); labelDiscountinuity.Visible = _parentassetmanifestdata.DiscontinuityDetected; if (!_parentassetmanifestdata.Error) // we were able to read asset timings and not live { _timescale = timeControlStart.TimeScale = timeControlEnd.TimeScale = _parentassetmanifestdata.TimeScale; timeControlStart.ScaledFirstTimestampOffset = timeControlEnd.ScaledFirstTimestampOffset = _parentassetmanifestdata.TimestampOffset; buttonShowEDL.Offset = timeControlStart.GetOffSetAsTimeSpan(); textBoxOffset.Text = _parentassetmanifestdata.TimestampOffset.ToString(); labelOffset.Visible = textBoxOffset.Visible = true; textBoxFilterTimeScale.Text = _timescale.ToString(); textBoxFilterTimeScale.Visible = labelAssetTimescale.Visible = true; timeControlStart.Max = timeControlEnd.Max = _parentassetmanifestdata.AssetDuration; labelassetduration.Visible = textBoxAssetDuration.Visible = true; textBoxAssetDuration.Text = timeControlStart.Max.ToString(@"d\.hh\:mm\:ss") + (_parentassetmanifestdata.IsLive ? " (LIVE)" : ""); // let set duration and active track bat timeControlStart.TotalDuration = timeControlEnd.TotalDuration = _parentassetmanifestdata.AssetDuration; timeControlStart.DisplayTrackBar = true; timeControlEnd.DisplayTrackBar = true; timeControlEnd.SetTimeStamp(timeControlEnd.Max); } else // one asset but not able to read asset timings { timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = false; timeControlStart.TimeScale = timeControlEnd.TimeScale = _timescale; timeControlStart.Max = timeControlEnd.Max = TimeSpan.MaxValue; //timeControlEnd.SetTimeStamp(timeControlEnd.Max); } } else // several assets { groupBoxTrimming.Enabled = panelAssetInfo.Visible = false; // no trimming and no asset info radioButtonAssetFilter.Enabled = false; // no asset filter option timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = false; timeControlStart.TimeScale = timeControlEnd.TimeScale = _timescale; timeControlStart.Max = timeControlEnd.Max = TimeSpan.MaxValue; //timeControlEnd.SetTimeStamp(timeControlEnd.Max); } }
private void DynManifestFilter_Load(object sender, EventArgs e) { _parentassetmanifestdata = new ManifestTimingData(); tabControl1.TabPages.Remove(tabPageTRRaw); FillComboBoxImportFilters(_parentAsset); timeControlDVR.TotalDuration = TimeSpan.FromHours(24); timeControlDVR.Max = TimeSpan.FromHours(24); ///////////////////////////////////////////// // New Global Filter ///////////////////////////////////////////// if (_filterToDisplay == null && _parentAsset == null) { newfilter = true; isGlobalFilter = true; tabControl1.TabPages.Remove(tabPageInformation); _filter_presentationtimerange = new PresentationTimeRange(); filtertracks = new List <ExFilterTrack>(); timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = false; _timescale = timeControlStart.TimeScale = timeControlEnd.TimeScale = timeControlDVR.TimeScale = _filter_presentationtimerange.Timescale; textBoxFilterTimeScale.Text = (_filter_presentationtimerange.Timescale == null) ? "(default)" : _filter_presentationtimerange.Timescale.ToString(); } ///////////////////////////////////////////// // Existing Global Filter ///////////////////////////////////////////// else if (_filterToDisplay != null && _parentAsset == null) { newfilter = false; isGlobalFilter = true; DisplayFilterInfo(); _filter_name = _filterToDisplay.Name; _filter_presentationtimerange = _filterToDisplay.PresentationTimeRange; filtertracks = ConvertFilterTracksToInternalVar(_filterToDisplay.Tracks); _timescale = _filterToDisplay.PresentationTimeRange.Timescale; timeControlStart.TimeScale = timeControlEnd.TimeScale = timeControlDVR.TimeScale = _timescale; buttonOk.Text = "Update Filter"; buttonOk.Enabled = true; // we can enable the button toolTip1.SetToolTip(this.buttonOk, "It can take up to 2 minutes for streaming endpoint to refresh the rules"); textBoxFilterName.Enabled = false; // no way to change the filter name textBoxFilterName.Text = _filter_name; timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = false; checkBoxStartTime.Checked = _filter_presentationtimerange.StartTimestamp != null; checkBoxEndTime.Checked = _filter_presentationtimerange.EndTimestamp != null; checkBoxDVRWindow.Checked = _filter_presentationtimerange.PresentationWindowDuration != null; checkBoxLiveBackoff.Checked = _filter_presentationtimerange.LiveBackoffDuration != null; timeControlStart.SetScaledTimeStamp(_filter_presentationtimerange.StartTimestamp); timeControlEnd.SetScaledTimeStamp(_filter_presentationtimerange.EndTimestamp); timeControlDVR.SetTimeStamp(_filter_presentationtimerange.PresentationWindowDuration ?? TimeSpan.FromMinutes(2)); // we don't want to pass the max value to the control (overflow) TimeSpan backoff = _filter_presentationtimerange.LiveBackoffDuration ?? new TimeSpan(0); numericUpDownBackoffSeconds.Value = Convert.ToDecimal(backoff.TotalSeconds); } ///////////////////////////////////////////// // New Asset Filter ///////////////////////////////////////////// else if (_filterToDisplay == null && _parentAsset != null) { newfilter = true; isGlobalFilter = false; tabControl1.TabPages.Remove(tabPageInformation); _filter_presentationtimerange = new PresentationTimeRange(); filtertracks = new List <ExFilterTrack>(); labelFilterTitle.Text = "Asset Filter"; textBoxAssetName.Visible = true; labelassetname.Visible = true; textBoxAssetName.Text = _parentAsset != null ? _parentAsset.Name : string.Empty; // let's try to read asset timing _parentassetmanifestdata = AssetInfo.GetManifestTimingData(_parentAsset); if (!_parentassetmanifestdata.Error) // we were able to read asset timings and not live { // timescale _timescale = timeControlStart.TimeScale = timeControlEnd.TimeScale = timeControlDVR.TimeScale = _parentassetmanifestdata.TimeScale; timeControlStart.ScaledFirstTimestampOffset = timeControlEnd.ScaledFirstTimestampOffset = _parentassetmanifestdata.TimestampOffset; textBoxOffset.Text = _parentassetmanifestdata.TimestampOffset.ToString(); labelOffset.Visible = textBoxOffset.Visible = true; // let's disable trackbars if this is live (duration is not fixed) timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = !_parentassetmanifestdata.IsLive; TimeSpan duration = _parentassetmanifestdata.AssetDuration; textBoxAssetDuration.Text = duration.ToString(@"d\.hh\:mm\:ss"); labelassetduration.Visible = textBoxAssetDuration.Visible = true; textBoxFilterName.Text = "filter" + new Random().Next(9999).ToString(); if (!_parentassetmanifestdata.IsLive) // Not a live content { // let set duration and active track bat timeControlStart.TotalDuration = timeControlEnd.TotalDuration = timeControlDVR.TotalDuration = _parentassetmanifestdata.AssetDuration; timeControlDVR.TotalDuration = TimeSpan.FromHours(24); timeControlStart.Max = timeControlEnd.Max = duration; timeControlEnd.SetTimeStamp(timeControlEnd.Max); } else { textBoxAssetDuration.Text += " (LIVE)"; } if (_subclipconfig != null && _subclipconfig.Trimming) // user used the subclip UI before and timings are passed { timeControlStart.SetTimeStamp(_subclipconfig.StartTimeForAssetFilter - timeControlStart.GetOffSetAsTimeSpan()); timeControlEnd.SetTimeStamp(_subclipconfig.EndTimeForAssetFilter - timeControlStart.GetOffSetAsTimeSpan()); checkBoxStartTime.Checked = checkBoxEndTime.Checked = true; textBoxFilterName.Text = "subclip" + new Random().Next(9999).ToString(); } } else // not able to read asset timings { timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = false; timeControlStart.TimeScale = timeControlEnd.TimeScale = timeControlDVR.TimeScale = _timescale; timeControlStart.Max = timeControlEnd.Max = timeControlDVR.Max = TimeSpan.MaxValue; timeControlEnd.SetTimeStamp(timeControlEnd.Max); labelassetduration.Visible = textBoxAssetDuration.Visible = false; } } ///////////////////////////////////////////// // Existing Asset Filter ///////////////////////////////////////////// else if (_filterToDisplay != null && _parentAsset != null) { newfilter = false; isGlobalFilter = false; DisplayFilterInfo(); _filter_name = _filterToDisplay.Name; _filter_presentationtimerange = _filterToDisplay.PresentationTimeRange; filtertracks = ConvertFilterTracksToInternalVar(_filterToDisplay.Tracks); _timescale = _filterToDisplay.PresentationTimeRange.Timescale; buttonOk.Text = "Update Filter"; buttonOk.Enabled = true; // we can enable the button toolTip1.SetToolTip(this.buttonOk, "It can take up to 2 minutes for streaming endpoint to refresh the rules"); labelFilterTitle.Text = "Asset Filter"; textBoxAssetName.Visible = true; labelassetname.Visible = true; textBoxAssetName.Text = _parentAsset != null ? _parentAsset.Name : string.Empty; textBoxFilterName.Enabled = false; // no way to change the filter name textBoxFilterName.Text = _filter_name; // let's try to read asset timing _parentassetmanifestdata = AssetInfo.GetManifestTimingData(_parentAsset); _timescale = timeControlStart.TimeScale = timeControlEnd.TimeScale = timeControlDVR.TimeScale = _filterToDisplay.PresentationTimeRange.Timescale; if (!_parentassetmanifestdata.Error && _timescale == _parentassetmanifestdata.TimeScale) // we were able to read asset timings and timescale between manifest and existing asset match { // let's disable trackbars if this is live (duration is not fixed) timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = !_parentassetmanifestdata.IsLive; timeControlStart.ScaledFirstTimestampOffset = timeControlEnd.ScaledFirstTimestampOffset = _parentassetmanifestdata.TimestampOffset; textBoxOffset.Text = _parentassetmanifestdata.TimestampOffset.ToString(); labelOffset.Visible = textBoxOffset.Visible = true; TimeSpan duration = _parentassetmanifestdata.AssetDuration; textBoxAssetDuration.Text = duration.ToString(@"d\.hh\:mm\:ss"); labelassetduration.Visible = textBoxAssetDuration.Visible = true; if (!_parentassetmanifestdata.IsLive) { timeControlStart.Max = timeControlEnd.Max = duration; // let set duration and active track bat timeControlStart.TotalDuration = timeControlEnd.TotalDuration = duration; } else { textBoxAssetDuration.Text += " (LIVE)"; } } else // not able to read asset timings or mismatch in timescale { timeControlStart.DisplayTrackBar = timeControlEnd.DisplayTrackBar = timeControlDVR.DisplayTrackBar = false; timeControlStart.Max = timeControlEnd.Max = TimeSpan.MaxValue; labelassetduration.Visible = textBoxAssetDuration.Visible = false; } checkBoxStartTime.Checked = _filter_presentationtimerange.StartTimestamp != null; checkBoxEndTime.Checked = _filter_presentationtimerange.EndTimestamp != null; checkBoxDVRWindow.Checked = _filter_presentationtimerange.PresentationWindowDuration != null; checkBoxLiveBackoff.Checked = _filter_presentationtimerange.LiveBackoffDuration != null; timeControlStart.SetScaledTimeStamp(_filter_presentationtimerange.StartTimestamp); timeControlEnd.SetScaledTimeStamp(_filter_presentationtimerange.EndTimestamp); // we don't want to pass the max value to the control (overflow) timeControlDVR.SetTimeStamp(_filter_presentationtimerange.PresentationWindowDuration ?? TimeSpan.FromMinutes(2)); // we don't want to pass the max value to the control (overflow) TimeSpan backoff = _filter_presentationtimerange.LiveBackoffDuration ?? new TimeSpan(0); numericUpDownBackoffSeconds.Value = Convert.ToDecimal(backoff.TotalSeconds); } // Common code textBoxFilterTimeScale.Text = (_timescale == null) ? "(default)" : _timescale.ToString(); // dataPropertyType dataPropertyType = new DataTable(); dataPropertyType.Columns.Add(new DataColumn("Value", typeof(string))); dataPropertyType.Columns.Add(new DataColumn("Description", typeof(string))); dataPropertyType.Rows.Add(FilterTrackType.Audio.ToString(), FilterTrackType.Audio.ToString()); dataPropertyType.Rows.Add(FilterTrackType.Video.ToString(), FilterTrackType.Video.ToString()); dataPropertyType.Rows.Add(FilterTrackType.Text.ToString(), FilterTrackType.Text.ToString()); // FilterPropertyFourCCValue dataPropertyFourCC = new DataTable(); dataPropertyFourCC.Columns.Add(new DataColumn("Value", typeof(string))); dataPropertyFourCC.Columns.Add(new DataColumn("Description", typeof(string))); dataPropertyFourCC.Rows.Add(FilterPropertyFourCCValue.avc1, FilterPropertyFourCCValue.avc1); dataPropertyFourCC.Rows.Add(FilterPropertyFourCCValue.ec3, FilterPropertyFourCCValue.ec3); dataPropertyFourCC.Rows.Add(FilterPropertyFourCCValue.mp4a, FilterPropertyFourCCValue.mp4a); dataPropertyFourCC.Rows.Add(FilterPropertyFourCCValue.mp4v, FilterPropertyFourCCValue.mp4v); // dataProperty dataProperty = new DataTable(); dataProperty.Columns.Add(new DataColumn("Property", typeof(string))); dataProperty.Columns.Add(new DataColumn("Description", typeof(string))); dataProperty.Rows.Add(FilterProperty.Type, FilterProperty.Type); dataProperty.Rows.Add(FilterProperty.Bitrate, FilterProperty.Bitrate); dataProperty.Rows.Add(FilterProperty.FourCC, FilterProperty.FourCC); dataProperty.Rows.Add(FilterProperty.Language, FilterProperty.Language); dataProperty.Rows.Add(FilterProperty.Name, FilterProperty.Name); // dataOperator dataOperator = new DataTable(); dataOperator.Columns.Add(new DataColumn("Operator", typeof(string))); dataOperator.Columns.Add(new DataColumn("Description", typeof(string))); dataOperator.Rows.Add(FilterTrackCompareOperator.Equal.ToString(), FilterTrackCompareOperator.Equal.ToString()); dataOperator.Rows.Add(FilterTrackCompareOperator.NotEqual.ToString(), FilterTrackCompareOperator.NotEqual.ToString()); var columnProperty = new DataGridViewComboBoxColumn(); columnProperty.DataSource = dataProperty; columnProperty.ValueMember = "Property"; columnProperty.DisplayMember = "Description"; dataGridViewTracks.Columns.Add(columnProperty); var columnOperator = new DataGridViewComboBoxColumn(); columnOperator.DataSource = dataOperator; columnOperator.ValueMember = "Operator"; columnOperator.DisplayMember = "Description"; dataGridViewTracks.Columns.Add(columnOperator); var columnValue = new DataGridViewTextBoxColumn(); dataGridViewTracks.Columns.Add(columnValue); moreinfoprofilelink.Links.Add(new LinkLabel.Link(0, moreinfoprofilelink.Text.Length, Constants.LinkHowIMoreInfoDynamicManifest)); RefreshTracks(); CheckIfErrorTimeControls(); UpdateDurationText(); }
static public ManifestTimingData GetManifestTimingData(CloudMediaContext context, IAsset asset, TraceWriter log) // Parse the manifest and get data from it { ManifestTimingData response = new ManifestTimingData() { IsLive = false, Error = false, TimestampOffset = 0, TimestampList = new List <ulong>(), DiscontinuityDetected = false }; try { ILocator mytemplocator = null; Uri myuri = MediaServicesHelper.GetValidOnDemandURI(context, asset); if (myuri == null) { mytemplocator = MediaServicesHelper.CreatedTemporaryOnDemandLocator(asset); myuri = MediaServicesHelper.GetValidOnDemandURI(context, asset); } if (myuri != null) { log.Info($"Asset URI {myuri.ToString()}"); XDocument manifest = XDocument.Load(myuri.ToString()); //log.Info($"manifest {manifest}"); var smoothmedia = manifest.Element("SmoothStreamingMedia"); var videotrack = smoothmedia.Elements("StreamIndex").Where(a => a.Attribute("Type").Value == "video"); // TIMESCALE string timescalefrommanifest = smoothmedia.Attribute("TimeScale").Value; if (videotrack.FirstOrDefault().Attribute("TimeScale") != null) // there is timescale value in the video track. Let's take this one. { timescalefrommanifest = videotrack.FirstOrDefault().Attribute("TimeScale").Value; } ulong timescale = ulong.Parse(timescalefrommanifest); response.TimeScale = (ulong?)timescale; // Timestamp offset if (videotrack.FirstOrDefault().Element("c").Attribute("t") != null) { response.TimestampOffset = ulong.Parse(videotrack.FirstOrDefault().Element("c").Attribute("t").Value); } else { response.TimestampOffset = 0; // no timestamp, so it should be 0 } ulong totalduration = 0; ulong durationpreviouschunk = 0; ulong durationchunk; int repeatchunk; foreach (var chunk in videotrack.Elements("c")) { durationchunk = chunk.Attribute("d") != null?ulong.Parse(chunk.Attribute("d").Value) : 0; log.Info($"duration d {durationchunk}"); repeatchunk = chunk.Attribute("r") != null?int.Parse(chunk.Attribute("r").Value) : 1; log.Info($"repeat r {repeatchunk}"); if (chunk.Attribute("t") != null) { ulong tvalue = ulong.Parse(chunk.Attribute("t").Value); response.TimestampList.Add(tvalue); if (tvalue != response.TimestampOffset) { totalduration = tvalue - response.TimestampOffset; // Discountinuity ? We calculate the duration from the offset response.DiscontinuityDetected = true; // let's flag it } } else { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk); } totalduration += durationchunk * (ulong)repeatchunk; for (int i = 1; i < repeatchunk; i++) { response.TimestampList.Add(response.TimestampList[response.TimestampList.Count() - 1] + durationchunk); } durationpreviouschunk = durationchunk; } response.TimestampEndLastChunk = response.TimestampList[response.TimestampList.Count() - 1] + durationpreviouschunk; if (smoothmedia.Attribute("IsLive") != null && smoothmedia.Attribute("IsLive").Value == "TRUE") { // Live asset.... No duration to read (but we can read scaling and compute duration if no gap) response.IsLive = true; response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } else { totalduration = ulong.Parse(smoothmedia.Attribute("Duration").Value); response.AssetDuration = TimeSpan.FromSeconds((double)totalduration / ((double)timescale)); } } else { response.Error = true; } if (mytemplocator != null) { mytemplocator.Delete(); } } catch (Exception ex) { response.Error = true; } return(response); }