Added support for reading VobSub inside Matroska

git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@189 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
niksedk 2010-12-23 06:11:10 +00:00
parent 1bd4256e49
commit b744ab2cd4
3 changed files with 234 additions and 67 deletions

View File

@ -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,15 +3991,12 @@ 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);
return;
}
if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_HDMV/PGS")
{
MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!");
if (_fileName == "123")
// MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!");
LoadBluRaySubFromMatroska(matroskaSubtitleInfo, fileName);
return;
}
@ -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<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid);
Cursor.Current = Cursors.Default;
if (isValid)
{
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1;
_subtitle.Paragraphs.Clear();
List<VobSubMergedPack> mergedVobSubPacks = new List<VobSubMergedPack>();
List<VobSubPack> vobSubPacks = new List<VobSubPack>();
List<Color> palette = new List<Color>();
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");
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<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid);
Cursor.Current = Cursors.Default;
if (isValid)
{
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1;
_subtitle.Paragraphs.Clear();
List<BluRaySupPicture> subtitles = new List<BluRaySupPicture>();
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)
{

View File

@ -35,6 +35,8 @@ namespace Nikse.SubtitleEdit.Logic
public string Language { get; set; }
public string CodecId { 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
}
}
}
}

View File

@ -24,10 +24,14 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
public readonly List<Color> Palette = new List<Color>();
public readonly List<string> Languages = new List<string>();
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))
{