Пример #1
0
        /// <summary>
        /// Convert an int with value 24, 25, 29 and 30 to its corresponding <see cref="SmpteFrameRate"/> value.
        /// </summary>
        /// <param name="frameRate">The frameRate value.</param>
        /// <returns>Returns <see cref="SmpteFrameRate.None"/> of no conversion could be made.</returns>
        public static SmpteFrameRate ToFrameRate(int frameRate)
        {
            SmpteFrameRate fps = SmpteFrameRate.None;

            if (Enum.IsDefined(typeof(SmpteFrameRate), frameRate))
            {
                fps = (SmpteFrameRate)frameRate;
            }

            //switch (frameRate)
            //{
            //    case 24:
            //        fps = SmpteFrameRate.Smpte24;
            //        break;
            //    case 25:
            //        fps = SmpteFrameRate.Smpte25;
            //        break;
            //    case 29:
            //        fps = SmpteFrameRate.SmpteDrop30;
            //        break;
            //    case 30:
            //        fps = SmpteFrameRate.Smpte30;
            //        break;
            //}

            return(fps);
        }
Пример #2
0
        /// <summary>
        /// Constructs a new instance based on <paramref name="microseconds"/>.
        /// </summary>
        /// <param name="microseconds">A number of microseconds.</param>
        /// <param name="fps">The frame rate to use.</param>
        /// <param name="subFramesPerFrame">The number of sub-frames in a frame. Can be zero.</param>
        /// <returns>Never returns null.</returns>
        public static SmpteTime FromMicroseconds(long microseconds, SmpteFrameRate fps, int subFramesPerFrame)
        {
            ThrowIfInvalidFrameRate(fps);

            int   frameRate      = FromFrameRate(fps);
            float microsPerFrame = GetMicrosecondsPerFrame(frameRate);

            int hour = (int)(microseconds / MicrosecondsInHour);

            microseconds -= hour * MicrosecondsInHour;
            int minutes = (int)(microseconds / MicrosecondsInMinute);

            microseconds -= minutes * MicrosecondsInMinute;
            int seconds = (int)(microseconds / MicrosecondsInSecond);

            microseconds -= seconds * MicrosecondsInSecond;
            int frames = (int)(microseconds / microsPerFrame);

            microseconds -= (int)(frames * microsPerFrame);

            int subFrames = 0;

            if (subFramesPerFrame > 0)
            {
                subFrames = (int)(microseconds / (microsPerFrame / subFramesPerFrame));
            }

            return(new SmpteTime(hour, minutes, seconds, frames, subFrames, fps, subFramesPerFrame));
        }
Пример #3
0
 /// <summary>
 /// Sets the smpte frame rate.
 /// </summary>
 /// <param name="frameRate">The frame rate.</param>
 public void SetSmpteFrameRate(SmpteFrameRate frameRate)
 {
     if (frameRate != SmpteFrameRate.Unknown)
     {
         this.currentSmpteFrameRate = frameRate;
     }
 }
        private static bool IsSetFrameRateCommand(string str, out SmpteFrameRate frameRate)
        {
            var prefix = "SetFrameRate ";

            if (!str.StartsWith(prefix))
            {
                frameRate = SmpteFrameRate.Unknown;
                return(false);
            }

            var remainder = str.Length > prefix.Length ? str.Substring(prefix.Length).Trim() : string.Empty;

            var lookupDictionary = new Dictionary <string, SmpteFrameRate>();

            lookupDictionary.Add("Smpte2398", SmpteFrameRate.Smpte2398);
            lookupDictionary.Add("Smpte24", SmpteFrameRate.Smpte24);
            lookupDictionary.Add("Smpte25", SmpteFrameRate.Smpte25);
            lookupDictionary.Add("Smpte2997Drop", SmpteFrameRate.Smpte2997Drop);
            lookupDictionary.Add("Smpte2997NonDrop", SmpteFrameRate.Smpte2997NonDrop);
            lookupDictionary.Add("Smpte30", SmpteFrameRate.Smpte30);

            if (lookupDictionary.ContainsKey(remainder))
            {
                frameRate = lookupDictionary[remainder];
                return(true);
            }
            frameRate = SmpteFrameRate.Unknown;
            return(true);
        }
