Пример #1
0
        /// <summary>
        /// Add a subtitle track.
        /// The Source track is set based on the following order. If null, it will skip to the next option.
        ///   1. Passed in Subitle param
        ///   2. First preferred Subtitle from source
        ///   3. First subtitle from source.
        /// Will not add a subtitle if the source has none.
        /// </summary>
        /// <param name="subtitle">
        /// The subtitle. Use null to add preferred, or first from source (based on user preference)
        /// </param>
        private void Add(Subtitle subtitle)
        {
            string preferred =
                this.UserSettingService.GetUserSetting <string>(UserSettingConstants.NativeLanguageForSubtitles);

            Subtitle source = subtitle ??
                              ((this.SourceTracks != null)
                                   ? (this.SourceTracks.FirstOrDefault(l => l.Language == preferred) ??
                                      this.SourceTracks.FirstOrDefault(s => s.SubtitleType != SubtitleType.ForeignAudioSearch))
                                   : null);

            if (source == null)
            {
                source = ForeignAudioSearchTrack;
            }

            SubtitleTrack track = new SubtitleTrack
            {
                SubtitleType = SubtitleType.VobSub,
                SourceTrack  = source,
            };

            if ((source.SubtitleType == SubtitleType.PGS || source.SubtitleType == SubtitleType.VobSub) &&
                this.Task != null &&
                (this.Task.OutputFormat == OutputFormat.Mp4 || this.Task.OutputFormat == OutputFormat.M4V || this.Task.OutputFormat == OutputFormat.av_mp4))
            {
                this.SelectBurnedInTrack(track);
            }

            this.Task.SubtitleTracks.Add(track);
        }
Пример #2
0
        /// <summary>
        /// Add a subtitle track.
        /// The Source track is set based on the following order. If null, it will skip to the next option.
        ///   1. Passed in Subitle param
        ///   2. First preferred Subtitle from source
        ///   3. First subtitle from source.
        /// Will not add a subtitle if the source has none.
        /// </summary>
        /// <param name="subtitle">
        /// The subtitle. Use null to add preferred, or first from source (based on user preference)
        /// </param>
        private void Add(Subtitle subtitle)
        {
            Subtitle source = subtitle
                              ?? ((this.SourceTracks != null)
                                      ? (this.SourceTracks.FirstOrDefault(l => l.Language == this.GetPreferredSubtitleTrackLanguage())
                                         ?? this.SourceTracks.FirstOrDefault(
                                             s => s.SubtitleType != SubtitleType.ForeignAudioSearch))
                                      : null);

            if (source == null)
            {
                source = ForeignAudioSearchTrack;
            }

            SubtitleTrack track = new SubtitleTrack
            {
                SubtitleType = SubtitleType.VobSub,
                SourceTrack  = source,
            };

            if ((source.SubtitleType == SubtitleType.PGS || source.SubtitleType == SubtitleType.VobSub || source.SubtitleType == SubtitleType.ForeignAudioSearch) &&
                this.Task != null &&
                (this.Task.OutputFormat == OutputFormat.Mp4 || this.Task.OutputFormat == OutputFormat.M4V))
            {
                if (track.CanBeBurned)
                {
                    track.Burned = true;
                    this.SetBurnedToFalseForAllExcept(track);
                }
            }

            this.Task.SubtitleTracks.Add(track);
        }
Пример #3
0
        /// <summary>
        /// Helper method that creates a user friendly type from the internal interop structure.
        /// </summary>
        /// <param name="s">TrackDescriptionStructure from interop</param>
        /// <returns>public TrackDescription to be consumed by the user</returns>
        internal static MediaTrack Build(this MediaTrackStructure s)
        {
            AudioTrack    audioTrack    = default;
            VideoTrack    videoTrack    = default;
            SubtitleTrack subtitleTrack = default;

            switch (s.TrackType)
            {
            case TrackType.Audio:
                audioTrack = MarshalUtils.PtrToStructure <AudioTrack>(s.TrackData);
                break;

            case TrackType.Video:
                videoTrack = MarshalUtils.PtrToStructure <VideoTrack>(s.TrackData);
                break;

            case TrackType.Text:
                subtitleTrack = MarshalUtils.PtrToStructure <SubtitleTrackStructure>(s.TrackData).Build();
                break;

            case TrackType.Unknown:
                break;
            }

            return(new MediaTrack(s.Codec,
                                  s.OriginalFourcc,
                                  s.Id,
                                  s.TrackType,
                                  s.Profile,
                                  s.Level,
                                  new MediaTrackData(audioTrack, videoTrack, subtitleTrack), s.Bitrate,
                                  s.Language.FromUtf8(),
                                  s.Description.FromUtf8()));
        }
