internal static Subtitle LoadMatroskaSSA(MatroskaTrackInfo matroskaSubtitleInfo, string fileName, SubtitleFormat format, List<MatroskaSubtitle> sub)
        {
            var subtitle = new Subtitle { Header = matroskaSubtitleInfo.CodecPrivate };
            var lines = subtitle.Header.Trim().SplitToLines().ToList();

            var footer = new StringBuilder();
            var comments = new Subtitle();
            if (!string.IsNullOrEmpty(matroskaSubtitleInfo.CodecPrivate))
            {
                bool footerOn = false;
                foreach (string line in lines)
                {
                    if (footerOn)
                    {
                        footer.AppendLine(line);
                    }
                    else if (line.Trim() == "[Events]")
                    {
                    }
                    else if (line.Trim() == "[Fonts]" || line.Trim() == "[Graphics]")
                    {
                        footerOn = true;
                        footer.AppendLine();
                        footer.AppendLine();
                        footer.AppendLine(line);
                    }
                    else if (line.StartsWith("Comment:", StringComparison.Ordinal))
                    {
                        var arr = line.Split(',');
                        if (arr.Length > 3)
                        {
                            arr = arr[1].Split(new[] { ':', '.' });
                            if (arr.Length == 4)
                            {
                                int hour;
                                int min;
                                int sec;
                                int ms;
                                if (int.TryParse(arr[0], out hour) && int.TryParse(arr[1], out min) && int.TryParse(arr[2], out sec) && int.TryParse(arr[3], out ms))
                                {
                                    comments.Paragraphs.Add(new Paragraph(new TimeCode(hour, min, sec, ms * 10), new TimeCode(0, 0, 0, 0), line));
                                }
                            }
                        }
                    }
                }
            }

            const string headerFormat = "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
            if (!subtitle.Header.Contains("[Events]"))
            {
                subtitle.Header = subtitle.Header.Trim() + Environment.NewLine + Environment.NewLine + "[Events]" + Environment.NewLine + headerFormat + Environment.NewLine;
            }
            else
            {
                subtitle.Header = subtitle.Header.Remove(subtitle.Header.IndexOf("[Events]", StringComparison.Ordinal));
                subtitle.Header = subtitle.Header.Trim() + Environment.NewLine + Environment.NewLine + "[Events]" + Environment.NewLine + headerFormat + Environment.NewLine;
            }

            lines = subtitle.Header.Trim().SplitToLines().ToList();

            const string timeCodeFormat = "{0}:{1:00}:{2:00}.{3:00}"; // h:mm:ss.cc
            foreach (var mp in sub)
            {
                var p = new Paragraph(string.Empty, mp.Start, mp.End);
                string start = string.Format(timeCodeFormat, p.StartTime.Hours, p.StartTime.Minutes, p.StartTime.Seconds, p.StartTime.Milliseconds / 10);
                string end = string.Format(timeCodeFormat, p.EndTime.Hours, p.EndTime.Minutes, p.EndTime.Seconds, p.EndTime.Milliseconds / 10);

                // MKS contains this: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text
                lines.AddRange(from cp in comments.Paragraphs where cp.StartTime.TotalMilliseconds <= p.StartTime.TotalMilliseconds select cp.Text);

                for (int commentIndex = comments.Paragraphs.Count - 1; commentIndex >= 0; commentIndex--)
                {
                    var cp = comments.Paragraphs[commentIndex];
                    if (cp.StartTime.TotalMilliseconds <= p.StartTime.TotalMilliseconds)
                    {
                        comments.Paragraphs.RemoveAt(commentIndex);
                    }
                }

                string text = mp.Text.Replace(Environment.NewLine, "\\N");
                int idx = text.IndexOf(',') + 1;
                if (idx > 0 && idx < text.Length)
                {
                    text = text.Remove(0, idx); // remove ReadOrder
                    idx = text.IndexOf(',');
                    text = text.Insert(idx, "," + start + "," + end);
                    lines.Add("Dialogue: " + text);
                }
            }

            lines.AddRange(comments.Paragraphs.Select(cp => cp.Text));

            lines.AddRange(footer.ToString().SplitToLines());

            format.LoadSubtitle(subtitle, lines, fileName);
            return subtitle;
        }
        internal static SubtitleFormat LoadMatroskaTextSubtitle(MatroskaTrackInfo matroskaSubtitleInfo, MatroskaFile matroska, List<MatroskaSubtitle> sub, Subtitle subtitle)
        {
            if (subtitle == null)
            {
                throw new ArgumentNullException("subtitle");
            }

            subtitle.Paragraphs.Clear();

            var isSsa = false;
            SubtitleFormat format = new SubRip();
            if (matroskaSubtitleInfo.CodecPrivate.Contains("[script info]", StringComparison.OrdinalIgnoreCase))
            {
                if (matroskaSubtitleInfo.CodecPrivate.Contains("[V4 Styles]", StringComparison.OrdinalIgnoreCase))
                {
                    format = new SubStationAlpha();
                }
                else
                {
                    format = new AdvancedSubStationAlpha();
                }

                isSsa = true;
            }

            if (isSsa)
            {
                foreach (var p in LoadMatroskaSSA(matroskaSubtitleInfo, matroska.Path, format, sub).Paragraphs)
                {
                    subtitle.Paragraphs.Add(p);
                }

                if (!string.IsNullOrEmpty(matroskaSubtitleInfo.CodecPrivate))
                {
                    bool eventsStarted = false;
                    bool fontsStarted = false;
                    bool graphicsStarted = false;
                    var header = new StringBuilder();
                    foreach (string line in matroskaSubtitleInfo.CodecPrivate.Replace(Environment.NewLine, "\n").Split('\n'))
                    {
                        if (!eventsStarted && !fontsStarted && !graphicsStarted)
                        {
                            header.AppendLine(line);
                        }

                        if (line.TrimStart().StartsWith("dialog:", StringComparison.OrdinalIgnoreCase))
                        {
                            eventsStarted = true;
                            fontsStarted = false;
                            graphicsStarted = false;
                        }
                        else if (line.Trim().Equals("[events]", StringComparison.OrdinalIgnoreCase))
                        {
                            eventsStarted = true;
                            fontsStarted = false;
                            graphicsStarted = false;
                        }
                        else if (line.Trim().Equals("[fonts]", StringComparison.OrdinalIgnoreCase))
                        {
                            eventsStarted = false;
                            fontsStarted = true;
                            graphicsStarted = false;
                        }
                        else if (line.Trim().Equals("[graphics]", StringComparison.OrdinalIgnoreCase))
                        {
                            eventsStarted = false;
                            fontsStarted = false;
                            graphicsStarted = true;
                        }
                    }

                    subtitle.Header = header.ToString().TrimEnd();
                    if (!subtitle.Header.Contains("[events]", StringComparison.OrdinalIgnoreCase))
                    {
                        subtitle.Header += Environment.NewLine + Environment.NewLine + "[Events]" + Environment.NewLine;
                    }
                }
            }
            else
            {
                foreach (var p in sub)
                {
                    subtitle.Paragraphs.Add(new Paragraph(p.Text, p.Start, p.End));
                }
            }

            subtitle.Renumber();
            return format;
        }
        private static SubtitleFormat ConvertToMatroska(MatroskaFile matroska, MatroskaTrackInfo track, SubtitleFormat format, Subtitle sub, string fileName, List<MatroskaTrackInfo> tracks, string toFormat, IList<SubtitleFormat> formats, string offset, Encoding targetEncoding, string outputFolder, int count, bool overwrite, string pacCodePage, double? targetFrameRate, ref int converted, ref int errors, ref bool done)
        {
            var ss = matroska.GetSubtitle(track.TrackNumber, null);
            format = Utilities.LoadMatroskaTextSubtitle(track, matroska, ss, sub);
            string newFileName = fileName;
            if (tracks.Count > 1)
            {
                newFileName = fileName
                    .Insert(fileName.Length - 4, "_" + track.TrackNumber + "_" + track.Language
                        .Replace("?", string.Empty)
                        .Replace("!", string.Empty)
                        .Replace("*", string.Empty)
                        .Replace(",", string.Empty)
                        .Replace("/", string.Empty)
                        .Trim());
            }

            bool isSubStationAlpha =
                format.GetType() == typeof(AdvancedSubStationAlpha) ||
                format.GetType() == typeof(SubStationAlpha);

            if (isSubStationAlpha)
            {
                if (toFormat.ToLower() != AdvancedSubStationAlpha.NameOfFormat.ToLower().Replace(" ", string.Empty) &&
                    toFormat.ToLower() != SubStationAlpha.NameOfFormat.ToLower().Replace(" ", string.Empty))
                {
                    foreach (SubtitleFormat subtitleFormat in formats)
                    {
                        if (subtitleFormat
                            .Name
                            .Replace(" ", string.Empty)
                            .Equals(toFormat, StringComparison.OrdinalIgnoreCase) ||
                            subtitleFormat
                                .Name
                                .Replace(" ", string.Empty)
                                .Equals(toFormat.Replace(" ", string.Empty), StringComparison.OrdinalIgnoreCase))
                        {
                            format.RemoveNativeFormatting(sub, subtitleFormat);
                            break;
                        }
                    }
                }
            }

            BatchConvertSave(toFormat, offset, targetEncoding, outputFolder, count, ref converted, ref errors, formats, newFileName, sub, format, overwrite, pacCodePage, targetFrameRate);
            done = true;
            return format;
        }