Added xml subtitle format "FLVCoreCuePoints" - thx Jon :)

git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@2344 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
niksedk 2014-01-05 17:26:46 +00:00
parent ae8a78cd6e
commit 2ef6929ee6
12 changed files with 716 additions and 95 deletions

View File

@ -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;
}

View File

@ -0,0 +1,109 @@
namespace Nikse.SubtitleEdit.Forms
{
partial class TransportStreamSubtitleChooser
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@ -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;
}
}
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -220,6 +220,9 @@ namespace Nikse.SubtitleEdit.Forms
// XSub (DivX)
List<XSub> _xSubList;
// DVB (from transport stream)
List<Logic.TransportStream.DvbSubPes> _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<Logic.TransportStream.DvbSubPes> 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;
}
}
}

View File

@ -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<string> 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 =
"<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + Environment.NewLine +
"<FLVCoreCuePoints Version=\"1\" />";
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<string> lines, string fileName)
{
_errorCount = 0;
var sb = new StringBuilder();
lines.ForEach(line => sb.AppendLine(line));
string allText = sb.ToString();
if (!allText.Contains("<FLVCoreCuePoints") && allText.Contains("<CuePoint"))
return;
var xml = new XmlDocument();
try
{
xml.LoadXml(allText);
}
catch (Exception exception)
{
System.Diagnostics.Debug.WriteLine(exception.Message);
_errorCount = 1;
return;
}
foreach (XmlNode node in xml.DocumentElement.SelectNodes("CuePoint"))
{
try
{
string text = node.SelectSingleNode("Name").InnerText;
double start = int.Parse(node.SelectSingleNode("Time").InnerText);
double duration = Utilities.GetOptimalDisplayMilliseconds(text);
foreach (XmlNode parameter in node.SelectNodes("Parameters/Parameter"))
{
if (parameter.SelectSingleNode("Name").InnerText == "duration")
{
duration = int.Parse(parameter.SelectSingleNode("Value").InnerText);
}
}
subtitle.Paragraphs.Add(new Paragraph(text, start, start + duration));
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
_errorCount++;
}
}
for (int i = 0; i < subtitle.Paragraphs.Count; i++)
{
Paragraph p = subtitle.Paragraphs[i];
p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + Utilities.GetOptimalDisplayMilliseconds(p.Text);
if (i < subtitle.Paragraphs.Count - 1)
{
Paragraph next = subtitle.Paragraphs[i + 1];
if (p.EndTime.TotalMilliseconds > next.StartTime.TotalMilliseconds)
p.EndTime.TotalMilliseconds = next.StartTime.TotalMilliseconds - Configuration.Settings.General.MininumMillisecondsBetweenLines;
}
}
subtitle.Renumber(1);
}
}
}

View File

@ -62,6 +62,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats
new FinalCutProTestXml(),
new FinalCutProTest2Xml(),
new FlashXml(),
new FLVCoreCuePoints(),
new Footage(),
new GpacTtxt(),
new ImageLogicAutocaption(),

View File

@ -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);

View File

@ -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<int> twoBitColorLookup = new List<int> { 0, 1, 2, 3 };
List<int> twoToFourBitColorLookup = new List<int> { 0, 1, 2, 3 };
List<int> twoToEightBitColorLookup = new List<int> { 0, 1, 2, 3 };
List<int> fourToEightBitColorLookup = new List<int> { 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)
{

View File

@ -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;

View File

@ -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<int> SubtitlePacketIds { get; private set; }
public List<Packet> SubtitlePackets { get; private set; }
public List<Packet> ProgramAssociationTables { get; private set; }
public void ParseTsFile(string fileName)
{
@ -37,6 +37,7 @@ namespace Nikse.SubtitleEdit.Logic.TransportStream
TotalNumberOfPrivateStream1Continuation0 = 0;
SubtitlePacketIds = new List<int>();
SubtitlePackets = new List<Packet>();
ProgramAssociationTables = new List<Packet>();
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<PacketizedElementaryStream> GetSubtitlePesPackets(int packetId)
public List<DvbSubPes> GetSubtitlePesPackets(int packetId)
{
var list = new List<PacketizedElementaryStream>();
var buffer = new byte[20000];
int index =0;
var list = new List<DvbSubPes>();
int last = -1;
List<Packet> packetList = new List<Packet>();
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<Packet>();
}
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<DvbSubPes> list, List<Packet> 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;

View File

@ -617,6 +617,12 @@
<Compile Include="Forms\TimedTextStyles.Designer.cs">
<DependentUpon>TimedTextStyles.cs</DependentUpon>
</Compile>
<Compile Include="Forms\TransportStreamSubtitleChooser.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\TransportStreamSubtitleChooser.Designer.cs">
<DependentUpon>TransportStreamSubtitleChooser.cs</DependentUpon>
</Compile>
<Compile Include="Forms\UnknownSubtitle.cs">
<SubType>Form</SubType>
</Compile>
@ -864,6 +870,7 @@
<Compile Include="Logic\SubtitleFormats\DCinemaSmpte2007.cs" />
<Compile Include="Logic\SubtitleFormats\FinalCutProImage.cs" />
<Compile Include="Logic\SubtitleFormats\ELRStudioClosedCaption.cs" />
<Compile Include="Logic\SubtitleFormats\FLVCoreCuePoints.cs" />
<Compile Include="Logic\SubtitleFormats\ScenaristClosedCaptionsDropFrame.cs" />
<Compile Include="Logic\SubtitleFormats\FinalCutProXCM.cs" />
<Compile Include="Logic\SubtitleFormats\UnknownSubtitle67.cs" />
@ -1386,6 +1393,9 @@
<EmbeddedResource Include="Forms\TimedTextStyles.resx">
<DependentUpon>TimedTextStyles.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\TransportStreamSubtitleChooser.resx">
<DependentUpon>TransportStreamSubtitleChooser.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\UnknownSubtitle.resx">
<DependentUpon>UnknownSubtitle.cs</DependentUpon>
<SubType>Designer</SubType>