Пример #5
0
        private static TimeCode GetLooseTimeCode(string timecode, SmpteFrameRate frameRate)
        {
            if (IsTimeCode(timecode))
            {
                return(GetTimeCode(timecode, frameRate));
            }

            //We know there is at least one colon.
            var colonParts = timecode.Split(new char[] { ':', '.', ';' }).Select(p => int.Parse(p)).ToArray();
            var cpl        = colonParts.Length;

            if (cpl < 2 || cpl > 4)
            {
                throw new InvalidOperationException();
            }

            var newColonParts = new int[4];

            colonParts.CopyTo(newColonParts, 4 - cpl);

            var str    = string.Join(":", newColonParts.Select(p => p.ToString("00")));
            var retval = new TimeCode(str, frameRate);

            return(retval);
        }
Пример #6
0
        /// <summary>
        /// Reads the manifest and tries to extract the frame rate.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The event args instance containing event data.</param>
        private void OnOpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                StreamReader reader   = new StreamReader(e.Result);
                string       manifest = reader.ReadToEnd().ToUpper(CultureInfo.InvariantCulture);
                reader.Close();

                int termIndex       = manifest.IndexOf(CodecPrivateDataTerm);
                int termIndexLength = termIndex + CodecPrivateDataTerm.Length;

                int    endTermIndex     = manifest.IndexOf(@"""", termIndexLength);
                string codecPrivateData = manifest.Substring(termIndexLength, endTermIndex - termIndexLength);

                try
                {
                    SmpteFrameRate frameRate = this.GetFrameRate(codecPrivateData);
                    this.OnGetFrameRateCompleted(frameRate);
                }
                catch (Exception ex)
                {
                    this.logger.Log("WVC1CodecPrivateDataParser", ex);
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Gets the string value of the frame rate.
        /// </summary>
        /// <param name="frameRate">SmpteFrameRate value.</param>
        /// <returns>The string corresponding to the frame rate.</returns>
        private string GetSmpteFrameRateValue(SmpteFrameRate frameRate)
        {
            switch (frameRate)
            {
            case SmpteFrameRate.Smpte2997NonDrop:
                return(this.SmpteTimeCodeValues[0]);

            case SmpteFrameRate.Smpte2997Drop:
                return(this.SmpteTimeCodeValues[1]);

            case SmpteFrameRate.Smpte30:
                return(this.SmpteTimeCodeValues[2]);

            case SmpteFrameRate.Smpte25:
                return(this.SmpteTimeCodeValues[3]);

            case SmpteFrameRate.Smpte24:
                return(this.SmpteTimeCodeValues[4]);

            case SmpteFrameRate.Smpte2398:
                return(this.SmpteTimeCodeValues[5]);

            case SmpteFrameRate.Unknown:
                return(this.SmpteTimeCodeValues[6]);

            default:
                return(this.SmpteTimeCodeValues[6]);
            }
        }
Пример #8
0
 /// <summary>
 /// Throws an exception if the specified <paramref name="fps"/> is not supported.
 /// </summary>
 /// <param name="fps">Must not be <see cref="SmpteFrameRate.None"/> or <see cref="SmpteFrameRate.SmpteDrop30"/>.</param>
 private static void ThrowIfInvalidFrameRate(SmpteFrameRate fps)
 {
     // drop-30 is not supported.
     if (fps == SmpteFrameRate.None || fps == SmpteFrameRate.SmpteDrop30)
     {
         throw new ArgumentException("Invalid Frames per Second value.", nameof(fps));
     }
 }
Пример #9
0
        /// <summary>
        /// Raises the FrameRateParsed event.
        /// </summary>
        /// <param name="frameRate">The frame rate included on the event args data.</param>
        private void OnFrameRateParsed(SmpteFrameRate frameRate)
        {
            EventHandler <DataEventArgs <SmpteFrameRate> > handler = this.FrameRateParsed;

            if (handler != null)
            {
                handler(this, new DataEventArgs <SmpteFrameRate>(frameRate));
            }
        }
Пример #10
0
        public XmlAssetsDataParser(Func <IMetadataStrategy> metadataStrategyFactory, IConfigurationService configurationService, ICdnTokenGenerator cdnTokenGenerator)
        {
            this.metadataStrategyFactory = metadataStrategyFactory;
            this.cdnTokenGenerator       = cdnTokenGenerator;

            this.cdnSharedSecret           = configurationService.GetParameterValue(CdnSharedSecretSettingName);
            this.defaultCdnContentDuration = configurationService.GetParameterValueAsInt(DefaultCdnContentDurationSettingName) ?? 60 * 60 * 24 * 365;
            this.defaultFrameRate          = configurationService.GetDefaultFrameRate();
        }
Пример #11
0
        /// <summary>
        /// Raises the GetFrameCompleted event.
        /// </summary>
        /// <param name="frameRate">The frame rate.</param>
        private void OnGetFrameRateCompleted(SmpteFrameRate frameRate)
        {
            EventHandler <DataEventArgs <SmpteFrameRate> > completed = this.GetFrameRateCompleted;

            if (completed != null)
            {
                completed(this, new DataEventArgs <SmpteFrameRate>(frameRate));
            }
        }
Пример #12
0
        /// <summary>
        /// Sets the current smpte frame rate in video preview.
        /// </summary>
        /// <param name="frameRate">The frame rate.</param>
        public void SetCurrentSmpteFrameRate(SmpteFrameRate frameRate)
        {
            // IList<VideoPreview> videoPreviews = this.AssetsList.GetChildControls<VideoPreview>();
            IList <VideoPreviewTimeline> videoPreviews = this.AssetsList.GetChildControls <VideoPreviewTimeline>();

            foreach (VideoPreviewTimeline preview in videoPreviews)
            {
                preview.UpdateSmpteFrameRate(frameRate);
            }
        }
Пример #13
0
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        /// <param name="hour">Smpte hours.</param>
        /// <param name="minute">Smpte minutes.</param>
        /// <param name="second">Smpte seconds.</param>
        /// <param name="frame">Smpte frames.</param>
        /// <param name="fps">Smpte frames per second. Must not be <see cref="SmpteFrameRate.None"/> or <see cref="SmpteFrameRate.SmpteDrop30"/>.</param>
        public SmpteTime(int hour, int minute, int second, int frame, SmpteFrameRate fps)
        {
            ThrowIfInvalidFrameRate(fps);

            Hour            = hour;
            Minute          = minute;
            Second          = second;
            Frame           = frame;
            FramesPerSecond = fps;
        }
Пример #14
0
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        /// <param name="fps">Number of frames per second.</param>
        /// <param name="subsPerFrame">Number of sub-frames per frame. Can be zero.</param>
        public SmpteTimeBase(SmpteFrameRate fps, int subsPerFrame)
        {
            Check.IfArgumentOutOfRange(subsPerFrame, 0, int.MaxValue, "subsPerFrame");
            if (fps == SmpteFrameRate.None)
            {
                throw new ArgumentException("None is not a valid value.", "fps");
            }

            this.FramesPerSecond   = fps;
            this.SubFramesPerFrame = subsPerFrame;
        }
Пример #15
0
 /// <summary>
 /// init structure
 /// </summary>
 private void Init()
 {
     CustomProperties          = new Dictionary <string, string>();
     title                     = string.Empty;
     description               = string.Empty;
     thumbSource               = null;
     fileSize                  = 0;
     frameRate                 = SmpteFrameRate.Smpte30;
     width                     = 640;
     height                    = 480;
     offlineVideoBitrateInKbps = 0;
 }
        /// <summary>
        /// Parses a codec private data to get the frame rate.
        /// </summary>
        /// <param name="fourCC">The four-character code identifying data formats.</param>
        /// <param name="codecPrivateData">The codec private data to parse.</param>
        /// <returns>The frame rate.</returns>
        public SmpteFrameRate GetFrameRate(string fourCC, string codecPrivateData)
        {
            SmpteFrameRate   frameRate      = SmpteFrameRate.Unknown;
            IFrameRateParser frameRatePaser = null;

            if (this.frameRateParsers.TryGetValue(fourCC, out frameRatePaser))
            {
                frameRate = frameRatePaser.GetFrameRate(codecPrivateData);
            }

            return(frameRate);
        }
Пример #17
0
        /// <summary>
        /// Constructs a new instance.
        /// </summary>
        /// <param name="hour">Smpte hours.</param>
        /// <param name="minute">Smpte minutes.</param>
        /// <param name="second">Smpte seconds.</param>
        /// <param name="frame">Smpte frames.</param>
        /// <param name="subFrames">Smpte sub-frames.</param>
        /// <param name="fps">Smpte frames per second. Must not be <see cref="SmpteFrameRate.None"/> or <see cref="SmpteFrameRate.SmpteDrop30"/>.</param>
        /// <param name="subFramesPerFrame">The number of sub-frames in a frame. Can be zero.</param>
        public SmpteTime(int hour, int minute, int second, int frame, int subFrames, SmpteFrameRate fps, int subFramesPerFrame)
        {
            ThrowIfInvalidFrameRate(fps);

            this.Hour              = hour;
            this.Minute            = minute;
            this.Second            = second;
            this.Frame             = frame;
            this.SubFrames         = subFrames;
            this.FramesPerSecond   = fps;
            this.SubFramesPerFrame = subFramesPerFrame;
        }
Пример #18
0
        public static (TimeCode start, TimeCode end) GetTimeCodeLine(string line, SmpteFrameRate smpteFrameRate = SmpteFrameRate.Smpte25)
        {
            if (!IsTimecodeLine(line))
            {
                throw new InvalidOperationException();
            }
            var startStr = line.Substring(0, 12);
            var start    = FromString(startStr, smpteFrameRate);

            var endStr = line.Substring(17);
            var end    = FromString(endStr, smpteFrameRate);

            return(start : start, end : end);
        }
Пример #19
0
        private void ConfigureServices(SmpteFrameRate frameRate, double sectionDurationSeconds)
        {
            var serviceCollection = new ServiceCollection();

            serviceCollection.AddTransient <IMarkerSectionParser, MarkerSectionParser>();
            serviceCollection.AddTransient <IMarkersReader, MarkersReader>();
            serviceCollection.AddTransient <IMarkerMerger, MarkerMerger>();
            serviceCollection.Configure <MarkerMergerSettings>(settings =>
            {
                settings.FrameRate = frameRate;
                settings.SectionDurationSeconds = sectionDurationSeconds;
            });
            ServiceProvider = serviceCollection.BuildServiceProvider();
        }
Пример #20
0
        /// <summary>
        /// This method is invoked whenever any property in the SettingsViewPresentationModel
        /// changes. Based on the property modified, the same is published by invoking the
        /// corresponding EventHandler.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <seealso cref="PropertyChangedEventArgs"/> event args.</param>
        private void SettingsViewPresentationModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
            case "IsAspectRatio43Selected":
                this.eventAggregator.GetEvent <AspectRatioChangedEvent>().Publish(AspectRatio.Square);
                break;

            case "IsAspectRatio169Selected":
                this.eventAggregator.GetEvent <AspectRatioChangedEvent>().Publish(AspectRatio.Wide);
                break;

            case "SelectedSmpteTimeCode":
                SmpteFrameRate frameRate = this.GetSmpteFrameRateValue();
                this.projectService.GetCurrentProject().SmpteFrameRate = frameRate;
                this.eventAggregator.GetEvent <SmpteTimeCodeChangedEvent>().Publish(frameRate);
                break;

            case "SelectedStartTimeCode":
                TimeCode startTimeCode = new TimeCode(this.SelectedStartTimeCode, this.GetSmpteFrameRateValue());
                this.projectService.GetCurrentProject().StartTimeCode = startTimeCode;
                this.eventAggregator.GetEvent <StartTimeCodeChangedEvent>().Publish(startTimeCode);
                break;

            case "SelectedEditMode":
                EditMode editMode = this.GetEditModeValue();
                this.projectService.GetCurrentProject().RippleMode = editMode == EditMode.Ripple;
                this.eventAggregator.GetEvent <EditModeChangedEvent>().Publish(editMode);
                break;

            case "SelectedAutoSaveTimeInterval":
                this.projectService.GetCurrentProject().AutoSaveInterval = this.selectedAutoSaveTimeInterval;
                this.timer.Interval = new TimeSpan(0, this.selectedAutoSaveTimeInterval, 0);
                break;

            case "TreatGapAsError":
                this.UpdateSetting("TreatGapAsError", this.TreatGapAsError.ToString());
                this.eventAggregator.GetEvent <CheckedTreatGapAsErrorEvent>().Publish(this.TreatGapAsError);
                break;

            case "ProjectName":
                this.projectService.GetCurrentProject().Name = string.IsNullOrEmpty(this.ProjectName) ? null : this.projectName;
                break;
            }
        }
        public IEnumerable <Section> ReadFromFile(string filePath, SmpteFrameRate frameRate = SmpteFrameRate.Smpte25)
        {
            var str    = File.ReadAllText(filePath);
            var lines  = str.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
            var retval = new List <Section>();

            foreach (var line in lines)
            {
                var parts   = line.Split(new char[] { '\t' }, StringSplitOptions.None);
                var section = new Section
                {
                    In  = new TimeCode(parts[0], frameRate),
                    Out = new TimeCode(parts[1], frameRate)
                };
                retval.Add(section);
            }
            return(retval);
        }
        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);
            }
        }
Пример #23
0
        public static TimeCode FromString(string str, SmpteFrameRate smpteFrameRate = SmpteFrameRate.Smpte25)
        {
            var pattern = "^(?<hours>[0-9]{2})\\:(?<minutes>[0-9]{2})\\:(?<seconds>[0-9]{2}),(?<fraction>[0-9]{3})$";
            var match   = Regex.Match(str, pattern);

            if (!match.Success)
            {
                throw new InvalidOperationException();
            }

            var hours    = int.Parse(match.Groups["hours"].Value);
            var minutes  = int.Parse(match.Groups["minutes"].Value);
            var seconds  = int.Parse(match.Groups["seconds"].Value);
            var fraction = int.Parse(match.Groups["fraction"].Value);
            var fps      = 25.0;
            var frames   = (int)(((double)fraction) / 1000.0 * fps);

            return(new TimeCode(hours, minutes, seconds, frames, smpteFrameRate));
        }
Пример #24
0
        /// <summary>
        /// Validates that the string provided is a valid TimeCode.
        /// </summary>
        /// <param name="timeCode">String that is the time code.</param>
        /// <param name="smpteRate">Current smpte rate.</param>
        /// <exception cref="InputValidationException"></exception>
        private static void ValidateStartTimeCode(string timeCode, SmpteFrameRate smpteRate)
        {
            try
            {
                if (!TimeCode.ValidateSmpte12MTimecode(timeCode))
                {
                    throw new InputValidationException(Resources.Resources.InvalidStartTimeCode);
                }

                if (TimeCode.FromAbsoluteTime(DefaultTimelineDuration, smpteRate) <= new TimeCode(timeCode, smpteRate))
                {
                    throw new InputValidationException(string.Format(CultureInfo.InvariantCulture, Resources.Resources.InvalidStartTimeCodeValue, TimeCode.FromAbsoluteTime(DefaultTimelineDuration, smpteRate)));
                }
            }
            catch (Exception ex)
            {
                throw new InputValidationException(ex.Message, ex);
            }
        }
        public IEnumerable <Section> Convert(string avidDSFilePath, SmpteFrameRate smpteFrameRate)
        {
            var dsText = File.ReadAllText(avidDSFilePath);
            var avidDSDocumentReader = new AvidDSDocumentReader();
            var avidDSDocument       = avidDSDocumentReader.Read(dsText);

            var retval = new List <Section>();

            foreach (var dsComponent in avidDSDocument.Components)
            {
                var outTC1 = new TimeCode(dsComponent.Out, smpteFrameRate);
                var outTC  = TimeCode.FromFrames(outTC1.TotalFrames - 1, smpteFrameRate);
                retval.Add(new Section
                {
                    In  = new TimeCode(dsComponent.In, smpteFrameRate),
                    Out = outTC
                });
            }
            return(retval.ToArray());
        }
Пример #26
0
        public static long GetFramerateDivisor(SmpteFrameRate framerate)
        {
            switch (framerate)
            {
            case SmpteFrameRate.Smpte2398:
                return(10594584000);

            case SmpteFrameRate.Smpte24:
                throw new NotImplementedException();

            case SmpteFrameRate.Smpte25:
                return(10160640000);

            case SmpteFrameRate.Smpte2997Drop:
                return(8475667200);

            default:
                throw new NotImplementedException();

                //////10594584000 is 23.97 fps, 10160640000 is 25fps, and 8475667200 is 29.9 fps.
            }
        }
Пример #27
0
        /// <summary>
        /// Converts a frame rate value to an integer.
        /// </summary>
        /// <param name="fps">The frame rate value.</param>
        /// <returns>Returns zero if <see cref="SmpteFrameRate.None"/> was specified.</returns>
        public static int FromFrameRate(SmpteFrameRate fps)
        {
            int frameRate = (int)fps;

            //switch (fps)
            //{
            //    case SmpteFrameRate.Smpte24:
            //        frameRate = 24;
            //        break;
            //    case SmpteFrameRate.Smpte25:
            //        frameRate = 25;
            //        break;
            //    case SmpteFrameRate.SmpteDrop30:
            //        frameRate = 29;
            //        break;
            //    case SmpteFrameRate.Smpte30:
            //        frameRate = 30;
            //        break;
            //}

            return(frameRate);
        }
Пример #28
0
        /// <summary>
        /// Initializes a new instance of the <see cref="PlayerControl"/> class.
        /// </summary>
        public PlayerControl()
        {
            InitializeComponent();
            this.timer = new DispatcherTimer {
                Interval = new TimeSpan(0, 0, 1)
            };
            this.timer.Tick   += this.Timer_Tick;
            this.positionTimer = new DispatcherTimer {
                Interval = new TimeSpan(0, 0, 0, 0, 15)
            };
            this.positionTimer.Tick   += this.PositionTimer_Tick;
            this.currentSmpteFrameRate = SmpteFrameRate.Smpte2997NonDrop;
            this.externalManifestFiles = new List <Uri>();

            if (!DesignerProperties.IsInDesignMode)
            {
                this.logger = ServiceLocator.Current.GetInstance(typeof(ILogger)) as ILogger;
                this.codecPrivateDataParser = ServiceLocator.Current.GetInstance(typeof(ICodecPrivateDataParser)) as ICodecPrivateDataParser;
                if (this.codecPrivateDataParser != null)
                {
                    this.codecPrivateDataParser.GetFrameRateCompleted += (sender, args) => this.OnFrameRateParsed(args.Data);
                }
            }
        }
Пример #29
0
 /// <summary>
 /// init structure
 /// </summary>
 private void Init()
 {
     CustomProperties = new Dictionary<string, string>();
     title = string.Empty;
     description = string.Empty;
     thumbSource = null;
     fileSize = 0;
     frameRate = SmpteFrameRate.Smpte30;
     width = 640;
     height = 480;
     offlineVideoBitrateInKbps = 0;
 }
 /// <summary>
 /// Updates the smpte frame rate.
 /// </summary>
 /// <param name="frameRate">The frame rate.</param>
 private void UpdateSmpteFrameRate(SmpteFrameRate frameRate)
 {
     this.View.SetCurrentSmpteFrameRate(frameRate);
 }
Пример #31
0
        /* #endregion Private Static Fields */
        /* #region Private Static Methods */
        private static TimeCode GetTimeCode(string timecode, SmpteFrameRate frameRate)
        {
            var tc = new TimeCode(timecode, frameRate);

            return(tc);
        }