public string GetText(MatroskaTrackInfo matroskaTrackInfo) { var data = GetData(matroskaTrackInfo); if (data != null) { // terminate string at first binary zero - https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#terminating-elements // https://github.com/SubtitleEdit/subtitleedit/issues/2732 int max = data.Length; for (int i = 0; i < max; i++) { if (data[i] == 0) { max = i; break; } } var text = System.Text.Encoding.UTF8.GetString(data, 0, max); // normalize "new line" to current OS default - also see https://github.com/SubtitleEdit/subtitleedit/issues/2838 text = text.Replace("\\N", Environment.NewLine); text = string.Join(Environment.NewLine, text.SplitToLines()); return(text); } return(string.Empty); }
/// <summary> /// Get data, if contentEncodingType == 0, then data is compressed with zlib /// </summary> /// <param name="matroskaTrackInfo"></param> /// <returns>Data byte array (uncompressed)</returns> public byte[] GetData(MatroskaTrackInfo matroskaTrackInfo) { if (matroskaTrackInfo.ContentEncodingType != MatroskaTrackInfo.ContentEncodingTypeCompression || // no compression (matroskaTrackInfo.ContentEncodingScope & MatroskaTrackInfo.ContentEncodingScopeTracks) == 0) // tracks not compressed { return(Data); } var outStream = new MemoryStream(); var outZStream = new zlib.ZOutputStream(outStream); var inStream = new MemoryStream(Data); byte[] buffer; try { MatroskaTrackInfo.CopyStream(inStream, outZStream); buffer = new byte[outZStream.TotalOut]; outStream.Position = 0; outStream.Read(buffer, 0, buffer.Length); } finally { outZStream.Close(); inStream.Close(); } return(buffer); }
public string GetText(MatroskaTrackInfo matroskaTrackInfo) { var data = GetData(matroskaTrackInfo); if (data != null) { return(System.Text.Encoding.UTF8.GetString(data).Replace("\\N", Environment.NewLine)); } return(string.Empty); }
public string GetText(MatroskaTrackInfo matroskaTrackInfo) { var data = GetData(matroskaTrackInfo); if (data != null) { // terminate string at first binary zero - https://github.com/Matroska-Org/ebml-specification/blob/master/specification.markdown#terminating-elements // https://github.com/SubtitleEdit/subtitleedit/issues/2732 int max = data.Length; for (int i = 0; i < max; i++) { if (data[i] == 0) { max = i; break; } } return(System.Text.Encoding.UTF8.GetString(data, 0, max).Replace("\\N", Environment.NewLine)); } return(string.Empty); }
public static Subtitle LoadMatroskaSSA(MatroskaTrackInfo matroskaSubtitleInfo, string fileName, SubtitleFormat format, List<MatroskaSubtitle> sub) { var subtitle = new Subtitle { Header = matroskaSubtitleInfo.CodecPrivate }; var lines = new List<string>(); foreach (string l in subtitle.Header.Trim().SplitToLines()) lines.Add(l); 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 = new List<string>(); foreach (string l in subtitle.Header.Trim().SplitToLines()) lines.Add(l); 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 for (int commentIndex = 0; commentIndex < comments.Paragraphs.Count; commentIndex++) { var cp = comments.Paragraphs[commentIndex]; if (cp.StartTime.TotalMilliseconds <= p.StartTime.TotalMilliseconds) lines.Add(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); } } for (int commentIndex = 0; commentIndex < comments.Paragraphs.Count; commentIndex++) { var cp = comments.Paragraphs[commentIndex]; lines.Add(cp.Text); } foreach (string l in footer.ToString().SplitToLines()) lines.Add(l); format.LoadSubtitle(subtitle, lines, fileName); return subtitle; }
public 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; }