Added fps and bottom margin to export bluraysup/bdn xml

git-svn-id: https://subtitleedit.googlecode.com/svn/trunk@1042 99eadd0c-20b8-1223-b5c4-2a2b2df33de2
This commit is contained in:
niksedk 2012-03-14 21:43:30 +00:00
parent 17f4b29f56
commit bafd53ebc8
4 changed files with 383 additions and 264 deletions

View File

@ -34,6 +34,8 @@
this.folderBrowserDialog1 = new System.Windows.Forms.FolderBrowserDialog();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.groupBoxImageSettings = new System.Windows.Forms.GroupBox();
this.labelLanguage = new System.Windows.Forms.Label();
this.comboBoxLanguage = new System.Windows.Forms.ComboBox();
this.labelImageFormat = new System.Windows.Forms.Label();
this.comboBoxImageFormat = new System.Windows.Forms.ComboBox();
this.checkBoxBold = new System.Windows.Forms.CheckBox();
@ -55,9 +57,11 @@
this.colorDialog1 = new System.Windows.Forms.ColorDialog();
this.labelImageResolution = new System.Windows.Forms.Label();
this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog();
this.labelLanguage = new System.Windows.Forms.Label();
this.comboBoxLanguage = new System.Windows.Forms.ComboBox();
this.comboBoxFramerate = new System.Windows.Forms.ComboBox();
this.labelFrameRate = new System.Windows.Forms.Label();
this.subtitleListView1 = new Nikse.SubtitleEdit.Controls.SubtitleListView();
this.comboBoxBottomMargin = new System.Windows.Forms.ComboBox();
this.labelBottomMargin = new System.Windows.Forms.Label();
((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
this.groupBoxImageSettings.SuspendLayout();
this.SuspendLayout();
@ -67,9 +71,9 @@
this.pictureBox1.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.pictureBox1.Location = new System.Drawing.Point(12, 375);
this.pictureBox1.Location = new System.Drawing.Point(12, 399);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(712, 181);
this.pictureBox1.Size = new System.Drawing.Size(712, 249);
this.pictureBox1.TabIndex = 1;
this.pictureBox1.TabStop = false;
//
@ -77,7 +81,7 @@
//
this.buttonExport.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonExport.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonExport.Location = new System.Drawing.Point(517, 562);
this.buttonExport.Location = new System.Drawing.Point(517, 654);
this.buttonExport.Name = "buttonExport";
this.buttonExport.Size = new System.Drawing.Size(126, 21);
this.buttonExport.TabIndex = 2;
@ -90,7 +94,7 @@
this.buttonCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.buttonCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.buttonCancel.ImeMode = System.Windows.Forms.ImeMode.NoControl;
this.buttonCancel.Location = new System.Drawing.Point(649, 562);
this.buttonCancel.Location = new System.Drawing.Point(649, 654);
this.buttonCancel.Name = "buttonCancel";
this.buttonCancel.Size = new System.Drawing.Size(75, 21);
this.buttonCancel.TabIndex = 3;
@ -101,7 +105,7 @@
//
this.progressBar1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.progressBar1.Location = new System.Drawing.Point(12, 562);
this.progressBar1.Location = new System.Drawing.Point(12, 654);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(499, 21);
this.progressBar1.TabIndex = 20;
@ -111,6 +115,10 @@
//
this.groupBoxImageSettings.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBoxImageSettings.Controls.Add(this.comboBoxBottomMargin);
this.groupBoxImageSettings.Controls.Add(this.labelBottomMargin);
this.groupBoxImageSettings.Controls.Add(this.labelFrameRate);
this.groupBoxImageSettings.Controls.Add(this.comboBoxFramerate);
this.groupBoxImageSettings.Controls.Add(this.labelLanguage);
this.groupBoxImageSettings.Controls.Add(this.comboBoxLanguage);
this.groupBoxImageSettings.Controls.Add(this.labelImageFormat);
@ -133,14 +141,42 @@
this.groupBoxImageSettings.Controls.Add(this.buttonColor);
this.groupBoxImageSettings.Location = new System.Drawing.Point(12, 218);
this.groupBoxImageSettings.Name = "groupBoxImageSettings";
this.groupBoxImageSettings.Size = new System.Drawing.Size(712, 137);
this.groupBoxImageSettings.Size = new System.Drawing.Size(712, 161);
this.groupBoxImageSettings.TabIndex = 1;
this.groupBoxImageSettings.TabStop = false;
this.groupBoxImageSettings.Text = "Image settings";
//
// labelLanguage
//
this.labelLanguage.Location = new System.Drawing.Point(421, 108);
this.labelLanguage.Name = "labelLanguage";
this.labelLanguage.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.labelLanguage.Size = new System.Drawing.Size(110, 13);
this.labelLanguage.TabIndex = 30;
this.labelLanguage.Text = "Language";
this.labelLanguage.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.labelLanguage.Visible = false;
//
// comboBoxLanguage
//
this.comboBoxLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxLanguage.FormattingEnabled = true;
this.comboBoxLanguage.Items.AddRange(new object[] {
"Bmp",
"Exif",
"Gif",
"Jpg",
"Png",
"Tiff"});
this.comboBoxLanguage.Location = new System.Drawing.Point(537, 105);
this.comboBoxLanguage.Name = "comboBoxLanguage";
this.comboBoxLanguage.Size = new System.Drawing.Size(121, 21);
this.comboBoxLanguage.TabIndex = 29;
this.comboBoxLanguage.Visible = false;
//
// labelImageFormat
//
this.labelImageFormat.Location = new System.Drawing.Point(416, 81);
this.labelImageFormat.Location = new System.Drawing.Point(421, 81);
this.labelImageFormat.Name = "labelImageFormat";
this.labelImageFormat.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.labelImageFormat.Size = new System.Drawing.Size(110, 13);
@ -167,7 +203,7 @@
// checkBoxBold
//
this.checkBoxBold.AutoSize = true;
this.checkBoxBold.Location = new System.Drawing.Point(276, 59);
this.checkBoxBold.Location = new System.Drawing.Point(276, 53);
this.checkBoxBold.Name = "checkBoxBold";
this.checkBoxBold.Size = new System.Drawing.Size(47, 17);
this.checkBoxBold.TabIndex = 5;
@ -231,7 +267,7 @@
this.checkBoxAntiAlias.AutoSize = true;
this.checkBoxAntiAlias.Checked = true;
this.checkBoxAntiAlias.CheckState = System.Windows.Forms.CheckState.Checked;
this.checkBoxAntiAlias.Location = new System.Drawing.Point(276, 86);
this.checkBoxAntiAlias.Location = new System.Drawing.Point(276, 76);
this.checkBoxAntiAlias.Name = "checkBoxAntiAlias";
this.checkBoxAntiAlias.Size = new System.Drawing.Size(66, 17);
this.checkBoxAntiAlias.TabIndex = 6;
@ -345,7 +381,7 @@
//
// labelBorderWidth
//
this.labelBorderWidth.Location = new System.Drawing.Point(416, 55);
this.labelBorderWidth.Location = new System.Drawing.Point(421, 54);
this.labelBorderWidth.Name = "labelBorderWidth";
this.labelBorderWidth.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.labelBorderWidth.Size = new System.Drawing.Size(110, 13);
@ -412,40 +448,31 @@
//
this.labelImageResolution.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.labelImageResolution.BackColor = System.Drawing.Color.Transparent;
this.labelImageResolution.Location = new System.Drawing.Point(651, 358);
this.labelImageResolution.Location = new System.Drawing.Point(651, 382);
this.labelImageResolution.Name = "labelImageResolution";
this.labelImageResolution.Size = new System.Drawing.Size(73, 14);
this.labelImageResolution.TabIndex = 22;
this.labelImageResolution.Text = "320x240";
this.labelImageResolution.TextAlign = System.Drawing.ContentAlignment.TopRight;
//
// labelLanguage
// comboBoxFramerate
//
this.labelLanguage.Location = new System.Drawing.Point(416, 108);
this.labelLanguage.Name = "labelLanguage";
this.labelLanguage.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.labelLanguage.Size = new System.Drawing.Size(110, 13);
this.labelLanguage.TabIndex = 30;
this.labelLanguage.Text = "Language";
this.labelLanguage.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.labelLanguage.Visible = false;
this.comboBoxFramerate.FormattingEnabled = true;
this.comboBoxFramerate.Location = new System.Drawing.Point(537, 134);
this.comboBoxFramerate.Name = "comboBoxFramerate";
this.comboBoxFramerate.Size = new System.Drawing.Size(121, 21);
this.comboBoxFramerate.TabIndex = 33;
//
// comboBoxLanguage
// labelFrameRate
//
this.comboBoxLanguage.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxLanguage.FormattingEnabled = true;
this.comboBoxLanguage.Items.AddRange(new object[] {
"Bmp",
"Exif",
"Gif",
"Jpg",
"Png",
"Tiff"});
this.comboBoxLanguage.Location = new System.Drawing.Point(537, 105);
this.comboBoxLanguage.Name = "comboBoxLanguage";
this.comboBoxLanguage.Size = new System.Drawing.Size(121, 21);
this.comboBoxLanguage.TabIndex = 29;
this.comboBoxLanguage.Visible = false;
this.labelFrameRate.Location = new System.Drawing.Point(421, 137);
this.labelFrameRate.Name = "labelFrameRate";
this.labelFrameRate.RightToLeft = System.Windows.Forms.RightToLeft.No;
this.labelFrameRate.Size = new System.Drawing.Size(110, 13);
this.labelFrameRate.TabIndex = 34;
this.labelFrameRate.Text = "Frame rate";
this.labelFrameRate.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
this.labelFrameRate.Visible = false;
//
// subtitleListView1
//
@ -464,11 +491,29 @@
this.subtitleListView1.View = System.Windows.Forms.View.Details;
this.subtitleListView1.SelectedIndexChanged += new System.EventHandler(this.subtitleListView1_SelectedIndexChanged);
//
// comboBoxBottomMargin
//
this.comboBoxBottomMargin.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.comboBoxBottomMargin.FormattingEnabled = true;
this.comboBoxBottomMargin.Location = new System.Drawing.Point(100, 132);
this.comboBoxBottomMargin.Name = "comboBoxBottomMargin";
this.comboBoxBottomMargin.Size = new System.Drawing.Size(121, 21);
this.comboBoxBottomMargin.TabIndex = 35;
//
// labelBottomMargin
//
this.labelBottomMargin.AutoSize = true;
this.labelBottomMargin.Location = new System.Drawing.Point(10, 135);
this.labelBottomMargin.Name = "labelBottomMargin";
this.labelBottomMargin.Size = new System.Drawing.Size(74, 13);
this.labelBottomMargin.TabIndex = 36;
this.labelBottomMargin.Text = "Bottom margin";
//
// ExportPngXml
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(730, 588);
this.ClientSize = new System.Drawing.Size(730, 680);
this.Controls.Add(this.labelImageResolution);
this.Controls.Add(this.groupBoxImageSettings);
this.Controls.Add(this.progressBar1);
@ -524,5 +569,9 @@
private System.Windows.Forms.ComboBox comboBoxImageFormat;
private System.Windows.Forms.Label labelLanguage;
private System.Windows.Forms.ComboBox comboBoxLanguage;
private System.Windows.Forms.Label labelFrameRate;
private System.Windows.Forms.ComboBox comboBoxFramerate;
private System.Windows.Forms.ComboBox comboBoxBottomMargin;
private System.Windows.Forms.Label labelBottomMargin;
}
}

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Text;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
@ -19,7 +20,7 @@ namespace Nikse.SubtitleEdit.Forms
private class MakeBitmapParameter
{
public Bitmap Bitmap { get; set; }
public Paragraph P { get; set; }
public Paragraph P { get; set; }
public string Type { get; set; }
public Color SubtitleColor { get; set; }
public string SubtitleFontName { get; set; }
@ -33,19 +34,21 @@ namespace Nikse.SubtitleEdit.Forms
public byte[] Buffer { get; set; }
public int ScreenWidth { get; set; }
public int ScreenHeight { get; set; }
public double FramesPerSeconds { get; set; }
public int BottomMargin { get; set; }
public bool Saved { get; set; }
}
Subtitle _subtitle;
Color _subtitleColor = Color.White;
string _subtitleFontName = "Verdana";
float _subtitleFontSize = 75.0f;
bool _subtitleFontBold = false;
Color _borderColor = Color.Black;
float _borderWidth = 2.0f;
bool _isLoading = true;
string _exportType = "BDNXML";
string _fileName;
private Subtitle _subtitle;
private Color _subtitleColor = Color.White;
private string _subtitleFontName = "Verdana";
private float _subtitleFontSize = 75.0f;
private bool _subtitleFontBold = false;
private Color _borderColor = Color.Black;
private float _borderWidth = 2.0f;
private bool _isLoading = true;
private string _exportType = "BDNXML";
private string _fileName;
public ExportPngXml()
{
@ -53,9 +56,25 @@ namespace Nikse.SubtitleEdit.Forms
comboBoxImageFormat.SelectedIndex = 4;
}
private static string BdnXmlTimeCode(TimeCode timecode)
private double FrameRate
{
int frames = timecode.Milliseconds / 40; // 40==25fps (1000/25)
get
{
if (comboBoxFramerate.SelectedItem == null)
return 25;
string s = comboBoxFramerate.SelectedItem.ToString();
s = s.Replace(",", ".").Trim();
double d;
if (double.TryParse(s, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d))
return d;
return 25;
}
}
private string BdnXmlTimeCode(TimeCode timecode)
{
int frames = (int)Math.Round(timecode.Milliseconds / (1000.0 / FrameRate));
return string.Format("{0:00}:{1:00}:{2:00}:{3:00}", timecode.Hours, timecode.Minutes, timecode.Seconds, frames);
}
@ -72,7 +91,7 @@ namespace Nikse.SubtitleEdit.Forms
Width = paramter.ScreenWidth,
Height = paramter.ScreenHeight
};
paramter.Buffer = Logic.BluRaySup.BluRaySupPicture.CreateSupFrame(brSub, paramter.Bitmap);
paramter.Buffer = Logic.BluRaySup.BluRaySupPicture.CreateSupFrame(brSub, paramter.Bitmap, paramter.FramesPerSeconds, paramter.BottomMargin);
}
else if (paramter.Type == "VOBSUB")
{
@ -101,6 +120,8 @@ namespace Nikse.SubtitleEdit.Forms
ScreenWidth = screenWidth,
ScreenHeight = screenHeight,
Bitmap = null,
FramesPerSeconds = FrameRate,
BottomMargin = comboBoxBottomMargin.SelectedIndex,
Saved = false,
};
if (index < _subtitle.Paragraphs.Count)
@ -197,13 +218,13 @@ namespace Nikse.SubtitleEdit.Forms
if (_exportType == "BLURAYSUP")
binarySubtitleFile = new FileStream(saveFileDialog1.FileName, FileMode.Create);
else if (_exportType == "VOBSUB")
vobSubWriter = new VobSubWriter(saveFileDialog1.FileName, width, height, 15, 32, _subtitleColor, _borderColor, GetOutlineColor(_borderColor), IfoParser.ArrayOfLanguage[comboBoxLanguage.SelectedIndex], IfoParser.ArrayOfLanguageCode[comboBoxLanguage.SelectedIndex]);
vobSubWriter = new VobSubWriter(saveFileDialog1.FileName, width, height, comboBoxBottomMargin.SelectedIndex, 32, _subtitleColor, _borderColor, GetOutlineColor(_borderColor), IfoParser.ArrayOfLanguage[comboBoxLanguage.SelectedIndex], IfoParser.ArrayOfLanguageCode[comboBoxLanguage.SelectedIndex]);
progressBar1.Value = 0;
progressBar1.Maximum = _subtitle.Paragraphs.Count-1;
progressBar1.Visible = true;
const int border = 25;
int border = comboBoxBottomMargin.SelectedIndex;
int imagesSavedCount = 0;
var sb = new StringBuilder();
@ -282,6 +303,22 @@ namespace Nikse.SubtitleEdit.Forms
}
else
{
string videoFormat = "1080p";
if (comboBoxResolution.SelectedIndex == 2)
videoFormat = "720p";
else if (comboBoxResolution.SelectedIndex == 3)
videoFormat = "960x720";
else if (comboBoxResolution.SelectedIndex == 4)
videoFormat = "480p";
else if (comboBoxResolution.SelectedIndex == 5)
videoFormat = "720x576";
else if (comboBoxResolution.SelectedIndex == 6)
videoFormat = "720x480";
else if (comboBoxResolution.SelectedIndex == 7)
videoFormat = "640x352";
else if (comboBoxResolution.SelectedIndex == 8)
videoFormat = "640x272";
var doc = new XmlDocument();
Paragraph first = _subtitle.Paragraphs[0];
Paragraph last = _subtitle.Paragraphs[_subtitle.Paragraphs.Count - 1];
@ -290,7 +327,7 @@ namespace Nikse.SubtitleEdit.Forms
"<Description>" + Environment.NewLine +
"<Name Title=\"subtitle_exp\" Content=\"\"/>" + Environment.NewLine +
"<Language Code=\"eng\"/>" + Environment.NewLine +
"<Format VideoFormat=\"1080p\" FrameRate=\"25\" DropFrame=\"False\"/>" + Environment.NewLine +
"<Format VideoFormat=\""+videoFormat + "\" FrameRate=\""+ FrameRate.ToString(CultureInfo.InvariantCulture) + "\" DropFrame=\"False\"/>" + Environment.NewLine +
"<Events Type=\"Graphic\" FirstEventInTC=\"" + BdnXmlTimeCode(first.StartTime) + "\" LastEventOutTC=\"" + BdnXmlTimeCode(last.EndTime) + "\" NumberofEvents=\"" + imagesSavedCount.ToString() + "\"/>" + Environment.NewLine +
"</Description>" + Environment.NewLine +
"<Events>" + Environment.NewLine +
@ -329,7 +366,7 @@ namespace Nikse.SubtitleEdit.Forms
{
string numberString = string.Format("IMAGE{0:000}", i);
string fileName = Path.Combine(folderBrowserDialog1.SelectedPath, numberString + "." + comboBoxImageFormat.Text.ToLower());
var imageFormat = System.Drawing.Imaging.ImageFormat.Png; ;
var imageFormat = System.Drawing.Imaging.ImageFormat.Png;
if (comboBoxImageFormat.SelectedIndex == 0)
imageFormat = System.Drawing.Imaging.ImageFormat.Bmp;
else if (comboBoxImageFormat.SelectedIndex == 1)
@ -383,9 +420,8 @@ namespace Nikse.SubtitleEdit.Forms
private string FormatFabTime(TimeCode time, MakeBitmapParameter param)
{
if (param.Bitmap.Width == 720 && param.Bitmap.Width == 480) // NTSC
return string.Format("{0:00};{1:00};{2:00};{3:00}", time.Hours, time.Minutes, time.Seconds, Nikse.SubtitleEdit.Logic.SubtitleFormats.SubtitleFormat.MillisecondsToFrames(time.Milliseconds));
else
return string.Format("{0:00}:{1:00}:{2:00}:{3:00}", time.Hours, time.Minutes, time.Seconds, Nikse.SubtitleEdit.Logic.SubtitleFormats.SubtitleFormat.MillisecondsToFrames(time.Milliseconds));
return string.Format("{0:00};{1:00};{2:00};{3:00}", time.Hours, time.Minutes, time.Seconds, Logic.SubtitleFormats.SubtitleFormat.MillisecondsToFrames(time.Milliseconds));
return string.Format("{0:00}:{1:00}:{2:00}:{3:00}", time.Hours, time.Minutes, time.Seconds, Logic.SubtitleFormats.SubtitleFormat.MillisecondsToFrames(time.Milliseconds));
}
private void SetupImageParameters()
@ -410,7 +446,7 @@ namespace Nikse.SubtitleEdit.Forms
private Bitmap GenerateImageFromTextWithStyle(string text)
{
MakeBitmapParameter mbp = new MakeBitmapParameter();
var mbp = new MakeBitmapParameter();
mbp.AlignLeft = comboBoxHAlign.SelectedIndex == 0;
mbp.AlignRight = comboBoxHAlign.SelectedIndex == 2;
mbp.AntiAlias = checkBoxAntiAlias.Checked;
@ -425,7 +461,7 @@ namespace Nikse.SubtitleEdit.Forms
var bmp = GenerateImageFromTextWithStyle(mbp);
if (_exportType == "VOBSUB")
{
NikseBitmap nbmp = new NikseBitmap(bmp);
var nbmp = new NikseBitmap(bmp);
nbmp.ConverToFourColors(Color.Transparent, _subtitleColor, _borderColor, GetOutlineColor(_borderColor));
bmp = nbmp.GetBitmap();
}
@ -434,9 +470,7 @@ namespace Nikse.SubtitleEdit.Forms
private static float MeasureTextWidth(Font font, string text, bool bold)
{
var sf = new StringFormat();
sf.Alignment = StringAlignment.Near;
sf.LineAlignment = StringAlignment.Near;
var sf = new StringFormat {Alignment = StringAlignment.Near, LineAlignment = StringAlignment.Near};
var path = new GraphicsPath();
var sb = new StringBuilder(text);
@ -515,7 +549,7 @@ namespace Nikse.SubtitleEdit.Forms
if (parameter.AlignLeft)
lefts.Add(5);
else if (parameter.AlignRight)
lefts.Add((float)(bmp.Width - (MeasureTextWidth(font, line, parameter.SubtitleFontBold) + 15)));
lefts.Add(bmp.Width - (MeasureTextWidth(font, line, parameter.SubtitleFontBold) + 15));
else
lefts.Add((float)(bmp.Width - g.MeasureString(line, font).Width * 0.8+15) / 2);
}
@ -654,6 +688,7 @@ namespace Nikse.SubtitleEdit.Forms
buttonCancel.Text = Configuration.Settings.Language.General.OK;
labelImageResolution.Text = string.Empty;
labelLanguage.Text = Configuration.Settings.Language.ChooseLanguage.Language;
labelFrameRate.Text = Configuration.Settings.Language.General.FrameRate;
labelHorizontalAlign.Text = Configuration.Settings.Language.ExportPngXml.Align;
if (Configuration.Settings.Language.ExportPngXml.Left != null &&
Configuration.Settings.Language.ExportPngXml.Center != null &&
@ -694,6 +729,49 @@ namespace Nikse.SubtitleEdit.Forms
}
comboBoxImageFormat.Visible = exportType == "FAB";
labelImageFormat.Visible = exportType == "FAB";
labelFrameRate.Visible = exportType == "BDNXML" || exportType == "BLURAYSUP";
comboBoxFramerate.Visible = exportType == "BDNXML" || exportType == "BLURAYSUP";
if (exportType == "BDNXML")
{
labelFrameRate.Top = labelLanguage.Top;
comboBoxFramerate.Top = comboBoxLanguage.Top;
comboBoxFramerate.Items.Add("23.976");
comboBoxFramerate.Items.Add("24");
comboBoxFramerate.Items.Add("25");
comboBoxFramerate.Items.Add("29.97");
comboBoxFramerate.Items.Add("50");
comboBoxFramerate.Items.Add("59.94");
comboBoxFramerate.SelectedIndex = 2;
}
else if (exportType == "BLURAYSUP")
{
labelFrameRate.Top = labelLanguage.Top;
comboBoxFramerate.Top = comboBoxLanguage.Top;
comboBoxFramerate.Items.Add("23.976");
comboBoxFramerate.Items.Add("24");
comboBoxFramerate.Items.Add("25");
comboBoxFramerate.Items.Add("29.97");
comboBoxFramerate.Items.Add("50");
comboBoxFramerate.Items.Add("59.94");
comboBoxFramerate.SelectedIndex = 1;
comboBoxFramerate.DropDownStyle = ComboBoxStyle.DropDownList;
}
for (int i=0; i<1000; i++)
comboBoxBottomMargin.Items.Add(i);
comboBoxBottomMargin.SelectedIndex = 15;
if (exportType == "BLURAYSUP")
comboBoxBottomMargin.SelectedIndex = 20;
if (_exportType == "BLURAYSUP" || _exportType == "VOBSUB")
{
comboBoxBottomMargin.Visible = true;
labelBottomMargin.Visible = true;
}
else
{
comboBoxBottomMargin.Visible = false;
labelBottomMargin.Visible = false;
}
foreach (var x in FontFamily.Families)
{

View File

@ -103,7 +103,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
/** list of (list of) palette info - there are up to 8 palettes per epoch, each can be updated several times */
public List<List<PaletteInfo>> Palettes;
private static byte[] packetHeader =
private static readonly byte[] PacketHeader =
{
0x50, 0x47, // 0: "PG"
0x00, 0x00, 0x00, 0x00, // 2: PTS - presentation time stamp
@ -112,7 +112,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
0x00, 0x00, // 11: segment_length (bytes following till next PG)
};
private static byte[] headerPCSStart =
private static readonly byte[] HeaderPCSStart =
{
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
@ -127,7 +127,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
0x00, 0x00, 0x00, 0x00 // 15: composition_object_horizontal_position, composition_object_vertical_position
};
private static byte[] headerPCSEnd =
private static readonly byte[] HeaderPCSEnd =
{
0x00, 0x00, 0x00, 0x00, // 0: video_width, video_height
0x10, // 4: hi nibble: frame_rate (0x10=24p), lo nibble: reserved
@ -138,7 +138,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
0x00, // 10: number_of_composition_objects (0..2)
};
private static byte[] headerODSFirst =
private static readonly byte[] HeaderODSFirst =
{
0x00, 0x00, // 0: object_id
0x00, // 2: object_version_number
@ -147,14 +147,14 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
0x00, 0x00, 0x00, 0x00, // 7: object_width, object_height
};
private static byte[] headerODSNext =
private static readonly byte[] HeaderODSNext =
{
0x00, 0x00, // 0: object_id
0x00, // 2: object_version_number
0x40, // 3: first_in_sequence (0x80), last_in_sequence (0x40), 6bits reserved
};
private static byte[] headerWDS =
private static readonly byte[] HeaderWds =
{
0x01, // 0 : number of windows (currently assumed 1, 0..2 is legal)
0x00, // 1 : window id (0..1)
@ -183,7 +183,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
Palettes = new List<List<PaletteInfo>>();
foreach (List<PaletteInfo> palette in subPicture.Palettes)
{
List<PaletteInfo> p = new List<PaletteInfo>();
var p = new List<PaletteInfo>();
foreach (PaletteInfo pi in palette)
{
p.Add(new PaletteInfo(pi));
@ -210,22 +210,18 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
System.Diagnostics.Debug.WriteLine("Invalid Blu-ray SupPicture - ImageObjects is null - BluRaySupPictures.cs: internal ImageObject ObjectIdImage");
return null;
}
else if (ObjectId < ImageObjects.Count)
if (ObjectId < ImageObjects.Count)
{
return ImageObjects[ObjectId];
}
else
{
System.Diagnostics.Debug.WriteLine("Invalid Blu-ray SupPicture index - BluRaySupPictures.cs: internal ImageObject ObjectIdImage");
return ImageObjects[ImageObjects.Count - 1];
}
System.Diagnostics.Debug.WriteLine("Invalid Blu-ray SupPicture index - BluRaySupPictures.cs: internal ImageObject ObjectIdImage");
return ImageObjects[ImageObjects.Count - 1];
}
}
/// <summary>
/// decode palette from the input stream
/// </summary>
/// <param name="pic">SubPicture object containing info about the current caption</param>
/// <returns>Palette object</returns>
public BluRaySupPalette DecodePalette(BluRaySupPalette defaultPalette)
{
@ -240,7 +236,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
return new BluRaySupPalette(defaultPalette);
}
List<PaletteInfo> pl = pic.Palettes[pic.ObjectIdImage.PaletteId];
BluRaySupPalette palette = new BluRaySupPalette(256, Core.UsesBt601());
var palette = new BluRaySupPalette(256, Core.UsesBt601());
// by definition, index 0xff is always completely transparent
// also all entries must be fully transparent after initialization
@ -296,8 +292,6 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
/// <summary>
/// Decode caption from the input stream
/// </summary>
/// <param name="pic">SubPicture object containing info about the caption</param>
/// <param name="transIdx">index of the transparent color</param>
/// <returns>bitmap of the decoded caption</returns>
public Bitmap DecodeImage(BluRaySupPalette defaultPalette)
{
@ -311,7 +305,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
throw new Exception("Subpicture too large: " + w + "x" + h);
//Bitmap bm = new Bitmap(w, h);
FastBitmap bm = new FastBitmap(new Bitmap(w, h));
var bm = new FastBitmap(new Bitmap(w, h));
bm.LockImage();
BluRaySupPalette pal = DecodePalette(defaultPalette);
@ -327,7 +321,6 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
index += fragment.ImagePacketSize;
}
index = 0;
do
{
@ -407,7 +400,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
/// <returns>RLE buffer</returns>
private static byte[] EncodeImage(Bitmap bm, Dictionary<Color, int> palette)
{
List<Byte> bytes = new List<Byte>();
var bytes = new List<Byte>();
byte color = 0;
int ofs = 0;
int len = 0;
@ -505,7 +498,7 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
private static Dictionary<Color, int> GetBitmapPalette(Bitmap bitmap)
{
Dictionary<Color, int> pal = new Dictionary<Color, int>();
var pal = new Dictionary<Color, int>();
for (int y = 0; y < bitmap.Height; y++)
{
for (int x = 0; x < bitmap.Width; x++)
@ -524,17 +517,17 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
/// </summary>
/// <param name="fps">frame rate</param>
/// <returns>byte ID for the given frame rate</returns>
private static int getFpsId(double fps)
private static int GetFpsId(double fps)
{
if (fps == Core.Fps24Hz)
return 0x20;
if (fps == Core.FpsPal)
return 0x30;
if (fps == Core.FpsNtsc)
if (Math.Abs(fps - Core.FpsNtsc) < 0.05)
return 0x40;
if (fps == Core.FpsPalI)
return 0x60;
if (fps == Core.FpsNtscI)
if (Math.Abs(fps - Core.FpsNtscI) < 0.05)
return 0x70;
// assume FPS_24P (also for FPS_23_975)
return 0x10;
@ -545,13 +538,13 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
/// </summary>
/// <param name="pic">SubPicture object containing caption info</param>
/// <param name="bm">bitmap</param>
/// <param name="pal">palette</param>
/// <param name="fps">frames per second</param>
/// <param name="bottomMargin">image bottom margin</param>
/// <returns>byte buffer containing the binary stream representation of one caption</returns>
public static byte[] CreateSupFrame(BluRaySupPicture pic, Bitmap bm)
public static byte[] CreateSupFrame(BluRaySupPicture pic, Bitmap bm, double fps, int bottomMargin)
{
int size = 0;
var colorPalette = GetBitmapPalette(bm);
BluRaySupPalette pal = new BluRaySupPalette(colorPalette.Count);
var pal = new BluRaySupPalette(colorPalette.Count);
int k = 0;
foreach (var kvp in colorPalette)
{
@ -578,16 +571,16 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
// object frames
int palSize = colorPalette.Count;
size = packetHeader.Length * (8 + numAddPackets);
size += headerPCSStart.Length + headerPCSEnd.Length;
size += 2 * headerWDS.Length + headerODSFirst.Length;
size += numAddPackets * headerODSNext.Length;
int size = PacketHeader.Length * (8 + numAddPackets);
size += HeaderPCSStart.Length + HeaderPCSEnd.Length;
size += 2 * HeaderWds.Length + HeaderODSFirst.Length;
size += numAddPackets * HeaderODSNext.Length;
size += (2 + palSize * 5) /* PDS */;
size += rleBuf.Length;
pic.WindowXOffset = (pic.Width - bm.Width) / 2;
pic.WindowYOffset = pic.Height - (bm.Height + (pic.Height / 12));
pic.WindowYOffset = pic.Height - (bm.Height + bottomMargin);
int yOfs = pic.WindowYOffset - Core.CropOfsY;
if (yOfs < 0)
{
@ -603,153 +596,153 @@ namespace Nikse.SubtitleEdit.Logic.BluRaySup
int h = pic.Height - 2 * Core.CropOfsY;
byte[] buf = new byte[size];
int index = 0;
int index = 0;
int fpsId = getFpsId(Core.fpsTrg);
int fpsId = GetFpsId(fps);
/* time (in 90kHz resolution) needed to initialize (clear) the screen buffer
based on the composition pixel rate of 256e6 bit/s - always rounded up */
int frameInitTime = (pic.Width * pic.Height * 9 + 3199) / 3200; // better use default height here
/* time (in 90kHz resolution) needed to initialize (clear) the window area
based on the composition pixel rate of 256e6 bit/s - always rounded up
Note: no cropping etc. -> window size == image size */
int windowInitTime = (bm.Width * bm.Height * 9 + 3199) / 3200;
/* time (in 90kHz resolution) needed to decode the image
based on the decoding pixel rate of 128e6 bit/s - always rounded up */
int imageDecodeTime = (bm.Width * bm.Height * 9 + 1599) / 1600;
// write PCS start
packetHeader[10] = 0x16; // ID
int dts = pic.StartTimeForWrite - (frameInitTime + windowInitTime);
ToolBox.SetDWord(packetHeader, 2, pic.StartTimeForWrite); // PTS
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
ToolBox.SetWord(packetHeader, 11, headerPCSStart.Length); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
ToolBox.SetWord(headerPCSStart, 0, pic.Width);
ToolBox.SetWord(headerPCSStart, 2, h); // cropped height
ToolBox.SetByte(headerPCSStart, 4, fpsId);
ToolBox.SetWord(headerPCSStart, 5, pic.CompositionNumber);
headerPCSStart[14] = (byte)(pic.IsForced ? 0x40 : 0);
ToolBox.SetWord(headerPCSStart, 15, pic.WindowXOffset);
ToolBox.SetWord(headerPCSStart, 17, yOfs);
for (int i = 0; i < headerPCSStart.Length; i++)
buf[index++] = headerPCSStart[i];
/* time (in 90kHz resolution) needed to initialize (clear) the screen buffer
based on the composition pixel rate of 256e6 bit/s - always rounded up */
int frameInitTime = (pic.Width * pic.Height * 9 + 3199) / 3200; // better use default height here
/* time (in 90kHz resolution) needed to initialize (clear) the window area
based on the composition pixel rate of 256e6 bit/s - always rounded up
Note: no cropping etc. -> window size == image size */
int windowInitTime = (bm.Width * bm.Height * 9 + 3199) / 3200;
/* time (in 90kHz resolution) needed to decode the image
based on the decoding pixel rate of 128e6 bit/s - always rounded up */
int imageDecodeTime = (bm.Width * bm.Height * 9 + 1599) / 1600;
// write PCS start
PacketHeader[10] = 0x16; // ID
int dts = pic.StartTimeForWrite - (frameInitTime + windowInitTime);
ToolBox.SetDWord(PacketHeader, 2, pic.StartTimeForWrite); // PTS
ToolBox.SetDWord(PacketHeader, 6, dts); // DTS
ToolBox.SetWord(PacketHeader, 11, HeaderPCSStart.Length); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
ToolBox.SetWord(HeaderPCSStart, 0, pic.Width);
ToolBox.SetWord(HeaderPCSStart, 2, h); // cropped height
ToolBox.SetByte(HeaderPCSStart, 4, fpsId);
ToolBox.SetWord(HeaderPCSStart, 5, pic.CompositionNumber);
HeaderPCSStart[14] = (byte)(pic.IsForced ? 0x40 : 0);
ToolBox.SetWord(HeaderPCSStart, 15, pic.WindowXOffset);
ToolBox.SetWord(HeaderPCSStart, 17, yOfs);
for (int i = 0; i < HeaderPCSStart.Length; i++)
buf[index++] = HeaderPCSStart[i];
// write WDS
packetHeader[10] = 0x17; // ID
int timeStamp = pic.StartTimeForWrite - windowInitTime;
ToolBox.SetDWord(packetHeader, 2, timeStamp); // PTS (keep DTS)
ToolBox.SetWord(packetHeader, 11, headerWDS.Length); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
ToolBox.SetWord(headerWDS, 2, pic.WindowXOffset);
ToolBox.SetWord(headerWDS, 4, yOfs);
ToolBox.SetWord(headerWDS, 6, bm.Width);
ToolBox.SetWord(headerWDS, 8, bm.Height);
for (int i = 0; i < headerWDS.Length; i++)
buf[index++] = headerWDS[i];
// write WDS
PacketHeader[10] = 0x17; // ID
int timeStamp = pic.StartTimeForWrite - windowInitTime;
ToolBox.SetDWord(PacketHeader, 2, timeStamp); // PTS (keep DTS)
ToolBox.SetWord(PacketHeader, 11, HeaderWds.Length); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
ToolBox.SetWord(HeaderWds, 2, pic.WindowXOffset);
ToolBox.SetWord(HeaderWds, 4, yOfs);
ToolBox.SetWord(HeaderWds, 6, bm.Width);
ToolBox.SetWord(HeaderWds, 8, bm.Height);
for (int i = 0; i < HeaderWds.Length; i++)
buf[index++] = HeaderWds[i];
// write PDS
packetHeader[10] = 0x14; // ID
ToolBox.SetDWord(packetHeader, 2, dts); // PTS (=DTS of PCS/WDS)
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0)
ToolBox.SetWord(packetHeader, 11, (2 + palSize * 5)); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
buf[index++] = 0;
buf[index++] = 0;
for (int i = 0; i < palSize; i++)
{
buf[index++] = (byte)i; // index
buf[index++] = pal.GetY()[i]; // Y
buf[index++] = pal.GetCr()[i]; // Cr
buf[index++] = pal.GetCb()[i]; // Cb
buf[index++] = pal.GetAlpha()[i]; // Alpha
}
// write PDS
PacketHeader[10] = 0x14; // ID
ToolBox.SetDWord(PacketHeader, 2, dts); // PTS (=DTS of PCS/WDS)
ToolBox.SetDWord(PacketHeader, 6, 0); // DTS (0)
ToolBox.SetWord(PacketHeader, 11, (2 + palSize * 5)); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
buf[index++] = 0;
buf[index++] = 0;
for (int i = 0; i < palSize; i++)
{
buf[index++] = (byte)i; // index
buf[index++] = pal.GetY()[i]; // Y
buf[index++] = pal.GetCr()[i]; // Cr
buf[index++] = pal.GetCb()[i]; // Cb
buf[index++] = pal.GetAlpha()[i]; // Alpha
}
// write first OBJ
int bufSize = rleBuf.Length;
int rleIndex = 0;
if (bufSize > 0xffe4)
bufSize = 0xffe4;
packetHeader[10] = 0x15; // ID
timeStamp = dts + imageDecodeTime;
ToolBox.SetDWord(packetHeader, 2, timeStamp); // PTS
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
ToolBox.SetWord(packetHeader, 11, headerODSFirst.Length + bufSize); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
int marker = (int)((numAddPackets == 0) ? 0xC0000000 : 0x80000000);
ToolBox.SetDWord(headerODSFirst, 3, marker | (rleBuf.Length + 4));
ToolBox.SetWord(headerODSFirst, 7, bm.Width);
ToolBox.SetWord(headerODSFirst, 9, bm.Height);
for (int i = 0; i < headerODSFirst.Length; i++)
buf[index++] = headerODSFirst[i];
for (int i = 0; i < bufSize; i++)
// write first OBJ
int bufSize = rleBuf.Length;
int rleIndex = 0;
if (bufSize > 0xffe4)
bufSize = 0xffe4;
PacketHeader[10] = 0x15; // ID
timeStamp = dts + imageDecodeTime;
ToolBox.SetDWord(PacketHeader, 2, timeStamp); // PTS
ToolBox.SetDWord(PacketHeader, 6, dts); // DTS
ToolBox.SetWord(PacketHeader, 11, HeaderODSFirst.Length + bufSize); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
int marker = (int)((numAddPackets == 0) ? 0xC0000000 : 0x80000000);
ToolBox.SetDWord(HeaderODSFirst, 3, marker | (rleBuf.Length + 4));
ToolBox.SetWord(HeaderODSFirst, 7, bm.Width);
ToolBox.SetWord(HeaderODSFirst, 9, bm.Height);
for (int i = 0; i < HeaderODSFirst.Length; i++)
buf[index++] = HeaderODSFirst[i];
for (int i = 0; i < bufSize; i++)
buf[index++] = rleBuf[rleIndex++];
// write additional OBJ packets
bufSize = rleBuf.Length - bufSize; // remaining bytes to write
for (int p = 0; p < numAddPackets; p++)
{
int psize = bufSize;
if (psize > 0xffeb)
psize = 0xffeb;
PacketHeader[10] = 0x15; // ID (keep DTS & PTS)
ToolBox.SetWord(PacketHeader, 11, HeaderODSNext.Length + psize); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
for (int i = 0; i < HeaderODSNext.Length; i++)
buf[index++] = HeaderODSNext[i];
for (int i = 0; i < psize; i++)
buf[index++] = rleBuf[rleIndex++];
bufSize -= psize;
}
// write additional OBJ packets
bufSize = rleBuf.Length - bufSize; // remaining bytes to write
for (int p = 0; p < numAddPackets; p++)
{
int psize = bufSize;
if (psize > 0xffeb)
psize = 0xffeb;
packetHeader[10] = 0x15; // ID (keep DTS & PTS)
ToolBox.SetWord(packetHeader, 11, headerODSNext.Length + psize); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
for (int i = 0; i < headerODSNext.Length; i++)
buf[index++] = headerODSNext[i];
for (int i = 0; i < psize; i++)
buf[index++] = rleBuf[rleIndex++];
bufSize -= psize;
}
// write END
PacketHeader[10] = 0x80; // ID
ToolBox.SetDWord(PacketHeader, 6, 0); // DTS (0) (keep PTS of ODS)
ToolBox.SetWord(PacketHeader, 11, 0); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
// write END
packetHeader[10] = (byte)0x80; // ID
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0) (keep PTS of ODS)
ToolBox.SetWord(packetHeader, 11, 0); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
// write PCS end
PacketHeader[10] = 0x16; // ID
ToolBox.SetDWord(PacketHeader, 2, pic.EndTimeForWrite); // PTS
dts = pic.StartTimeForWrite - 1;
ToolBox.SetDWord(PacketHeader, 6, dts); // DTS
ToolBox.SetWord(PacketHeader, 11, HeaderPCSEnd.Length); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
ToolBox.SetWord(HeaderPCSEnd, 0, pic.Width);
ToolBox.SetWord(HeaderPCSEnd, 2, h); // cropped height
ToolBox.SetByte(HeaderPCSEnd, 4, fpsId);
ToolBox.SetWord(HeaderPCSEnd, 5, pic.CompositionNumber + 1);
for (int i = 0; i < HeaderPCSEnd.Length; i++)
buf[index++] = HeaderPCSEnd[i];
// write PCS end
packetHeader[10] = 0x16; // ID
ToolBox.SetDWord(packetHeader, 2, pic.EndTimeForWrite); // PTS
dts = (int)pic.StartTimeForWrite - 1;
ToolBox.SetDWord(packetHeader, 6, dts); // DTS
ToolBox.SetWord(packetHeader, 11, headerPCSEnd.Length); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
ToolBox.SetWord(headerPCSEnd, 0, pic.Width);
ToolBox.SetWord(headerPCSEnd, 2, h); // cropped height
ToolBox.SetByte(headerPCSEnd, 4, fpsId);
ToolBox.SetWord(headerPCSEnd, 5, pic.CompositionNumber + 1);
for (int i = 0; i < headerPCSEnd.Length; i++)
buf[index++] = headerPCSEnd[i];
// write WDS
PacketHeader[10] = 0x17; // ID
timeStamp = pic.EndTimeForWrite - windowInitTime;
ToolBox.SetDWord(PacketHeader, 2, timeStamp); // PTS (keep DTS of PCS)
ToolBox.SetWord(PacketHeader, 11, HeaderWds.Length); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
ToolBox.SetWord(HeaderWds, 2, pic.WindowXOffset);
ToolBox.SetWord(HeaderWds, 4, yOfs);
ToolBox.SetWord(HeaderWds, 6, bm.Width);
ToolBox.SetWord(HeaderWds, 8, bm.Height);
for (int i = 0; i < HeaderWds.Length; i++)
buf[index++] = HeaderWds[i];
// write WDS
packetHeader[10] = 0x17; // ID
timeStamp = pic.EndTimeForWrite - windowInitTime;
ToolBox.SetDWord(packetHeader, 2, timeStamp); // PTS (keep DTS of PCS)
ToolBox.SetWord(packetHeader, 11, headerWDS.Length); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
ToolBox.SetWord(headerWDS, 2, pic.WindowXOffset);
ToolBox.SetWord(headerWDS, 4, yOfs);
ToolBox.SetWord(headerWDS, 6, bm.Width);
ToolBox.SetWord(headerWDS, 8, bm.Height);
for (int i = 0; i < headerWDS.Length; i++)
buf[index++] = headerWDS[i];
// write END
packetHeader[10] = (byte)0x80; // ID
ToolBox.SetDWord(packetHeader, 2, dts); // PTS (DTS of end PCS)
ToolBox.SetDWord(packetHeader, 6, 0); // DTS (0)
ToolBox.SetWord(packetHeader, 11, 0); // size
for (int i = 0; i < packetHeader.Length; i++)
buf[index++] = packetHeader[i];
// write END
PacketHeader[10] = 0x80; // ID
ToolBox.SetDWord(PacketHeader, 2, dts); // PTS (DTS of end PCS)
ToolBox.SetDWord(PacketHeader, 6, 0); // DTS (0)
ToolBox.SetWord(PacketHeader, 11, 0); // size
for (int i = 0; i < PacketHeader.Length; i++)
buf[index++] = PacketHeader[i];
return buf;
}

View File

@ -10,67 +10,67 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
/// <summary>
/// 14 bytes Mpeg 2 pack header
/// </summary>
private static byte[] Mpeg2PackHeaderBuffer =
private static readonly byte[] Mpeg2PackHeaderBuffer =
{
0x00, 0x00, 0x01, // Start code
0xba, // MPEG-2 Pack ID
0x44, 0x02, 0xec, 0xdf, // System clock reference
0xfe, 0x57,
0x01, 0x89, 0xc3, // Program mux rate
0xf8, // stuffing byte
0xf8 // stuffing byte
};
/// <summary>
/// 9 bytes packetized elementary stream header (PES)
/// </summary>
private static byte[] PacketizedElementaryStreamHeaderBufferFirst =
private static readonly byte[] PacketizedElementaryStreamHeaderBufferFirst =
{
0x00, 0x00, 0x01, // Start code
0xbd, // bd = Private stream 1 (non MPEG audio, subpictures)
0x00, 0x00, // 18-19=PES packet length
0x81, // 20=Flags: PES scrambling control, PES priority, data alignment indicator, copyright, original or copy
0x81, // 21=Flags: PTS DTS flags, ESCR flag, ES rate flag, DSM trick mode flag, additional copy info flag, PES CRC flag, PES extension flag
0x08, // 22=PES header data length
0x08 // 22=PES header data length
};
/// <summary>
/// 9 bytes packetized elementary stream header (PES)
/// </summary>
private static byte[] PacketizedElementaryStreamHeaderBufferNext =
private static readonly byte[] PacketizedElementaryStreamHeaderBufferNext =
{
0x00, 0x00, 0x01, // Start code
0xbd, // bd = Private stream 1 (non MPEG audio, subpictures)
0x00, 0x00, // PES packet length
0x81, // 20=Flags: PES scrambling control, PES priority, data alignment indicator, copyright, original or copy
0x00, // 21=Flags: PTS DTS flags, ESCR flag, ES rate flag, DSM trick mode flag, additional copy info flag, PES CRC flag, PES extension flag
0x00, // 22=PES header data length
0x00 // 22=PES header data length
};
/// <summary>
/// 5 bytes presentation time stamp (PTS)
/// </summary>
private static byte[] PresentationTimeStampBuffer =
private static readonly byte[] PresentationTimeStampBuffer =
{
0x21, // 0010 3=PTS 32..30 1
0x00, 0x01, // 15=PTS 29..15 1
0x00, 0x01, // 15=PTS 14..00 1
0x00, 0x01 // 15=PTS 14..00 1
};
private const int PacketizedElementaryStreamMaximumLength = 2028;
private string _subFileName;
private readonly string _subFileName;
private FileStream _subFile;
StringBuilder _idx = new StringBuilder();
int _screenWidth = 720;
int _screenHeight = 480;
int _bottomMargin = 15;
int _languageStreamId = 32;
readonly StringBuilder _idx = new StringBuilder();
readonly int _screenWidth = 720;
readonly int _screenHeight = 480;
readonly int _bottomMargin = 15;
readonly int _languageStreamId = 32;
Color _background = Color.Transparent;
Color _pattern = Color.White;
Color _emphasis1 = Color.Black;
Color _emphasis2 = Color.FromArgb(240, Color.Black);
string _languageName = "English";
string _languageNameShort = "en";
readonly string _languageName = "English";
readonly string _languageNameShort = "en";
public VobSubWriter(string subFileName, int screenWidth, int screenHeight, int bottomMargin, int languageStreamId, Color pattern, Color emphasis1, Color emphasis2,
string languageName, string languageNameShort)
@ -107,7 +107,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
WriteEndianWord(startDisplayControlSequenceTableAddress, ms);
// Write image
int imageTopFieldDataAddress = (int)(4);
const int imageTopFieldDataAddress = 4;
ms.Write(twoPartBuffer.Buffer1, 0, twoPartBuffer.Buffer1.Length);
int imageBottomFieldDataAddress = 4 + twoPartBuffer.Buffer1.Length;
ms.Write(twoPartBuffer.Buffer2, 0, twoPartBuffer.Buffer2.Length);
@ -139,7 +139,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
// Control Sequence Table
// Write delay - subtitle duration
WriteEndianWord((int)((Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0 - 1023) >> 10)), ms);
WriteEndianWord(Convert.ToInt32(p.Duration.TotalMilliseconds * 90.0 - 1023) >> 10, ms);
// next display control sequence table address (use current is last)
WriteEndianWord(startDisplayControlSequenceTableAddress + 24, ms); // start of display control sequence table address
@ -207,8 +207,8 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
int length = Mpeg2PackHeaderBuffer.Length + imageBuffer.Length - subtract;
if (length > PacketizedElementaryStreamMaximumLength)
{
writeBuffer[4] = (byte)(PacketizedElementaryStreamMaximumLength / 256);
writeBuffer[5] = (byte)(PacketizedElementaryStreamMaximumLength % 256);
writeBuffer[4] = PacketizedElementaryStreamMaximumLength / 256;
writeBuffer[5] = PacketizedElementaryStreamMaximumLength % 256;
}
else
{
@ -242,7 +242,6 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
/// <summary>
/// Directly provides the four contrast (alpha blend) values to associate with the four pixel values. One nibble per pixel value for a total of 2 bytes. 0x0 = transparent, 0xF = opaque
/// </summary>
/// <param name="_subFile"></param>
private void WriteContrast(Stream stream)
{
stream.WriteByte(4);
@ -256,14 +255,14 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
private void WriteColors(Stream stream)
{
// Index to palette
byte emphasis2 = 3;
byte emphasis1 = 2;
byte pattern = 1;
byte background = 0;
const byte emphasis2 = 3;
const byte emphasis1 = 2;
const byte pattern = 1;
const byte background = 0;
stream.WriteByte(3);
stream.WriteByte((byte)((emphasis2 << 4) | emphasis1)); // emphasis2 + emphasis1
stream.WriteByte((byte)((pattern << 4) | background)); // pattern + background
stream.WriteByte((emphasis2 << 4) | emphasis1); // emphasis2 + emphasis1
stream.WriteByte((pattern << 4) | background); // pattern + background
}
/// <summary>
@ -271,7 +270,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
/// </summary>
private void FillPTS(TimeCode timeCode)
{
string pre = "0011"; // 0011 or 0010 ?
const string pre = "0011"; // 0011 or 0010 ?
long newPts = (long)(timeCode.TotalSeconds * 90000.0 + 0.5);
string bString = Convert.ToString(newPts, 2).PadLeft(33, '0');
string fiveBytesString = pre + bString.Substring(0, 3) + "1" + bString.Substring(3, 15) + "1" + bString.Substring(18, 15) + "1";
@ -292,7 +291,7 @@ namespace Nikse.SubtitleEdit.Logic.VobSub
public void WriteIdxFile()
{
string idxFileName = _subFileName.Substring(0, _subFileName.Length - 3) + "idx";
System.IO.File.WriteAllText(idxFileName, _idx.ToString().Trim());
File.WriteAllText(idxFileName, _idx.ToString().Trim());
}
private StringBuilder CreateIdxHeader()