示例#1
0
        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);
        }
示例#3
0
        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);
            }
        }
示例#4
0
        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);
        }