diff --git a/src/Forms/Main.cs b/src/Forms/Main.cs index 8f7cff74e..8df40363a 100644 --- a/src/Forms/Main.cs +++ b/src/Forms/Main.cs @@ -2242,11 +2242,11 @@ namespace Nikse.SubtitleEdit.Forms var fi = new FileInfo(fileName); - //if (Path.GetExtension(fileName).ToLower() == ".ts" && fi.Length > 10000 && IsTransportStream(fileName)) //TODO: Also check mpg, mpeg - and file header! - //{ - // ImportSubtitleFromTransportStream(fileName); - // return; - //} + if (Path.GetExtension(fileName).ToLower() == ".ts" && fi.Length > 10000 && IsTransportStream(fileName)) //TODO: Also check mpg, mpeg - and file header! + { + ImportSubtitleFromTransportStream(fileName); + return; + } if ((Path.GetExtension(fileName).ToLower() == ".mp4" || Path.GetExtension(fileName).ToLower() == ".m4v" || Path.GetExtension(fileName).ToLower() == ".3gp") && fi.Length > 10000) @@ -9056,8 +9056,10 @@ namespace Nikse.SubtitleEdit.Forms private bool ImportSubtitleFromTransportStream(string fileName) { + ShowStatus("Parsing transport stream - please wait..."); var tsParser = new Nikse.SubtitleEdit.Logic.TransportStream.TransportStreamParser(); tsParser.ParseTsFile(fileName); + ShowStatus(string.Empty); if (tsParser.SubtitlePacketIds.Count == 0) { @@ -9065,43 +9067,49 @@ namespace Nikse.SubtitleEdit.Forms return false; } - // choose subtitle track - if (tsParser.SubtitlePacketIds.Count == 0) + int packedId = tsParser.SubtitlePacketIds[0]; + if (tsParser.SubtitlePacketIds.Count > 1) { - MessageBox.Show(_language.NoSubtitlesFound); - return false; + var subChooser = new TransportStreamSubtitleChooser(); + _formPositionsAndSizes.SetPositionAndSize(subChooser); + subChooser.Initialize(tsParser); + if (subChooser.ShowDialog(this) == DialogResult.Cancel) + return false; + packedId = tsParser.SubtitlePacketIds[subChooser.SelectedIndex]; + _formPositionsAndSizes.SavePositionAndSize(subChooser); } + var subtitles = tsParser.GetSubtitlePesPackets(packedId); + + var formSubOcr = new VobSubOcr(); + _formPositionsAndSizes.SetPositionAndSize(formSubOcr); + formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName); + if (formSubOcr.ShowDialog(this) == DialogResult.OK) + { + MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); - //var formSubOcr = new VobSubOcr(); - //_formPositionsAndSizes.SetPositionAndSize(formSubOcr); - //formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName); - //if (formSubOcr.ShowDialog(this) == DialogResult.OK) - //{ - // MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle); + _subtitle.Paragraphs.Clear(); + SetCurrentFormat(Configuration.Settings.General.DefaultSubtitleFormat); + _subtitle.WasLoadedWithFrameNumbers = false; + _subtitle.CalculateFrameNumbersFromTimeCodes(CurrentFrameRate); + foreach (Paragraph p in formSubOcr.SubtitleFromOcr.Paragraphs) + { + _subtitle.Paragraphs.Add(p); + } - // _subtitle.Paragraphs.Clear(); - // SetCurrentFormat(Configuration.Settings.General.DefaultSubtitleFormat); - // _subtitle.WasLoadedWithFrameNumbers = false; - // _subtitle.CalculateFrameNumbersFromTimeCodes(CurrentFrameRate); - // foreach (Paragraph p in formSubOcr.SubtitleFromOcr.Paragraphs) - // { - // _subtitle.Paragraphs.Add(p); - // } + ShowSource(); + SubtitleListview1.Fill(_subtitle, _subtitleAlternate); + _subtitleListViewIndex = -1; + SubtitleListview1.FirstVisibleIndex = -1; + SubtitleListview1.SelectIndexAndEnsureVisible(0); - // ShowSource(); - // SubtitleListview1.Fill(_subtitle, _subtitleAlternate); - // _subtitleListViewIndex = -1; - // SubtitleListview1.FirstVisibleIndex = -1; - // SubtitleListview1.SelectIndexAndEnsureVisible(0); + _fileName = string.Empty; + Text = Title; - // _fileName = string.Empty; - // Text = Title; - - // Configuration.Settings.Save(); - // _formPositionsAndSizes.SavePositionAndSize(formSubOcr); - // return true; - //} - //_formPositionsAndSizes.SavePositionAndSize(formSubOcr); + Configuration.Settings.Save(); + _formPositionsAndSizes.SavePositionAndSize(formSubOcr); + return true; + } + _formPositionsAndSizes.SavePositionAndSize(formSubOcr); return false; } diff --git a/src/Forms/TransportStreamSubtitleChooser.Designer.cs b/src/Forms/TransportStreamSubtitleChooser.Designer.cs new file mode 100644 index 000000000..4f397c12e --- /dev/null +++ b/src/Forms/TransportStreamSubtitleChooser.Designer.cs @@ -0,0 +1,109 @@ +namespace Nikse.SubtitleEdit.Forms +{ + partial class TransportStreamSubtitleChooser + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.labelChoose = new System.Windows.Forms.Label(); + this.listBox1 = new System.Windows.Forms.ListBox(); + this.buttonCancel = new System.Windows.Forms.Button(); + this.buttonOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // labelChoose + // + this.labelChoose.AutoSize = true; + this.labelChoose.Location = new System.Drawing.Point(9, 21); + this.labelChoose.Name = "labelChoose"; + this.labelChoose.Size = new System.Drawing.Size(220, 13); + this.labelChoose.TabIndex = 52; + this.labelChoose.Text = "More than one subtitle found - please choose"; + // + // listBox1 + // + this.listBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.listBox1.FormattingEnabled = true; + this.listBox1.Location = new System.Drawing.Point(12, 44); + this.listBox1.Name = "listBox1"; + this.listBox1.Size = new System.Drawing.Size(548, 264); + this.listBox1.TabIndex = 51; + // + // buttonCancel + // + this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonCancel.BackColor = System.Drawing.SystemColors.Control; + this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.buttonCancel.Location = new System.Drawing.Point(485, 312); + this.buttonCancel.Name = "buttonCancel"; + this.buttonCancel.Size = new System.Drawing.Size(75, 21); + this.buttonCancel.TabIndex = 50; + this.buttonCancel.Text = "C&ancel"; + this.buttonCancel.UseVisualStyleBackColor = false; + this.buttonCancel.Click += new System.EventHandler(this.buttonCancel_Click); + // + // buttonOK + // + this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.buttonOK.Location = new System.Drawing.Point(404, 312); + this.buttonOK.Name = "buttonOK"; + this.buttonOK.Size = new System.Drawing.Size(75, 21); + this.buttonOK.TabIndex = 49; + this.buttonOK.Text = "OK"; + this.buttonOK.UseVisualStyleBackColor = true; + this.buttonOK.Click += new System.EventHandler(this.buttonOK_Click); + // + // TransportStreamSubtitleChooser + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(572, 345); + this.Controls.Add(this.labelChoose); + this.Controls.Add(this.listBox1); + this.Controls.Add(this.buttonCancel); + this.Controls.Add(this.buttonOK); + this.KeyPreview = true; + this.Name = "TransportStreamSubtitleChooser"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Transport stream subtitle chooser"; + this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.TransportStreamSubtitleChooser_KeyDown); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label labelChoose; + private System.Windows.Forms.ListBox listBox1; + private System.Windows.Forms.Button buttonCancel; + private System.Windows.Forms.Button buttonOK; + } +} \ No newline at end of file diff --git a/src/Forms/TransportStreamSubtitleChooser.cs b/src/Forms/TransportStreamSubtitleChooser.cs new file mode 100644 index 000000000..46f49c852 --- /dev/null +++ b/src/Forms/TransportStreamSubtitleChooser.cs @@ -0,0 +1,70 @@ +using Nikse.SubtitleEdit.Logic; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; + +namespace Nikse.SubtitleEdit.Forms +{ + public partial class TransportStreamSubtitleChooser : Form + { + public TransportStreamSubtitleChooser() + { + InitializeComponent(); + //Text = Configuration.Settings.Language.MatroskaSubtitleChooser.Title; + labelChoose.Text = Configuration.Settings.Language.MatroskaSubtitleChooser.PleaseChoose; + buttonOK.Text = Configuration.Settings.Language.General.OK; + buttonCancel.Text = Configuration.Settings.Language.General.Cancel; + FixLargeFonts(); + } + + private void FixLargeFonts() + { + Graphics graphics = this.CreateGraphics(); + SizeF textSize = graphics.MeasureString(buttonOK.Text, this.Font); + if (textSize.Height > buttonOK.Height - 4) + { + int newButtonHeight = (int)(textSize.Height + 7 + 0.5); + Utilities.SetButtonHeight(this, newButtonHeight, 1); + } + } + + private void buttonOK_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.OK; + } + + private void buttonCancel_Click(object sender, EventArgs e) + { + DialogResult = DialogResult.Cancel; + } + + private void TransportStreamSubtitleChooser_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Escape) + DialogResult = DialogResult.Cancel; + } + + internal void Initialize(Logic.TransportStream.TransportStreamParser tsParser) + { + foreach (int id in tsParser.SubtitlePacketIds) + { + string s = string.Format(string.Format("Packet id {0}", id)); + listBox1.Items.Add(s); + } + listBox1.SelectedIndex = 0; + } + + public int SelectedIndex + { + get + { + return listBox1.SelectedIndex; + } + } + + } +} diff --git a/src/Forms/TransportStreamSubtitleChooser.resx b/src/Forms/TransportStreamSubtitleChooser.resx new file mode 100644 index 000000000..5ea0895e3 --- /dev/null +++ b/src/Forms/TransportStreamSubtitleChooser.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/Forms/VobSubOcr.cs b/src/Forms/VobSubOcr.cs index 0ed3b27cf..f69538eeb 100644 --- a/src/Forms/VobSubOcr.cs +++ b/src/Forms/VobSubOcr.cs @@ -220,6 +220,9 @@ namespace Nikse.SubtitleEdit.Forms // XSub (DivX) List _xSubList; + // DVB (from transport stream) + List _dvbSubtitles; + string _lastLine; string _languageId; string _importLanguageString; @@ -1249,6 +1252,15 @@ namespace Nikse.SubtitleEdit.Forms return _xSubList[index].GetImage(); } } + else if (_dvbSubtitles != null) + { + foreach (var segment in _dvbSubtitles[index].SubtitleSegments) + { + if (segment.ObjectData != null && segment.ObjectData.Image != null) + return segment.ObjectData.Image; + } + return new Bitmap(1, 1); + } if (_bluRaySubtitlesOriginal != null) { @@ -1299,6 +1311,8 @@ namespace Nikse.SubtitleEdit.Forms return (_bluRaySubtitles[index].StartTime + 45) / 90; else if (_xSubList != null) return (long)_xSubList[index].Start.TotalMilliseconds; + else if (_dvbSubtitles != null) + return (long)_dvbSubtitles[index].PresentationTimeStamp + 45 / 90; else return (long)_vobSubMergedPackist[index].StartTime.TotalMilliseconds; } @@ -1315,6 +1329,8 @@ namespace Nikse.SubtitleEdit.Forms return (_bluRaySubtitles[index].EndTime + 45) / 90; else if (_xSubList != null) return (long)_xSubList[index].End.TotalMilliseconds; + else if (_dvbSubtitles != null) + return (long)_dvbSubtitles[index].PresentationTimeStamp + 45 / 90; else return (long)_vobSubMergedPackist[index].EndTime.TotalMilliseconds; } @@ -1331,6 +1347,8 @@ namespace Nikse.SubtitleEdit.Forms return _bluRaySubtitles.Count; else if (_xSubList != null) return _xSubList.Count; + else if (_dvbSubtitles != null) + return _dvbSubtitles.Count; else return _vobSubMergedPackist.Count; } @@ -3719,6 +3737,19 @@ namespace Nikse.SubtitleEdit.Forms buttonEditCharacterDatabase.Enabled = true; buttonStartOcr.Focus(); } + else if (_dvbSubtitles != null) + { + checkBoxShowOnlyForced.Visible = false; + checkBoxUseTimeCodesFromIdx.Visible = false; + + buttonOK.Enabled = true; + buttonCancel.Enabled = true; + buttonStartOcr.Enabled = true; + buttonStop.Enabled = false; + buttonNewCharacterDatabase.Enabled = true; + buttonEditCharacterDatabase.Enabled = true; + buttonStartOcr.Focus(); + } else if (_bdnXmlOriginal != null) { LoadBdnXml(); @@ -6958,5 +6989,44 @@ namespace Nikse.SubtitleEdit.Forms exportBdnXmlPng.ShowDialog(this); } + internal void Initialize(List subtitles, VobSubOcrSettings vobSubOcrSettings, string fileName) + { + buttonOK.Enabled = false; + buttonCancel.Enabled = false; + buttonStartOcr.Enabled = false; + buttonStop.Enabled = false; + buttonNewCharacterDatabase.Enabled = false; + buttonEditCharacterDatabase.Enabled = false; + labelStatus.Text = string.Empty; + progressBar1.Visible = false; + progressBar1.Maximum = 100; + progressBar1.Value = 0; + numericUpDownPixelsIsSpace.Value = vobSubOcrSettings.XOrMorePixelsMakesSpace; + numericUpDownNumberOfPixelsIsSpaceNOCR.Value = vobSubOcrSettings.XOrMorePixelsMakesSpace; + _vobSubOcrSettings = vobSubOcrSettings; + + InitializeModi(); + InitializeTesseract(); + LoadImageCompareCharacterDatabaseList(); + + SetOcrMethod(); + + _dvbSubtitles = subtitles; + + foreach (Logic.TransportStream.DvbSubPes pes in _dvbSubtitles) + { + double pts = 0; + if (pes.PresentationTimeStamp != null) + pts = pes.PresentationTimeStamp.Value; + var p = new Paragraph(string.Empty, ((pts + 45) / 90.0), ((pts + 45) / 90.0)); + _subtitle.Paragraphs.Add(p); + } + subtitleListView1.Fill(_subtitle); + subtitleListView1.SelectIndexAndEnsureVisible(0); + + //SetTesseractLanguageFromLanguageString(languageString); + //_importLanguageString = languageString; + } + } } diff --git a/src/Logic/SubtitleFormats/FLVCoreCuePoints.cs b/src/Logic/SubtitleFormats/FLVCoreCuePoints.cs new file mode 100644 index 000000000..af61f89cb --- /dev/null +++ b/src/Logic/SubtitleFormats/FLVCoreCuePoints.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; + +namespace Nikse.SubtitleEdit.Logic.SubtitleFormats +{ + public class FLVCoreCuePoints : SubtitleFormat + { + public override string Extension + { + get { return ".xml"; } + } + + public override string Name + { + get { return "FLVCoreCuePoints"; } + } + + public override bool IsTimeBased + { + get { return true; } + } + + public override bool IsMine(List lines, string fileName) + { + var subtitle = new Subtitle(); + LoadSubtitle(subtitle, lines, fileName); + return subtitle.Paragraphs.Count > 0; + } + + public override string ToText(Subtitle subtitle, string title) + { + string xmlStructure = + "" + Environment.NewLine + + ""; + + var xml = new XmlDocument(); + xml.LoadXml(xmlStructure); + + foreach (Paragraph p in subtitle.Paragraphs) + { + XmlNode paragraph = xml.CreateElement("CuePoint"); + + XmlNode startTime = xml.CreateElement("Time"); + startTime.InnerText = p.StartTime.TotalMilliseconds.ToString(); + paragraph.AppendChild(startTime); + + XmlNode paragraphType = xml.CreateElement("Type"); + paragraphType.InnerText = "event"; + paragraph.AppendChild(paragraphType); + + XmlNode name = xml.CreateElement("Name"); + name.InnerText = p.Text; + paragraph.AppendChild(name); + + XmlNode parameters = xml.CreateElement("Parameters"); + + XmlNode parameter = xml.CreateElement("Parameter"); + name = xml.CreateElement("Name"); + name.InnerText = "source"; + XmlNode value = xml.CreateElement("Value"); + value.InnerText = "transcription"; + parameter.AppendChild(name); + parameter.AppendChild(value); + parameters.AppendChild(parameter); + + parameter = xml.CreateElement("Parameter"); + name = xml.CreateElement("Name"); + name.InnerText = "duration"; + value = xml.CreateElement("Value"); + value.InnerText = p.Duration.TotalMilliseconds.ToString(); + parameter.AppendChild(name); + parameter.AppendChild(value); + parameters.AppendChild(parameter); + + parameter = xml.CreateElement("Parameter"); + name = xml.CreateElement("Name"); + name.InnerText = "confidence"; + value = xml.CreateElement("Value"); + value.InnerText = "50"; + parameter.AppendChild(name); + parameter.AppendChild(value); + parameters.AppendChild(parameter); + + paragraph.AppendChild(parameters); + + xml.DocumentElement.AppendChild(paragraph); + } + + + return ToUtf8XmlString(xml); + } + + public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) + { + _errorCount = 0; + + var sb = new StringBuilder(); + lines.ForEach(line => sb.AppendLine(line)); + + string allText = sb.ToString(); + if (!allText.Contains(" next.StartTime.TotalMilliseconds) + p.EndTime.TotalMilliseconds = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MininumMillisecondsBetweenLines; + } + } + + subtitle.Renumber(1); + } + + } +} + + diff --git a/src/Logic/SubtitleFormats/SubtitleFormat.cs b/src/Logic/SubtitleFormats/SubtitleFormat.cs index 764ae13fb..eab81923f 100644 --- a/src/Logic/SubtitleFormats/SubtitleFormat.cs +++ b/src/Logic/SubtitleFormats/SubtitleFormat.cs @@ -62,6 +62,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats new FinalCutProTestXml(), new FinalCutProTest2Xml(), new FlashXml(), + new FLVCoreCuePoints(), new Footage(), new GpacTtxt(), new ImageLogicAutocaption(), diff --git a/src/Logic/TransportStream/DvbSubPes.cs b/src/Logic/TransportStream/DvbSubPes.cs index 935b8bd5c..7ec1c5d29 100644 --- a/src/Logic/TransportStream/DvbSubPes.cs +++ b/src/Logic/TransportStream/DvbSubPes.cs @@ -35,6 +35,9 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream public DvbSubPes(byte[] buffer, int index) { + if (buffer.Length < 9) + return; + StartCode = Helper.GetEndian(buffer, index + 0, 3); StreamId = buffer[index + 3]; Length = Helper.GetEndianWord(buffer, index + 4); diff --git a/src/Logic/TransportStream/ObjectDataSegment.cs b/src/Logic/TransportStream/ObjectDataSegment.cs index 2a3a94ed8..6ea26b292 100644 --- a/src/Logic/TransportStream/ObjectDataSegment.cs +++ b/src/Logic/TransportStream/ObjectDataSegment.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; + namespace Nikse.SubtitleEdit.Logic.TransportStream { public class ObjectDataSegment @@ -31,15 +32,24 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream public const int MapTable4To8Bit = 0x22; public const int EndOfObjectLineCode = 0xf0; - Random r = new Random(); + public ObjectDataSegment(byte[] buffer, int index, ClutDefinitionSegment cds) + { + ObjectId = Helper.GetEndianWord(buffer, index); + ObjectVersionNumber = buffer[index + 2] >> 4; + ObjectCodingMethod = (buffer[index + 2] & Helper.B00001100) >> 2; + NonModifyingColorFlag = (buffer[index + 2] & Helper.B00000010) > 0; + DecodeImage(buffer, index, cds); + } public void DecodeImage(byte[] buffer, int index, ClutDefinitionSegment cds) { Image = new Bitmap(720, 40); var r = new Random(); Color c = Color.Red; - List twoBitColorLookup = new List { 0, 1, 2, 3 }; + List twoToFourBitColorLookup = new List { 0, 1, 2, 3 }; + List twoToEightBitColorLookup = new List { 0, 1, 2, 3 }; + List fourToEightBitColorLookup = new List { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ,15 }; if (ObjectCodingMethod == 0) { @@ -60,13 +70,13 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream int bitIndex = 0; while (index < start + TopFieldDataBlockLength && TwoBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref bitIndex)) { - DrawPixels(cds, twoBitColorLookup[pixelCode], runLength, ref x, ref y); + DrawPixels(cds, twoToFourBitColorLookup[pixelCode], runLength, ref x, ref y); } } else if (dataType == PixelDecoding4Bit) { bool startHalf = false; - while (FourBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref startHalf)) + while (index < start + TopFieldDataBlockLength && FourBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref startHalf)) { DrawPixels(cds, pixelCode, runLength, ref x, ref y); } @@ -74,28 +84,49 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream else if (dataType == PixelDecoding8Bit) { System.Windows.Forms.MessageBox.Show("8-bit pixel decoding!"); - while (EightBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength)) + while (index < start + TopFieldDataBlockLength && EightBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength)) { DrawPixels(cds, pixelCode, runLength, ref x, ref y); } } else if (dataType == MapTable2To4Bit) { - //4 entry numbers of 4-bits each; entry number 0 first, entry number 3 last. - twoBitColorLookup[0] = buffer[index] >> 4; - twoBitColorLookup[1] = buffer[index] & Helper.B00001111; + //4 entry numbers of 4-bits each; entry number 0 first, entry number 3 last + twoToFourBitColorLookup[0] = buffer[index] >> 4; + twoToFourBitColorLookup[1] = buffer[index] & Helper.B00001111; index++; - twoBitColorLookup[2] = buffer[index] >> 4; - twoBitColorLookup[3] = buffer[index] & Helper.B00001111; + twoToFourBitColorLookup[2] = buffer[index] >> 4; + twoToFourBitColorLookup[3] = buffer[index] & Helper.B00001111; index++; } + else if (dataType == MapTable2To8Bit) + { + //4 entry numbers of 8-bits each; entry number 0 first, entry number 3 last + twoToEightBitColorLookup[0] = buffer[index]; + index++; + twoToEightBitColorLookup[1] = buffer[index]; + index++; + twoToEightBitColorLookup[2] = buffer[index]; + index++; + twoToEightBitColorLookup[4] = buffer[index]; + index++; + } + else if (dataType == MapTable4To8Bit) + { + // 16 entry numbers of 8-bits each + for (int k = 0; k < 16; k++) + { + fourToEightBitColorLookup[k] = buffer[index]; + index++; + } + } else if (dataType == EndOfObjectLineCode) { x = 0; y += 2; // interlaced - skip one line } if (index < start + TopFieldDataBlockLength) - { + { dataType = buffer[index]; index++; } @@ -113,13 +144,13 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream int bitIndex = 0; while (index < start + BottomFieldDataBlockLength - 1 && TwoBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref bitIndex)) { - DrawPixels(cds, twoBitColorLookup[pixelCode], runLength, ref x, ref y); + DrawPixels(cds, twoToFourBitColorLookup[pixelCode], runLength, ref x, ref y); } } else if (dataType == PixelDecoding4Bit) { bool startHalf = false; - while (FourBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref startHalf)) + while (index < start + BottomFieldDataBlockLength - 1 && FourBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength, ref startHalf)) { DrawPixels(cds, pixelCode, runLength, ref x, ref y); } @@ -127,21 +158,42 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream else if (dataType == PixelDecoding8Bit) { System.Windows.Forms.MessageBox.Show("8-bit pixel decoding!"); - while (EightBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength)) + while (index < start + BottomFieldDataBlockLength - 1 && EightBitPixelDecoding(buffer, ref index, ref pixelCode, ref runLength)) { DrawPixels(cds, pixelCode, runLength, ref x, ref y); } } else if (dataType == MapTable2To4Bit) { - //4 entry numbers of 4-bits each; entry number 0 first, entry number 3 last. - twoBitColorLookup[0] = buffer[index] >> 4; - twoBitColorLookup[1] = buffer[index] & Helper.B00001111; + //4 entry numbers of 4-bits each; entry number 0 first, entry number 3 last + twoToFourBitColorLookup[0] = buffer[index] >> 4; + twoToFourBitColorLookup[1] = buffer[index] & Helper.B00001111; index++; - twoBitColorLookup[2] = buffer[index] >> 4; - twoBitColorLookup[3] = buffer[index] & Helper.B00001111; + twoToFourBitColorLookup[2] = buffer[index] >> 4; + twoToFourBitColorLookup[3] = buffer[index] & Helper.B00001111; index++; } + else if (dataType == MapTable2To8Bit) + { + //4 entry numbers of 8-bits each; entry number 0 first, entry number 3 last + twoToEightBitColorLookup[0] = buffer[index]; + index++; + twoToEightBitColorLookup[1] = buffer[index]; + index++; + twoToEightBitColorLookup[2] = buffer[index]; + index++; + twoToEightBitColorLookup[4] = buffer[index]; + index++; + } + else if (dataType == MapTable4To8Bit) + { + // 16 entry numbers of 8-bits each + for (int k = 0; k < 16; k++) + { + fourToEightBitColorLookup[k] = buffer[index]; + index++; + } + } else if (dataType == EndOfObjectLineCode) { x = 0; @@ -183,17 +235,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream Image.SetPixel(x, y, c); x++; } - } - - public ObjectDataSegment(byte[] buffer, int index, ClutDefinitionSegment cds) - { - ObjectId = Helper.GetEndianWord(buffer, index); - ObjectVersionNumber = buffer[index + 2] >> 4; - ObjectCodingMethod = (buffer[index + 2] & Helper.B00001100) >> 2; - NonModifyingColorFlag = (buffer[index + 2] & Helper.B00000010) > 0; - - DecodeImage(buffer, index, cds); - } + } private int Next8Bits(byte[] buffer, ref int index) { diff --git a/src/Logic/TransportStream/SubtitleSegment.cs b/src/Logic/TransportStream/SubtitleSegment.cs index f20b03344..c4b0963f8 100644 --- a/src/Logic/TransportStream/SubtitleSegment.cs +++ b/src/Logic/TransportStream/SubtitleSegment.cs @@ -44,6 +44,9 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream if (buffer.Length - 6 < DataBuffer.Length) return; + if (index + 6 + DataBuffer.Length > buffer.Length) + return; + Buffer.BlockCopy(buffer, index + 6, DataBuffer, 0, DataBuffer.Length); IsValid = true; diff --git a/src/Logic/TransportStream/TransportStreamParser.cs b/src/Logic/TransportStream/TransportStreamParser.cs index 4cab37e22..3eaca6b45 100644 --- a/src/Logic/TransportStream/TransportStreamParser.cs +++ b/src/Logic/TransportStream/TransportStreamParser.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.IO; using System.Text; -using System.Windows.Forms; namespace Nikse.SubtitleEdit.Logic.TransportStream { @@ -17,6 +16,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream public long TotalNumberOfPrivateStream1Continuation0 { get; private set; } public List SubtitlePacketIds { get; private set; } public List SubtitlePackets { get; private set; } + public List ProgramAssociationTables { get; private set; } public void ParseTsFile(string fileName) { @@ -37,6 +37,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream TotalNumberOfPrivateStream1Continuation0 = 0; SubtitlePacketIds = new List(); SubtitlePackets = new List(); + ProgramAssociationTables = new List(); ms.Position = 0; int packetLength = DeterminePacketLength(ms); var packetBuffer = new byte[packetLength]; @@ -48,7 +49,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream byte syncByte = packetBuffer[0]; if (syncByte == Packet.SynchronizationByte) { - Packet packet = new Packet(packetBuffer); + var packet = new Packet(packetBuffer); if (packet.IsNullPacket) { @@ -56,7 +57,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream } else if (packet.IsProgramAssociationTable) { - StringBuilder sb = new StringBuilder(); + var sb = new StringBuilder(); sb.AppendLine("PacketNo: " + TotalNumberOfPackets + 1); sb.AppendLine("PacketId: " + packet.PacketId); sb.AppendLine(); @@ -87,8 +88,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream sb.AppendLine("CurrentNextIndicator: " + packet.ProgramAssociationTable.CurrentNextIndicator); sb.AppendLine("SectionNumber: " + packet.ProgramAssociationTable.SectionNumber); sb.AppendLine("LastSectionNumber: " + packet.ProgramAssociationTable.LastSectionNumber); - - //MessageBox.Show(sb.ToString()); + ProgramAssociationTables.Add(packet); } else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId)) { @@ -99,25 +99,25 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream if (!SubtitlePacketIds.Contains(packet.PacketId)) { SubtitlePacketIds.Add(packet.PacketId); -// MessageBox.Show("Subtitle packet id=" + packet.PacketId); } if (packet.ContinuityCounter == 0) { TotalNumberOfPrivateStream1Continuation0++; - int pes_extensionlength = 0xFF & packetBuffer[12 + packet.AdaptionFieldLength]; + int pes_extensionlength = 0; + if (12 + packet.AdaptionFieldLength < packetBuffer.Length) + pes_extensionlength = 0xFF & packetBuffer[12 + packet.AdaptionFieldLength]; int pes_offset = 13 + packet.AdaptionFieldLength + pes_extensionlength; - bool isTeletext = (pes_extensionlength == 0x24 && (0xFF & packetBuffer[pes_offset])>>4 == 1); + bool isTeletext = (pes_extensionlength == 0x24 && (0xFF & packetBuffer[pes_offset]) >> 4 == 1); // workaround uk freesat teletext if (!isTeletext) isTeletext = (pes_extensionlength == 0x24 && (0xFF & packetBuffer[pes_offset]) == 0x99); - //if (isTeletext) - // MessageBox.Show(TotalNumberOfPackets.ToString() + ": Teletext!"); - //if (!isTeletext) - // pes_subID = ((0xFF & ts_packet[pes_offset]) == 0x20 && (0xFF & ts_packet[pes_offset + 1]) == 0 && (0xFF & ts_packet[pes_offset + 2]) == 0xF) ? 0x20 : 0; + if (!isTeletext) + { + } } } TotalNumberOfPackets++; @@ -129,36 +129,62 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream break; } } - //MessageBox.Show("Done parsing " + Environment.NewLine + - // Environment.NewLine + - // "#Packets: " + TotalNumberOfPackets.ToString() + Environment.NewLine + - // "#Null packets: " + NumberOfNullPackets.ToString() + Environment.NewLine + - // "#Private stream 1's: " + TotalNumberOfPrivateStream1.ToString() + Environment.NewLine + - // "#Private stream 1's with continuation=0: " + TotalNumberOfPrivateStream1Continuation0.ToString()); } - public List GetSubtitlePesPackets(int packetId) + public List GetSubtitlePesPackets(int packetId) { - var list = new List(); - var buffer = new byte[20000]; - int index =0; + var list = new List(); + int last = -1; + List packetList = new List(); foreach (Packet packet in SubtitlePackets) { - if (packet.ContinuityCounter == 0) + if (packet.PacketId == packetId) { - if (index > 0) + if (packet.PayloadUnitStartIndicator) { - var pes = new PacketizedElementaryStream(buffer, 0); - list.Add(pes); + if (packetList.Count > 0) + AddPesPacket(list, packetList); + packetList = new List(); } - index = 0; + if (packet.Payload != null && last != packet.ContinuityCounter) + packetList.Add(packet); + last = packet.ContinuityCounter; } - Buffer.BlockCopy(packet.Payload, 0, buffer, index, packet.Payload.Length); - index += packet.Payload.Length; } + if (packetList.Count > 0) + AddPesPacket(list, packetList); return list; } + private static void AddPesPacket(List list, List packetList) + { + int bufferSize = 0; + foreach (Packet p in packetList) + bufferSize += p.Payload.Length; + var pesData = new byte[bufferSize]; + int pesIndex = 0; + foreach (Packet p in packetList) + { + Buffer.BlockCopy(p.Payload, 0, pesData, pesIndex, p.Payload.Length); + pesIndex += p.Payload.Length; + } + + DvbSubPes pes; + if (Nikse.SubtitleEdit.Logic.VobSub.VobSubParser.IsMpeg2PackHeader(pesData)) + { + pes = new DvbSubPes(pesData, Nikse.SubtitleEdit.Logic.VobSub.Mpeg2Header.Length); + } + else if (Nikse.SubtitleEdit.Logic.VobSub.VobSubParser.IsPrivateStream1(pesData, 0)) + { + pes = new DvbSubPes(pesData, 0); + } + else + { + pes = new DvbSubPes(pesData, 0); + } + list.Add(pes); + } + private int DeterminePacketLength(Stream ms) { return 188; diff --git a/src/SubtitleEdit.csproj b/src/SubtitleEdit.csproj index 85628969b..fab77d662 100644 --- a/src/SubtitleEdit.csproj +++ b/src/SubtitleEdit.csproj @@ -617,6 +617,12 @@ TimedTextStyles.cs + + Form + + + TransportStreamSubtitleChooser.cs + Form @@ -864,6 +870,7 @@ + @@ -1386,6 +1393,9 @@ TimedTextStyles.cs + + TransportStreamSubtitleChooser.cs + UnknownSubtitle.cs Designer