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) private void Main_Load(object sender, EventArgs e)
{ {
splitContainer1.Panel1MinSize = 525;
splitContainer1.Panel2MinSize = 250; splitContainer1.Panel2MinSize = 250;
splitContainer1.Panel1MinSize = 250; splitContainerMain.Panel1MinSize = 250;
splitContainerMain.Panel2MinSize = 250;
if (Configuration.Settings.General.StartListViewWidth < 250) if (Configuration.Settings.General.StartListViewWidth < 250)
Configuration.Settings.General.StartListViewWidth = (Width / 3) * 2; Configuration.Settings.General.StartListViewWidth = (Width / 3) * 2;
@ -485,7 +487,6 @@ namespace Nikse.SubtitleEdit.Forms
toolStripMenuItemImportDvdSubtitles.Text = _language.Menu.File.ImportOcrFromDvd; toolStripMenuItemImportDvdSubtitles.Text = _language.Menu.File.ImportOcrFromDvd;
toolStripMenuItemSubIdx.Text = _language.Menu.File.ImportOcrVobSubSubtitle; toolStripMenuItemSubIdx.Text = _language.Menu.File.ImportOcrVobSubSubtitle;
//toolStripMenuItemImportBluRaySup.Visible = false; //TODO: add blu ray sup import/ocr
toolStripMenuItemImportBluRaySup.Text = _language.Menu.File.ImportBluRaySupFile; toolStripMenuItemImportBluRaySup.Text = _language.Menu.File.ImportBluRaySupFile;
matroskaImportStripMenuItem.Text = _language.Menu.File.ImportSubtitleFromMatroskaFile; matroskaImportStripMenuItem.Text = _language.Menu.File.ImportSubtitleFromMatroskaFile;
@ -3990,16 +3991,13 @@ namespace Nikse.SubtitleEdit.Forms
if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_VOBSUB") if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_VOBSUB")
{ {
MessageBox.Show("VobSub subtitles inside Matroska not supported - sorry!"); LoadVobSubFromMatroska(matroskaSubtitleInfo, fileName);
if (_fileName == "123")
LoadVobSubFromMatroska(matroskaSubtitleInfo, fileName);
return; return;
} }
if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_HDMV/PGS") if (matroskaSubtitleInfo.CodecId.ToUpper() == "S_HDMV/PGS")
{ {
MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!"); // MessageBox.Show("Blu-ray subtitles inside Matroska not supported - sorry!");
if (_fileName == "123") LoadBluRaySubFromMatroska(matroskaSubtitleInfo, fileName);
LoadBluRaySubFromMatroska(matroskaSubtitleInfo, fileName);
return; return;
} }
else if (matroskaSubtitleInfo.CodecPrivate.ToLower().Contains("[script info]")) 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) private void LoadVobSubFromMatroska(MatroskaSubtitleInfo matroskaSubtitleInfo, string fileName)
{ {
if (matroskaSubtitleInfo.ContentEncodingType == 1)
{
MessageBox.Show("Encrypted vobsub content not supported");
}
bool isValid; bool isValid;
var matroska = new Matroska(); var matroska = new Matroska();
@ -4096,46 +4110,52 @@ namespace Nikse.SubtitleEdit.Forms
List<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid); List<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid);
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
if (isValid) if (isValid)
{ {
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile); MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1; _subtitleListViewIndex = -1;
_subtitle.Paragraphs.Clear(); _subtitle.Paragraphs.Clear();
List<VobSubMergedPack> mergedVobSubPacks = new List<VobSubMergedPack>(); List<VobSubMergedPack> mergedVobSubPacks = new List<VobSubMergedPack>();
List<VobSubPack> vobSubPacks = new List<VobSubPack>(); Nikse.SubtitleEdit.Logic.VobSub.Idx idx = new Logic.VobSub.Idx(matroskaSubtitleInfo.CodecPrivate.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries));
List<Color> palette = new List<Color>();
palette = null;
foreach (SubtitleSequence p in sub) foreach (SubtitleSequence p in sub)
{ {
SubPicture sp = new SubPicture(p.BinaryData); if (matroskaSubtitleInfo.ContentEncodingType == 0) // compressed with zlib
MessageBox.Show(sp.SubPictureDateSize.ToString()); {
MessageBox.Show(sp.ImageDisplayArea.ToString()); MemoryStream outStream = new MemoryStream();
ComponentAce.Compression.Libs.zlib.ZOutputStream outZStream = new ComponentAce.Compression.Libs.zlib.ZOutputStream(outStream);
int length = p.BinaryData.Length; MemoryStream inStream = new MemoryStream(p.BinaryData);
if (length > 5000) byte[] buffer;
MessageBox.Show("Large"); try
mergedVobSubPacks.Add(new VobSubMergedPack(p.BinaryData, TimeSpan.FromMilliseconds(p.StartMilliseconds), 32, null)); {
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(); 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) if (formSubOcr.ShowDialog(this) == DialogResult.OK)
{ {
MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); ResetSubtitle();
_subtitle.Paragraphs.Clear(); _subtitle.Paragraphs.Clear();
SetCurrentFormat(new SubRip().FriendlyName);
_subtitle.WasLoadedWithFrameNumbers = false; _subtitle.WasLoadedWithFrameNumbers = false;
_subtitle.CalculateFrameNumbersFromTimeCodes(CurrentFrameRate);
foreach (Paragraph p in formSubOcr.SubtitleFromOcr.Paragraphs) foreach (Paragraph p in formSubOcr.SubtitleFromOcr.Paragraphs)
{
_subtitle.Paragraphs.Add(p); _subtitle.Paragraphs.Add(p);
}
ShowSource(); ShowSource();
SubtitleListview1.Fill(_subtitle, _subtitleAlternate); SubtitleListview1.Fill(_subtitle, _subtitleAlternate);
@ -4144,7 +4164,8 @@ namespace Nikse.SubtitleEdit.Forms
SubtitleListview1.FirstVisibleIndex = -1; SubtitleListview1.FirstVisibleIndex = -1;
SubtitleListview1.SelectIndexAndEnsureVisible(0); SubtitleListview1.SelectIndexAndEnsureVisible(0);
_fileName = string.Empty; _fileName = Path.GetFileNameWithoutExtension(fileName);
_converted = true;
Text = Title; Text = Title;
Configuration.Settings.Save(); Configuration.Settings.Save();
@ -4154,6 +4175,11 @@ namespace Nikse.SubtitleEdit.Forms
private void LoadBluRaySubFromMatroska(MatroskaSubtitleInfo matroskaSubtitleInfo, string fileName) private void LoadBluRaySubFromMatroska(MatroskaSubtitleInfo matroskaSubtitleInfo, string fileName)
{ {
if (matroskaSubtitleInfo.ContentEncodingType == 1)
{
MessageBox.Show("Encrypted vobsub content not supported");
}
bool isValid; bool isValid;
var matroska = new Matroska(); var matroska = new Matroska();
@ -4163,22 +4189,51 @@ namespace Nikse.SubtitleEdit.Forms
List<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid); List<SubtitleSequence> sub = matroska.GetMatroskaSubtitle(fileName, (int)matroskaSubtitleInfo.TrackNumber, out isValid);
Cursor.Current = Cursors.Default; Cursor.Current = Cursors.Default;
if (isValid) if (isValid)
{ {
MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile); MakeHistoryForUndo(_language.BeforeImportFromMatroskaFile);
_subtitleListViewIndex = -1; _subtitleListViewIndex = -1;
_subtitle.Paragraphs.Clear(); _subtitle.Paragraphs.Clear();
List<BluRaySupPicture> subtitles = new List<BluRaySupPicture>();
StringBuilder log = new StringBuilder();
foreach (SubtitleSequence p in sub) foreach (SubtitleSequence p in sub)
{ {
int length = p.BinaryData.Length; byte[] buffer;
if (length > 5000) if (matroskaSubtitleInfo.ContentEncodingType == 0) // compressed with zlib
MessageBox.Show("Large"); {
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(); var formSubOcr = new VobSubOcr();
// formSubOcr.Initialize(mergedVobSubPacks, palette, Configuration.Settings.VobSubOcr); formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr);
if (formSubOcr.ShowDialog(this) == DialogResult.OK) if (formSubOcr.ShowDialog(this) == DialogResult.OK)
{ {
MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle);
@ -6397,32 +6452,14 @@ namespace Nikse.SubtitleEdit.Forms
Configuration.Settings.VideoControls.LastActiveTab = "Adjust"; Configuration.Settings.VideoControls.LastActiveTab = "Adjust";
} }
if (toolStripButtonToogleVideo.Checked && toolStripButtonToogleWaveForm.Checked ) if (toolStripButtonToogleWaveForm.Checked )
{
AudioWaveForm.Left = tabControlButtons.Left + tabControlButtons.Width + 5; 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); AudioWaveForm.Width = groupBoxVideo.Width - (AudioWaveForm.Left + 10);
panelWaveFormControls.Left = AudioWaveForm.Left; panelWaveFormControls.Left = AudioWaveForm.Left;
trackBarWaveFormPosition.Left = panelWaveFormControls.Left + panelWaveFormControls.Width + 5;
trackBarWaveFormPosition.Width = groupBoxVideo.Width - (trackBarWaveFormPosition.Left + 10);
this.Main_Resize(null, null); this.Main_Resize(null, null);
checkBoxSyncListViewWithVideoWhilePlaying.Left = tabControlButtons.Left + tabControlButtons.Width + 5;
//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;
//}
Refresh(); Refresh();
} }
@ -7137,7 +7174,7 @@ namespace Nikse.SubtitleEdit.Forms
public void SetSubtitle(Subtitle subtitle, string message) public void SetSubtitle(Subtitle subtitle, string message)
{ {
_subtitle = subtitle; _subtitle = subtitle;
SubtitleListview1.Fill(subtitle); SubtitleListview1.Fill(subtitle, _subtitleAlternate);
_change = true; _change = true;
ShowStatus(message); ShowStatus(message);
} }
@ -7419,7 +7456,7 @@ namespace Nikse.SubtitleEdit.Forms
if (doReFill) if (doReFill)
{ {
_subtitle.Renumber(1); _subtitle.Renumber(1);
SubtitleListview1.Fill(_subtitle); SubtitleListview1.Fill(_subtitle, _subtitleAlternate);
UpdateListviewwithUserLogEntries(); UpdateListviewwithUserLogEntries();
if (_oldSelectedParagraph != null) if (_oldSelectedParagraph != null)
{ {

View File

@ -34,7 +34,9 @@ namespace Nikse.SubtitleEdit.Logic
public string Name { get; set; } public string Name { get; set; }
public string Language { get; set; } public string Language { get; set; }
public string CodecId { 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 public class Matroska
@ -550,6 +552,9 @@ namespace Nikse.SubtitleEdit.Logic
string codecId = string.Empty; string codecId = string.Empty;
string codecPrivate = string.Empty; string codecPrivate = string.Empty;
string biCompression = string.Empty; string biCompression = string.Empty;
int contentCompressionAlgorithm = -1;
int contentEncodingType = -1;
while (f.Position < f.Length && done == false) while (f.Position < f.Length && done == false)
{ {
@ -624,6 +629,23 @@ namespace Nikse.SubtitleEdit.Logic
biCompression = codecPrivate.Substring(16, 4); biCompression = codecPrivate.Substring(16, 4);
f.Seek(afterPosition, SeekOrigin.Begin); 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 else
f.Seek(dataSize, SeekOrigin.Current); f.Seek(dataSize, SeekOrigin.Current);
} }
@ -642,11 +664,71 @@ namespace Nikse.SubtitleEdit.Logic
TrackNumber = trackNumber, TrackNumber = trackNumber,
CodecId = codecId, CodecId = codecId,
Language = language, 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) private void AnalyzeMatroskaSegmentInformation(long endPosition)
{ {
byte b; byte b;
@ -830,6 +912,8 @@ namespace Nikse.SubtitleEdit.Logic
else if (matroskaId == 0x1F43B675) // cluster else if (matroskaId == 0x1F43B675) // cluster
{ {
afterPosition = f.Position + dataSize; afterPosition = f.Position + dataSize;
if (f.Position > 8000000)
System.Windows.Forms.MessageBox.Show("8mb");
AnalyzeMatroskaCluster(); AnalyzeMatroskaCluster();
f.Seek(afterPosition, SeekOrigin.Begin); f.Seek(afterPosition, SeekOrigin.Begin);
} }
@ -904,6 +988,7 @@ namespace Nikse.SubtitleEdit.Logic
long dataSize; long dataSize;
long afterPosition; long afterPosition;
long clusterTimeCode = 0; long clusterTimeCode = 0;
long duration = 0;
while (f.Position < f.Length && done == false) while (f.Position < f.Length && done == false)
{ {
@ -929,6 +1014,48 @@ namespace Nikse.SubtitleEdit.Logic
AnalyzeMatroskaBlock(clusterTimeCode); AnalyzeMatroskaBlock(clusterTimeCode);
f.Seek(afterPosition, SeekOrigin.Begin); 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 else
f.Seek(dataSize, SeekOrigin.Current); 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<Color> Palette = new List<Color>();
public readonly List<string> Languages = new List<string>(); 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); 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)) if (timeCodeLinePattern.IsMatch(line))
{ {