From b744ab2cd469c1976946740b071ba5202e104b09 Mon Sep 17 00:00:00 2001 From: niksedk Date: Thu, 23 Dec 2010 06:11:10 +0000 Subject: [PATCH] Added support for reading VobSub inside Matroska git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@189 99eadd0c-20b8-1223-b5c4-2a2b2df33de2 --- src/Forms/Main.cs | 161 ++++++++++++++++++----------- src/Logic/VideoFormats/Matroska.cs | 132 ++++++++++++++++++++++- src/Logic/VobSub/Idx.cs | 8 +- 3 files changed, 234 insertions(+), 67 deletions(-) diff --git a/src/Forms/Main.cs b/src/Forms/Main.cs index ecca8c622..deb7f722d 100644 --- a/src/Forms/Main.cs +++ b/src/Forms/Main.cs @@ -391,8 +391,10 @@ namespace Nikse.SubtitleEdit.Forms private void Main_Load(object sender, EventArgs e) { + splitContainer1.Panel1MinSize = 525; splitContainer1.Panel2MinSize = 250; - splitContainer1.Panel1MinSize = 250; + splitContainerMain.Panel1MinSize = 250; + splitContainerMain.Panel2MinSize = 250; if (Configuration.Settings.General.StartListViewWidth < 250) Configuration.Settings.General.StartListViewWidth = (Width / 3) * 2; @@ -485,7 +487,6 @@ namespace Nikse.SubtitleEdit.Forms toolStripMenuItemImportDvdSubtitles.Text = _language.Menu.File.ImportOcrFromDvd; toolStripMenuItemSubIdx.Text = _language.Menu.File.ImportOcrVobSubSubtitle; - //toolStripMenuItemImportBluRaySup.Visible = false; //TODO: add blu ray sup import/ocr toolStripMenuItemImportBluRaySup.Text = _language.Menu.File.ImportBluRaySupFile; matroskaImportStripMenuItem.Text = _language.Menu.File.ImportSubtitleFromMatroskaFile; @@ -3990,16 +3991,13 @@ namespace Nikse.SubtitleEdit.Forms if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_VOBSUB") { - MessageBox.Show("VobSub subtitles inside Matroska not supported - sorry!"); - if (_fileName == "123") - LoadVobSubFromMatroska(matroskaSubtitleInfo, fileName); + LoadVobSubFromMatroska(matroskaSubtitleInfo, fileName); return; } if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_HDMV/PGS") { - MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!"); - if (_fileName == "123") - LoadBluRaySubFromMatroska(matroskaSubtitleInfo, fileName); +// MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!"); + LoadBluRaySubFromMatroska(matroskaSubtitleInfo, fileName); return; } else if (matroskaSubtitleInfo.CodecPrivate.ToLower().Contains("[script info]")) @@ -4085,8 +4083,24 @@ namespace Nikse.SubtitleEdit.Forms } } + public static void CopyStream(System.IO.Stream input, System.IO.Stream output) + { + byte[] buffer = new byte[2000]; + int len; + while ((len = input.Read(buffer, 0, 2000)) > 0) + { + output.Write(buffer, 0, len); + } + output.Flush(); + } + private void LoadVobSubFromMatroska(MatroskaSubtitleInfo matroskaSubtitleInfo, string fileName) { + if (matroskaSubtitleInfo.ContentEncodingType == 1) + { + MessageBox.Show("Encrypted vobsub content not supported"); + } + bool isValid; var matroska = new Matroska(); @@ -4096,46 +4110,52 @@ namespace Nikse.SubtitleEdit.Forms List sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid); Cursor.Current = Cursors.Default; - if (isValid) { MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile); _subtitleListViewIndex = -1; - _subtitle.Paragraphs.Clear(); - List mergedVobSubPacks = new List(); - List vobSubPacks = new List(); - List palette = new List(); - - palette = null; + Nikse.SubtitleEdit.Logic.VobSub.Idx idx = new Logic.VobSub.Idx(matroskaSubtitleInfo.CodecPrivate.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)); foreach (SubtitleSequence p in sub) - { - SubPicture sp = new SubPicture(p.BinaryData); - MessageBox.Show(sp.SubPictureDateSize.ToString()); - MessageBox.Show(sp.ImageDisplayArea.ToString()); - - int length = p.BinaryData.Length; - if (length > 5000) - MessageBox.Show("Large"); - mergedVobSubPacks.Add(new VobSubMergedPack(p.BinaryData, TimeSpan.FromMilliseconds(p.StartMilliseconds), 32, null)); + if (matroskaSubtitleInfo.ContentEncodingType == 0) // compressed with zlib + { + MemoryStream outStream = new MemoryStream(); + ComponentAce.Compression.Libs.zlib.ZOutputStream outZStream = new ComponentAce.Compression.Libs.zlib.ZOutputStream(outStream); + MemoryStream inStream = new MemoryStream(p.BinaryData); + byte[] buffer; + try + { + CopyStream(inStream, outZStream); + buffer = new byte[outZStream.TotalOut]; + outStream.Position = 0; + outStream.Read(buffer, 0, buffer.Length); + } + finally + { + outStream.Close(); + outZStream.Close(); + inStream.Close(); + } + mergedVobSubPacks.Add(new VobSubMergedPack(buffer, TimeSpan.FromMilliseconds(p.StartMilliseconds), 32, null)); + } + else + { + mergedVobSubPacks.Add(new VobSubMergedPack(p.BinaryData, TimeSpan.FromMilliseconds(p.StartMilliseconds), 32, null)); + } } + var formSubOcr = new VobSubOcr(); - formSubOcr.Initialize(mergedVobSubPacks, palette, Configuration.Settings.VobSubOcr); + formSubOcr.Initialize(mergedVobSubPacks, idx.Palette, Configuration.Settings.VobSubOcr); if (formSubOcr.ShowDialog(this) == DialogResult.OK) { - MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); - + ResetSubtitle(); _subtitle.Paragraphs.Clear(); - SetCurrentFormat(new SubRip().FriendlyName); _subtitle.WasLoadedWithFrameNumbers = false; - _subtitle.CalculateFrameNumbersFromTimeCodes(CurrentFrameRate); foreach (Paragraph p in formSubOcr.SubtitleFromOcr.Paragraphs) - { _subtitle.Paragraphs.Add(p); - } ShowSource(); SubtitleListview1.Fill(_subtitle, _subtitleAlternate); @@ -4144,7 +4164,8 @@ namespace Nikse.SubtitleEdit.Forms SubtitleListview1.FirstVisibleIndex = -1; SubtitleListview1.SelectIndexAndEnsureVisible(0); - _fileName = string.Empty; + _fileName = Path.GetFileNameWithoutExtension(fileName); + _converted = true; Text = Title; Configuration.Settings.Save(); @@ -4154,6 +4175,11 @@ namespace Nikse.SubtitleEdit.Forms private void LoadBluRaySubFromMatroska(MatroskaSubtitleInfo matroskaSubtitleInfo, string fileName) { + if (matroskaSubtitleInfo.ContentEncodingType == 1) + { + MessageBox.Show("Encrypted vobsub content not supported"); + } + bool isValid; var matroska = new Matroska(); @@ -4163,22 +4189,51 @@ namespace Nikse.SubtitleEdit.Forms List sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid); Cursor.Current = Cursors.Default; - if (isValid) { MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile); _subtitleListViewIndex = -1; _subtitle.Paragraphs.Clear(); - + List subtitles = new List(); + StringBuilder log = new StringBuilder(); foreach (SubtitleSequence p in sub) { - int length = p.BinaryData.Length; - if (length > 5000) - MessageBox.Show("Large"); + byte[] buffer; + if (matroskaSubtitleInfo.ContentEncodingType == 0) // compressed with zlib + { + MemoryStream outStream = new MemoryStream(); + ComponentAce.Compression.Libs.zlib.ZOutputStream outZStream = new ComponentAce.Compression.Libs.zlib.ZOutputStream(outStream); + MemoryStream inStream = new MemoryStream(p.BinaryData); + try + { + CopyStream(inStream, outZStream); + buffer = new byte[outZStream.TotalOut]; + outStream.Position = 0; + outStream.Read(buffer, 0, buffer.Length); + } + finally + { + outStream.Close(); + outZStream.Close(); + inStream.Close(); + } + } + else + { + buffer = p.BinaryData; + } + if (buffer.Length > 100) + { + MemoryStream ms = new MemoryStream(buffer); + var list = BluRaySupParser.ParseBluRaySup(ms, log); + foreach (var sup in list) + subtitles.Add(sup); + ms.Close(); + } } var formSubOcr = new VobSubOcr(); -// formSubOcr.Initialize(mergedVobSubPacks, palette, Configuration.Settings.VobSubOcr); + formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr); if (formSubOcr.ShowDialog(this) == DialogResult.OK) { MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); @@ -6397,32 +6452,14 @@ namespace Nikse.SubtitleEdit.Forms Configuration.Settings.VideoControls.LastActiveTab = "Adjust"; } - if (toolStripButtonToogleVideo.Checked && toolStripButtonToogleWaveForm.Checked ) - { + if (toolStripButtonToogleWaveForm.Checked ) AudioWaveForm.Left = tabControlButtons.Left + tabControlButtons.Width + 5; - //panelVideoPlayer.Left = AudioWaveForm.Left + AudioWaveForm.Width + 5; - } - else if (toolStripButtonToogleVideo.Checked) - { - //panelVideoPlayer.Left = tabControlButtons.Left + tabControlButtons.Width + 5; - } - else - { - AudioWaveForm.Left = tabControlButtons.Left + tabControlButtons.Width + 5; - } AudioWaveForm.Width = groupBoxVideo.Width - (AudioWaveForm.Left + 10); panelWaveFormControls.Left = AudioWaveForm.Left; + trackBarWaveFormPosition.Left = panelWaveFormControls.Left + panelWaveFormControls.Width + 5; + trackBarWaveFormPosition.Width = groupBoxVideo.Width - (trackBarWaveFormPosition.Left + 10); this.Main_Resize(null, null); - - - //labelVideoInfo.TextAlign = ContentAlignment.TopRight; - //labelVideoInfo.Left = groupBoxVideo.Width - (labelVideoInfo.Width + 10); - //if (toolStripButtonToogleVideo.Checked && !AudioWaveForm.Visible) - //{ - //labelVideoInfo.TextAlign = ContentAlignment.TopLeft; - //labelVideoInfo.Left = checkBoxSyncListViewWithVideoWhilePlaying.Left + checkBoxSyncListViewWithVideoWhilePlaying.Width + 10; - //} - + checkBoxSyncListViewWithVideoWhilePlaying.Left = tabControlButtons.Left + tabControlButtons.Width + 5; Refresh(); } @@ -7137,7 +7174,7 @@ namespace Nikse.SubtitleEdit.Forms public void SetSubtitle(Subtitle subtitle, string message) { _subtitle = subtitle; - SubtitleListview1.Fill(subtitle); + SubtitleListview1.Fill(subtitle, _subtitleAlternate); _change = true; ShowStatus(message); } @@ -7419,7 +7456,7 @@ namespace Nikse.SubtitleEdit.Forms if (doReFill) { _subtitle.Renumber(1); - SubtitleListview1.Fill(_subtitle); + SubtitleListview1.Fill(_subtitle, _subtitleAlternate); UpdateListviewwithUserLogEntries(); if (_oldSelectedParagraph != null) { diff --git a/src/Logic/VideoFormats/Matroska.cs b/src/Logic/VideoFormats/Matroska.cs index bbfa69617..f0c46e5a1 100644 --- a/src/Logic/VideoFormats/Matroska.cs +++ b/src/Logic/VideoFormats/Matroska.cs @@ -34,7 +34,9 @@ namespace Nikse.SubtitleEdit.Logic public string Name { get; set; } public string Language { get; set; } public string CodecId { get; set; } - public string CodecPrivate { get; set; } + public string CodecPrivate { get; set; } + public int ContentCompressionAlgorithm { get; set; } + public int ContentEncodingType { get; set; } } public class Matroska @@ -550,6 +552,9 @@ namespace Nikse.SubtitleEdit.Logic string codecId = string.Empty; string codecPrivate = string.Empty; string biCompression = string.Empty; + int contentCompressionAlgorithm = -1; + int contentEncodingType = -1; + while (f.Position < f.Length && done == false) { @@ -624,6 +629,23 @@ namespace Nikse.SubtitleEdit.Logic biCompression = codecPrivate.Substring(16, 4); f.Seek(afterPosition, SeekOrigin.Begin); } + else if (matroskaId == 0x6D80) // ContentEncodings + { + afterPosition = f.Position + dataSize; + + contentCompressionAlgorithm = 0; // default value + contentEncodingType = 0; // default value + + int contentEncoding1 = f.ReadByte(); + int contentEncoding2 = f.ReadByte(); + + if (contentEncoding1 == 0x62 && contentEncoding2 == 0x40) + { + AnalyzeMatroskaContentEncoding(afterPosition, ref contentCompressionAlgorithm, ref contentEncodingType); + } + f.Seek(afterPosition, SeekOrigin.Begin); + } + else f.Seek(dataSize, SeekOrigin.Current); } @@ -642,11 +664,71 @@ namespace Nikse.SubtitleEdit.Logic TrackNumber = trackNumber, CodecId = codecId, Language = language, - CodecPrivate = codecPrivate + CodecPrivate = codecPrivate, + ContentEncodingType = contentEncodingType, + ContentCompressionAlgorithm = contentCompressionAlgorithm } ); } } + private void AnalyzeMatroskaContentEncoding(long endPosition, ref int contentCompressionAlgorithm, ref int contentEncodingType) + { + bool done = false; + + byte b2 = (byte)f.ReadByte(); + long sizeOfSize2 = GetMatroskaVariableIntLength(b2); + long dataSize2 = GetMatroskaDataSize(sizeOfSize2, b2); + long afterposition2 = f.Position + dataSize2; + + while (f.Position < endPosition && done == false) + { + int ebmlId = f.ReadByte() * 256 + f.ReadByte(); + + if (ebmlId == 0) + done = true; + else + { + if (ebmlId == 0x5031)// ContentEncodingOrder + { + int contentEncodingOrder = f.ReadByte() * 256 + f.ReadByte(); + //System.Windows.Forms.MessageBox.Show("ContentEncodingOrder: " + contentEncodingOrder.ToString()); + } + else if (ebmlId == 0x5032)// ContentEncodingScope + { + int contentEncodingScope = f.ReadByte() * 256 + f.ReadByte(); + //System.Windows.Forms.MessageBox.Show("ContentEncodingScope: " + contentEncodingScope.ToString()); + } + else if (ebmlId == 0x5033)// ContentEncodingType + { + contentEncodingType = f.ReadByte() * 256 + f.ReadByte(); + } + else if (ebmlId == 0x5034)// ContentCompression + { + byte b = (byte)f.ReadByte(); + long sizeOfSize = GetMatroskaVariableIntLength(b); + long dataSize = GetMatroskaDataSize(sizeOfSize, b); + long afterPosition = f.Position + dataSize; + while (f.Position < afterPosition) + { + int contentCompressionId = f.ReadByte() * 256 + f.ReadByte(); + if (contentCompressionId == 0x4254) + { + contentCompressionAlgorithm = f.ReadByte() * 256 + f.ReadByte(); + } + else if (contentCompressionId == 0x4255) + { + int contentCompSettings = f.ReadByte() * 256 + f.ReadByte(); + //System.Windows.Forms.MessageBox.Show("contentCompSettings: " + contentCompSettings.ToString()); + } + + } + f.Seek(afterPosition, SeekOrigin.Begin); + } + } + } + } + + private void AnalyzeMatroskaSegmentInformation(long endPosition) { byte b; @@ -830,6 +912,8 @@ namespace Nikse.SubtitleEdit.Logic else if (matroskaId == 0x1F43B675) // cluster { afterPosition = f.Position + dataSize; + if (f.Position > 8000000) + System.Windows.Forms.MessageBox.Show("8mb"); AnalyzeMatroskaCluster(); f.Seek(afterPosition, SeekOrigin.Begin); } @@ -904,6 +988,7 @@ namespace Nikse.SubtitleEdit.Logic long dataSize; long afterPosition; long clusterTimeCode = 0; + long duration = 0; while (f.Position < f.Length && done == false) { @@ -929,6 +1014,48 @@ namespace Nikse.SubtitleEdit.Logic AnalyzeMatroskaBlock(clusterTimeCode); f.Seek(afterPosition, SeekOrigin.Begin); } + else if (matroskaId == 0xA3) // SimpleBlock + { + afterPosition = f.Position + dataSize; + long before = f.Position; + b = (byte)f.ReadByte(); + int sizeOftrackNumber = GetMatroskaVariableIntLength(b); + long trackNumber = GetMatroskaDataSize(sizeOftrackNumber, b); + + if (trackNumber == _subtitleRipTrackNumber) + { + int timeCode = GetInt16(); + + // lacing + byte flags = (byte)f.ReadByte(); + byte numberOfFrames = 0; + switch ((flags & 6)) // 6 = 00000110 + { + case 0: System.Diagnostics.Debug.Print("No lacing"); // No lacing + break; + case 2: System.Diagnostics.Debug.Print("Xiph lacing"); // 2 = 00000010 = Xiph lacing + numberOfFrames = (byte)f.ReadByte(); + numberOfFrames++; + break; + case 4: System.Diagnostics.Debug.Print("fixed-size"); // 4 = 00000100 = Fixed-size lacing + numberOfFrames = (byte)f.ReadByte(); + numberOfFrames++; + for (int i = 1; i <= numberOfFrames; i++) + b = (byte)f.ReadByte(); // frames + break; + case 6: System.Diagnostics.Debug.Print("EBML"); // 6 = 00000110 = EMBL + numberOfFrames = (byte)f.ReadByte(); + numberOfFrames++; + break; + } + + byte[] buffer = new byte[dataSize - (f.Position - before)]; + f.Read(buffer, 0, buffer.Length); + _subtitleRip.Add(new SubtitleSequence(buffer, timeCode + clusterTimeCode, timeCode + clusterTimeCode + duration)); + + } + f.Seek(afterPosition, SeekOrigin.Begin); + } else f.Seek(dataSize, SeekOrigin.Current); } @@ -1004,7 +1131,6 @@ namespace Nikse.SubtitleEdit.Logic } } - } } diff --git a/src/Logic/VobSub/Idx.cs b/src/Logic/VobSub/Idx.cs index ad9c8f80f..4f0dc4719 100644 --- a/src/Logic/VobSub/Idx.cs +++ b/src/Logic/VobSub/Idx.cs @@ -24,10 +24,14 @@ namespace Nikse.SubtitleEdit.Logic.VobSub public readonly List Palette = new List(); public readonly List Languages = new List(); - public Idx(string fileName) + public Idx(string fileName):this(File.ReadAllLines(fileName)) + { + } + + public Idx(string[] lines) { var timeCodeLinePattern = new Regex(@"^timestamp: \d+:\d+:\d+:\d+, filepos: [\dabcdefABCDEF]+$", RegexOptions.Compiled); - foreach (string line in File.ReadAllLines(fileName)) + foreach (string line in lines) { if (timeCodeLinePattern.IsMatch(line)) {