Пример #4
0
        /// <summary>
        /// Import an SRT File.
        /// </summary>
        public void Import()
        {
            OpenFileDialog dialog = new OpenFileDialog
            {
                Filter          = "SRT files (*.srt)|*.srt",
                CheckFileExists = true,
                Multiselect     = true
            };

            dialog.ShowDialog();

            foreach (var srtFile in dialog.FileNames)
            {
                SubtitleTrack track = new SubtitleTrack
                {
                    SrtFileName  = Path.GetFileNameWithoutExtension(srtFile),
                    SrtOffset    = 0,
                    SrtCharCode  = "UTF-8",
                    SrtLang      = "English",
                    SubtitleType = SubtitleType.SRT,
                    SrtPath      = srtFile
                };
                this.Task.SubtitleTracks.Add(track);
            }
        }
Пример #5
0
        private string GetSubtitleDescription()
        {
            if (this.Task.AudioTracks.Count == 0)
            {
                return(ResourcesUI.SummaryView_NoSubtitleTracks);
            }

            StringBuilder desc = new StringBuilder();

            if (this.Task.SubtitleTracks.Count >= 1)
            {
                SubtitleTrack track1       = this.Task.SubtitleTracks[0];
                string        subtitleName = track1.IsSrtSubtitle ? track1.SrtFileName : track1.SourceTrack.ToString();
                string        burned       = track1.Burned ? ", " + ResourcesUI.SummaryView_Burned : string.Empty;
                desc.AppendLine(string.Format("{0}{1}", subtitleName, burned));
            }

            if (this.Task.SubtitleTracks.Count >= 2)
            {
                SubtitleTrack track2       = this.Task.SubtitleTracks[1];
                string        subtitleName = track2.IsSrtSubtitle ? track2.SrtFileName : track2.SourceTrack.ToString();
                string        burned       = track2.Burned ? ", " + ResourcesUI.SummaryView_Burned : string.Empty;
                desc.AppendLine(string.Format("{0}{1}", subtitleName, burned));
            }

            if (this.Task.SubtitleTracks.Count > 2)
            {
                desc.AppendLine(string.Format("+ {0} {1}", this.Task.SubtitleTracks.Count - 2, ResourcesUI.SummaryView_AdditionalSubtitleTracks));
            }

            return(desc.ToString().Trim());
        }
Пример #6
0
        /// <summary>
        /// Add a Subtitle track.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void BtnAddSubTrackClick(object sender, EventArgs e)
        {
            // Logic
            string forcedVal  = check_forced.CheckState == CheckState.Checked ? "Yes" : "No";
            string defaultSub = check_default.CheckState == CheckState.Checked ? "Yes" : "No";
            string burnedVal  = check_burned.CheckState == CheckState.Checked &&
                                (drp_subtitleTracks.Text.Contains("(VOBSUB)") || drp_subtitleTracks.Text.Contains("(SSA)"))
                                   ? "Yes"
                                   : "No";
            string srtCode = "-", srtLangVal = "-", srtPath = "-", srtFile = "-";
            int    srtOffsetMs = 0;

            if (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt"))
            {
                srtFiles.TryGetValue(drp_subtitleTracks.SelectedItem.ToString(), out srtPath);
                srtFile     = drp_subtitleTracks.SelectedItem.ToString();
                srtLangVal  = srt_lang.SelectedItem.ToString();
                srtCode     = srt_charcode.SelectedItem.ToString();
                srtOffsetMs = (int)srt_offset.Value;
                if (defaultSub == "Yes")
                {
                    this.SetDefaultToOffForAllSRTTracks();
                }
            }
            else
            {
                if (defaultSub == "Yes")
                {
                    this.SetDefaultToOffForAllTracks();
                }
                if (burnedVal == "Yes")
                {
                    this.SetBurnedToOffForAllTracks();
                }
            }

            string trackName = (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt"))
                                   ? srtLangVal + " (" + srtFile + ")"
                                   : drp_subtitleTracks.SelectedItem.ToString();

            SubtitleTrack track = new SubtitleTrack
            {
                Track       = trackName,
                Forced      = check_forced.Checked,
                Burned      = check_burned.Checked,
                Default     = check_default.Checked,
                SrtLang     = srtLangVal,
                SrtCharCode = srtCode,
                SrtOffset   = srtOffsetMs,
                SrtPath     = srtPath,
                SrtFileName = srtFile
            };

            lv_subList.Items.Add(track.ListView);
            subList.Add(track);
        }
Пример #7
0
 /// <summary>
 /// Select the burned in track.
 /// </summary>
 /// <param name="subtitle">
 /// The subtitle.
 /// </param>
 public void SetBurnedToFalseForAllExcept(SubtitleTrack subtitle)
 {
     foreach (SubtitleTrack track in this.Task.SubtitleTracks)
     {
         if (track == subtitle)
         {
             continue; // Skip the track the user selected.
         }
         track.Burned = false;
     }
     this.NotifyOfPropertyChange(() => this.Task);
 }
Пример #8
0
        /// <summary>
        /// Add a subtitle Track
        /// </summary>
        /// <param name="sender">
        /// The Sender
        /// </param>
        /// <param name="e">
        /// The Event Args
        /// </param>
        private void btn_addSubtitleTrack_Click(object sender, EventArgs e)
        {
            if (drp_subtitleTracks.SelectedItem == null)
            {
                MessageBox.Show("No Subtitle Track Selected.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            // Logic
            string srtCode = "-", srtLangVal = "-", srtPath = "-", srtFile = "-";
            int    srtOffsetMs = 0;

            // Make sure we only have 1 burned track. We'll always give the latest track added burned in.
            if (check_burned.Checked)
            {
                this.SetBurnedToOffForAllTracks();
            }

            // Make sure we only have 1 default track
            if (check_default.Checked)
            {
                this.SetDefaultToOffForAllTracks();
            }

            if (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt"))
            {
                srtFiles.TryGetValue(drp_subtitleTracks.SelectedItem.ToString(), out srtPath);
                srtFile     = drp_subtitleTracks.SelectedItem.ToString();
                srtLangVal  = srt_lang.SelectedItem.ToString();
                srtCode     = srt_charcode.SelectedItem.ToString();
                srtOffsetMs = (int)srt_offset.Value;
            }

            string trackName = (drp_subtitleTracks.SelectedItem.ToString().Contains(".srt"))
                                   ? srtLangVal + " (" + srtFile + ")"
                                   : drp_subtitleTracks.SelectedItem.ToString();

            SubtitleTrack track = new SubtitleTrack
            {
                Track       = trackName,
                Forced      = check_forced.Checked,
                Burned      = check_burned.Checked,
                Default     = check_default.Checked,
                SrtLang     = srtLangVal,
                SrtCharCode = srtCode,
                SrtOffset   = srtOffsetMs,
                SrtPath     = srtPath,
                SrtFileName = srtFile
            };

            lv_subList.Items.Add(track.ListView);
            subList.Add(track);
        }
Пример #9
0
        /// <summary>
        /// Select the default subtitle track.
        /// </summary>
        /// <param name="subtitle">
        /// The subtitle.
        /// </param>
        public void SelectDefaultTrack(SubtitleTrack subtitle)
        {
            foreach (SubtitleTrack track in this.Task.SubtitleTracks)
            {
                if (track == subtitle)
                {
                    continue; // Skip the track the user selected.
                }
                track.Default = false;
            }

            this.NotifyOfPropertyChange(() => this.Task);
        }
Пример #10
0
        public OKEFile StartMuxing(string path, MediaFile mediaFile)
        {
            List <string> input             = new List <string>();
            string        videoFps          = "";
            string        videoName         = "";
            string        timeCodeFile      = null;
            List <string> audioLanguages    = new List <string>();
            List <string> audioNames        = new List <string>();
            List <string> subtitleLanguages = new List <string>();
            List <string> subtitleNames     = new List <string>();

            foreach (var track in mediaFile.Tracks)
            {
                if (track.Info.MuxOption != MuxOption.Default && track.Info.MuxOption != MuxOption.Mka)
                {
                    continue;
                }
                switch (track.TrackType)
                {
                case TrackType.Audio:
                    AudioTrack audioTrack = track as AudioTrack;
                    audioLanguages.Add(audioTrack.Info.Language);
                    audioNames.Add(audioTrack.Info.Name);
                    break;

                case TrackType.Video:
                    VideoTrack videoTrack = track as VideoTrack;
                    VideoInfo  videoInfo  = track.Info as VideoInfo;
                    videoFps     = $"{videoInfo.FpsNum}/{videoInfo.FpsDen}";
                    videoName    = videoInfo.Name;
                    timeCodeFile = videoInfo.TimeCodeFile;
                    break;

                case TrackType.Subtitle:
                    SubtitleTrack subtitleTrack = track as SubtitleTrack;
                    subtitleLanguages.Add(subtitleTrack.Info.Language);
                    subtitleNames.Add(subtitleTrack.Info.Name);
                    break;
                }

                input.Add(track.File.GetFullPath());
            }

            this.StartMerge(input, path, videoFps, videoName, timeCodeFile, audioLanguages, audioNames, subtitleLanguages, subtitleNames);

            OKEFile outFile = new OKEFile(path);

            outFile.AddCRC32();

            return(outFile.Exists() ? outFile : null);
        }
Пример #11
0
        /// <summary>
        /// The Subtitle List selected index has changed
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void LbSubListSelectedIndexChanged(object sender, EventArgs e)
        {
            // Set the dropdown controls based on the selected item in the List.
            if (lv_subList.Items.Count != 0 && lv_subList.SelectedIndices.Count != 0)
            {
                SubtitleTrack track = subList[lv_subList.SelectedIndices[0]];

                int c = 0;
                if (lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text.ToLower().Contains(".srt"))
                // We have an SRT
                {
                    foreach (var item in drp_subtitleTracks.Items)
                    {
                        if (item.ToString() == track.SrtFileName)
                        {
                            drp_subtitleTracks.SelectedIndex = c;
                        }
                        c++;
                    }
                    srt_lang.SelectedItem     = track.SrtLang;
                    srt_offset.Value          = track.SrtOffset;
                    srt_charcode.SelectedItem = track.SrtCharCode;
                    check_default.CheckState  = track.Default ? CheckState.Checked : CheckState.Unchecked;
                    SubGroupBox.Text          = "Selected Track: " + track.Track;
                }
                else // We have Bitmap/CC
                {
                    foreach (var item in drp_subtitleTracks.Items)
                    {
                        if (item.ToString() == track.Track)
                        {
                            drp_subtitleTracks.SelectedIndex = c;
                        }
                        c++;
                    }
                    check_forced.CheckState  = track.Forced ? CheckState.Checked : CheckState.Unchecked;
                    check_burned.CheckState  = track.Burned ? CheckState.Checked : CheckState.Unchecked;
                    check_default.CheckState = track.Default ? CheckState.Checked : CheckState.Unchecked;
                    SubGroupBox.Text         = "Selected Track: " +
                                               lv_subList.Items[lv_subList.SelectedIndices[0]].SubItems[0].Text;
                }
            }
            else
            {
                SubGroupBox.Text = "Selected Track: None (Click \"Add\" to add another track to the list)";
            }
        }
Пример #12
0
        /// <summary>
        /// Add a subtitle track.
        /// The Source track is set based on the following order. If null, it will skip to the next option.
        ///   1. Passed in Subitle param
        ///   2. First preferred Subtitle from source
        ///   3. First subtitle from source.
        /// Will not add a subtitle if the source has none.
        /// </summary>
        /// <param name="subtitle">
        /// The subtitle. Use null to add preferred, or first from source (based on user preference)
        /// </param>
        private void Add(Subtitle subtitle)
        {
            Subtitle source = subtitle
                              ?? ((this.SourceTracks != null)
                                      ? (this.SourceTracks.FirstOrDefault(l => l.Language == this.GetPreferredSubtitleTrackLanguage())
                                         ?? this.SourceTracks.FirstOrDefault(
                                             s => s.SubtitleType != SubtitleType.ForeignAudioSearch))
                                      : null);

            if (source == null)
            {
                source = ForeignAudioSearchTrack;
            }

            SubtitleTrack track = new SubtitleTrack
            {
                SubtitleType = SubtitleType.VobSub,
                SourceTrack  = source,
            };

            // Burn-in Behaviours
            if (this.SubtitleBehaviours.SelectedBurnInBehaviour == SubtitleBurnInBehaviourModes.ForeignAudio ||
                this.SubtitleBehaviours.SelectedBurnInBehaviour == SubtitleBurnInBehaviourModes.ForeignAudioPreferred)
            {
                track.Burned = true;
                this.SetBurnedToFalseForAllExcept(track);
            }

            // For MP4, PGS Subtitles must be burned in.
            if (!track.Burned && (source.SubtitleType == SubtitleType.PGS) && this.Task != null && this.Task.OutputFormat == OutputFormat.Mp4)
            {
                if (track.CanBeBurned)
                {
                    track.Burned = true;
                    this.SetBurnedToFalseForAllExcept(track);
                }
            }

            var encodeTask = this.Task;

            if (encodeTask != null)
            {
                encodeTask.SubtitleTracks.Add(track);
            }
        }
Пример #13
0
 private IEnumerable <ISubtitleTrack> PrepareSubtitleTracks(FileInfo fileInfo, IEnumerable <TrackInfoOutput> trackModels)
 {
     foreach (var model in trackModels)
     {
         var track = new SubtitleTrack
         {
             ID          = model.ID,
             FileInfo    = fileInfo,
             StreamOrder = model.StreamOrder,
             Format      = model.Format,
             CodecId     = model.CodecID,
             Duration    = model.Duration,
             Bitrate     = model.Bitrate,
             Language    = model.Language
         };
         yield return(track);
     }
 }
Пример #14
0
        /// <summary>
        /// Helper method that creates a user friendly type from the internal interop structure.
        /// </summary>
        /// <param name="s">TrackDescriptionStructure from interop</param>
        /// <returns>public TrackDescription to be consumed by the user</returns>
        internal static MediaTrack Build(this MediaTrackStructure s)
        {
            AudioTrack    audioTrack    = default;
            VideoTrack    videoTrack    = default;
            SubtitleTrack subtitleTrack = default;

            switch (s.TrackType)
            {
            case TrackType.Audio:
                audioTrack = MarshalUtils.PtrToStructure <AudioTrack>(s.TrackData);
                break;

            case TrackType.Video:
                videoTrack = MarshalUtils.PtrToStructure <VideoTrack>(s.TrackData);
                break;

            case TrackType.Text:
                subtitleTrack = MarshalUtils.PtrToStructure <SubtitleTrackStructure>(s.TrackData).Build();
                break;

            case TrackType.Unknown:
                break;
            }

            var language = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Language) as string;
            var des      = Utf8StringMarshaler.GetInstance().MarshalNativeToManaged(s.Description) as string;

            return(new MediaTrack(s.Codec,
                                  s.OriginalFourcc,
                                  s.Id,
                                  s.TrackType,
                                  s.Profile,
                                  s.Level,
                                  new MediaTrackData(audioTrack, videoTrack, subtitleTrack), s.Bitrate,
                                  language,
                                  des));
        }
Пример #15
0
        /// <summary>
        /// Add a subtitle track.
        /// The Source track is set based on the following order. If null, it will skip to the next option.
        ///   1. Passed in Subitle param
        ///   2. First preferred Subtitle from source
        ///   3. First subtitle from source.
        /// Will not add a subtitle if the source has none.
        /// </summary>
        /// <param name="subtitle">
        /// The subtitle. Use null to add preferred, or first from source (based on user preference)
        /// </param>
        private void Add(Subtitle subtitle)
        {
            string preferred =
                this.UserSettingService.GetUserSetting <string>(UserSettingConstants.NativeLanguageForSubtitles);

            Subtitle source = subtitle ??
                              ((this.SourceTracks != null)
                                   ? (this.SourceTracks.FirstOrDefault(l => l.Language == preferred) ??
                                      this.SourceTracks.FirstOrDefault(s => s.SubtitleType != SubtitleType.ForeignAudioSearch))
                                   : null);

            if (source == null)
            {
                source = ForeignAudioSearchTrack;
            }

            SubtitleTrack track = new SubtitleTrack
            {
                SubtitleType = SubtitleType.VobSub,
                SourceTrack  = source,
            };

            this.Task.SubtitleTracks.Add(track);
        }
Пример #16
0
        /// <summary>
        /// Encode and play a sample
        /// </summary>
        public void Play()
        {
            try
            {
                this.IsEncoding = true;
                if (File.Exists(this.CurrentlyPlaying))
                {
                    File.Delete(this.CurrentlyPlaying);
                }
            }
            catch (Exception)
            {
                this.IsEncoding = false;
                this.errorService.ShowMessageBox(Resources.StaticPreview_UnableToDeletePreview,
                                                 Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
            }

            if (this.Task == null || string.IsNullOrEmpty(Task.Source))
            {
                this.errorService.ShowMessageBox(Resources.StaticPreviewViewModel_ScanFirst,
                                                 Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            EncodeTask encodeTask = new EncodeTask(this.Task)
            {
                PreviewEncodeDuration = this.Duration,
                PreviewEncodeStartAt  = this.SelectedPreviewImage,
                PointToPointMode      = PointToPointMode.Preview
            };

            // Filename handling.
            if (string.IsNullOrEmpty(encodeTask.Destination))
            {
                string filename = Path.ChangeExtension(Path.GetTempFileName(), encodeTask.OutputFormat == OutputFormat.Mkv ? "m4v" : "mkv");
                encodeTask.Destination = filename;
                this.CurrentlyPlaying  = filename;
            }
            else
            {
                string directory       = Path.GetDirectoryName(encodeTask.Destination) ?? string.Empty;
                string filename        = Path.GetFileNameWithoutExtension(encodeTask.Destination);
                string extension       = Path.GetExtension(encodeTask.Destination);
                string previewFilename = string.Format("{0}_preview{1}", filename, extension);
                string previewFullPath = Path.Combine(directory, previewFilename);
                encodeTask.Destination = previewFullPath;
                this.CurrentlyPlaying  = previewFullPath;
            }

            // Setup the encode task as a preview encode
            encodeTask.IsPreviewEncode       = true;
            encodeTask.PreviewEncodeStartAt  = this.SelectedPreviewImage + 1;
            encodeTask.PreviewEncodeDuration = this.Duration;

            SubtitleTrack scanTrack = null;

            foreach (var track in encodeTask.SubtitleTracks)
            {
                if (track.SourceTrack != null && track.SourceTrack.SubtitleType == SubtitleType.ForeignAudioSearch)
                {
                    scanTrack = track;
                    break;
                }
            }

            if (scanTrack != null)
            {
                encodeTask.SubtitleTracks.Remove(scanTrack);
            }

            QueueTask task = new QueueTask(encodeTask, HBConfigurationFactory.Create(), this.ScannedSource.ScanPath);

            ThreadPool.QueueUserWorkItem(this.CreatePreview, task);
        }
Пример #17
0
 /// <summary>
 /// Remove a Track
 /// </summary>
 /// <param name="track">
 /// The track.
 /// </param>
 public void Remove(SubtitleTrack track)
 {
     this.Task.SubtitleTracks.Remove(track);
 }
Пример #18
0
 internal MediaTrackData(AudioTrack audio, VideoTrack video, SubtitleTrack subtitle)
 {
     Audio    = audio;
     Video    = video;
     Subtitle = subtitle;
 }
Пример #19
0
 //==========================================================================
 internal SubtitleStream(SubtitleTrack subtitleTrack)
     : base(subtitleTrack)
 {
     // ...
 }
Пример #20
0
 //==========================================================================
 internal SubtitleStream(SubtitleTrack subtitleTrack)
     : base(subtitleTrack)
 {
     // ...
 }