Initial work on TS convert

Work on #3633
This commit is contained in:
Nikolaj Olsson 2019-10-04 17:23:12 +02:00
parent a39667d7a4
commit cc648246e7
9 changed files with 227 additions and 67 deletions

View File

@ -305,6 +305,15 @@ namespace Nikse.SubtitleEdit.Core.BluRaySup
return mergedBmp;
}
public Position GetPosition()
{
if (PcsObjects.Count > 0)
{
return new Position(PcsObjects[0].Origin.X, PcsObjects[0].Origin.X);
}
return new Position(0,0);
}
public TimeCode StartTimeCode => new TimeCode(StartTime / 90.0);
public TimeCode EndTimeCode => new TimeCode(EndTime / 90.0);
}

View File

@ -198,6 +198,7 @@
<Compile Include="ImageSplitterItem.cs" />
<Compile Include="Interfaces\IRtfTextConverter.cs" />
<Compile Include="PlainTextImporter.cs" />
<Compile Include="Position.cs" />
<Compile Include="SeJsonValidator.cs" />
<Compile Include="SeJsonParser.cs" />
<Compile Include="SeLogger.cs" />

View File

@ -728,7 +728,8 @@ namespace Nikse.SubtitleEdit.Core
return leftStart;
}
public void CropSidesAndBottom(int maximumCropping, Color transparentColor, bool bottom)
/// <returns>Pixels cropped left</returns>
public int CropSidesAndBottom(int maximumCropping, Color transparentColor, bool bottom)
{
int leftStart = 0;
bool done = false;
@ -808,13 +809,13 @@ namespace Nikse.SubtitleEdit.Core
if (leftStart < 2 && rightEnd >= Width - 3)
{
return;
return 0;
}
int newWidth = rightEnd - leftStart + 1;
if (newWidth <= 0)
{
return;
return 0;
}
var newBitmapData = new byte[newWidth * newHeight * 4];
@ -829,6 +830,7 @@ namespace Nikse.SubtitleEdit.Core
Width = newWidth;
Height = newHeight;
_bitmapData = newBitmapData;
return leftStart;
}
public void CropTop(int maximumCropping, Color transparentColor)

14
libse/Position.cs Normal file
View File

@ -0,0 +1,14 @@
namespace Nikse.SubtitleEdit.Core
{
public class Position
{
public int Left { get; set; }
public int Top { get; set; }
public Position(int left, int top)
{
Left = left;
Top = top;
}
}
}

View File

@ -1,8 +1,11 @@
using System.Drawing;
using System.Linq.Expressions;
using System.Runtime.Remoting.Messaging;
using Nikse.SubtitleEdit.Core.Interfaces;
namespace Nikse.SubtitleEdit.Core.TransportStream
{
public class TransportStreamSubtitle
public class TransportStreamSubtitle
{
private ulong _startMilliseconds;
@ -68,7 +71,7 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
/// Gets full image if 'ActiveImageIndex' not set, otherwise only gets image by index
/// </summary>
/// <returns></returns>
public Bitmap GetActiveImage()
public Bitmap GetBitmap()
{
if (_bdSup != null)
{
@ -83,6 +86,28 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
return Pes.GetImageFull();
}
public bool IsForced
{
get
{
if (_bdSup != null)
{
return _bdSup.IsForced;
}
return false;
}
}
public Position GetPosition()
{
if (_bdSup != null)
{
return _bdSup.GetPosition();
}
return new Position(0, 0);
}
public int NumberOfImages
{
get

View File

@ -41,7 +41,8 @@ namespace Nikse.SubtitleEdit.Forms
public string FileName { get; set; }
public string ToFormat { get; set; }
public SubtitleFormat SourceFormat { get; set; }
public ThreadDoWorkParameter(bool fixCommonErrors, bool multipleReplace, bool fixRtl, bool splitLongLinesActive, bool autoBalance, bool setMinDisplayTimeBetweenSubtitles, ListViewItem item, Subtitle subtitle, SubtitleFormat format, Encoding encoding, string language, string fileName, string toFormat, SubtitleFormat sourceFormat)
public List<IBinaryParagraph> BinaryParagraphs { get; set; }
public ThreadDoWorkParameter(bool fixCommonErrors, bool multipleReplace, bool fixRtl, bool splitLongLinesActive, bool autoBalance, bool setMinDisplayTimeBetweenSubtitles, ListViewItem item, Subtitle subtitle, SubtitleFormat format, Encoding encoding, string language, string fileName, string toFormat, SubtitleFormat sourceFormat, List<IBinaryParagraph> binaryParagraphs)
{
FixCommonErrors = fixCommonErrors;
MultipleReplaceActive = multipleReplace;
@ -57,6 +58,7 @@ namespace Nikse.SubtitleEdit.Forms
FileName = fileName;
ToFormat = toFormat;
SourceFormat = sourceFormat;
BinaryParagraphs = binaryParagraphs;
}
}
@ -308,6 +310,7 @@ namespace Nikse.SubtitleEdit.Forms
var mkvSsa = new List<string>();
var mkvAss = new List<string>();
int mkvCount = 0;
var isTs = false;
SubtitleFormat format = null;
var sub = new Subtitle();
@ -394,6 +397,11 @@ namespace Nikse.SubtitleEdit.Forms
item.SubItems.Add(Configuration.Settings.Language.UnknownSubtitle.Title);
}
}
else if ((ext.Equals(".ts", StringComparison.OrdinalIgnoreCase) || ext.Equals(".m2ts", StringComparison.OrdinalIgnoreCase)) &&
(FileUtil.IsTransportStream(fileName) || FileUtil.IsM2TransportStream(fileName)))
{
isTs = true;
}
else
{
item.SubItems.Add(Configuration.Settings.Language.UnknownSubtitle.Title);
@ -453,6 +461,14 @@ namespace Nikse.SubtitleEdit.Forms
item.SubItems.Add("-");
}
}
else if (isTs)
{
item = new ListViewItem(fileName);
item.SubItems.Add(Utilities.FormatBytesToDisplayFileSize(fi.Length));
listViewInputFiles.Items.Add(item);
item.SubItems.Add("Transport Stream");
item.SubItems.Add("-");
}
else
{
listViewInputFiles.Items.Add(item);
@ -578,9 +594,9 @@ namespace Nikse.SubtitleEdit.Forms
_errors = 0;
_abort = false;
BackgroundWorker worker1 = SpawnWorker();
BackgroundWorker worker2 = SpawnWorker();
BackgroundWorker worker3 = SpawnWorker();
var worker1 = SpawnWorker();
var worker2 = SpawnWorker();
var worker3 = SpawnWorker();
listViewInputFiles.BeginUpdate();
foreach (ListViewItem item in listViewInputFiles.Items)
@ -598,6 +614,7 @@ namespace Nikse.SubtitleEdit.Forms
string fileName = item.Text;
try
{
var binaryParagraphs = new List<IBinaryParagraph>();
SubtitleFormat format = null;
var sub = new Subtitle();
var fi = new FileInfo(fileName);
@ -646,8 +663,8 @@ namespace Nikse.SubtitleEdit.Forms
s = rtb.Text;
}
}
var uknownFormatImporter = new UknownFormatImporter { UseFrames = true };
var genericParseSubtitle = uknownFormatImporter.AutoGuessImport(s.SplitToLines());
var unknownFormatImporter = new UknownFormatImporter { UseFrames = true };
var genericParseSubtitle = unknownFormatImporter.AutoGuessImport(s.SplitToLines());
if (genericParseSubtitle.Paragraphs.Count > 1)
{
sub = genericParseSubtitle;
@ -672,6 +689,7 @@ namespace Nikse.SubtitleEdit.Forms
var bluRaySubtitles = new List<BluRaySupParser.PcsData>();
bool isVobSub = false;
bool isMatroska = false;
bool isTs = false;
if (format == null && fileName.EndsWith(".sup", StringComparison.OrdinalIgnoreCase) && FileUtil.IsBluRaySup(fileName))
{
var log = new StringBuilder();
@ -685,13 +703,18 @@ namespace Nikse.SubtitleEdit.Forms
{
isMatroska = true;
}
if (format == null && bluRaySubtitles.Count == 0 && !isVobSub && !isMatroska)
else if (format == null && (fileName.EndsWith(".ts", StringComparison.OrdinalIgnoreCase) || fileName.EndsWith(".m2ts", StringComparison.OrdinalIgnoreCase)) && item.SubItems[2].Text.StartsWith("Transport Stream", StringComparison.Ordinal))
{
isTs = true;
}
if (format == null && bluRaySubtitles.Count == 0 && !isVobSub && !isMatroska && !isTs)
{
IncrementAndShowProgress();
}
else
{
if (isMatroska && (Path.GetExtension(fileName).Equals(".mkv", StringComparison.OrdinalIgnoreCase) || Path.GetExtension(fileName).Equals(".mks", StringComparison.OrdinalIgnoreCase)))
var ext = Path.GetExtension(fileName);
if (isMatroska && (ext.Equals(".mkv", StringComparison.OrdinalIgnoreCase) || ext.Equals(".mks", StringComparison.OrdinalIgnoreCase)))
{
using (var matroska = new MatroskaFile(fileName))
{
@ -820,9 +843,9 @@ namespace Nikse.SubtitleEdit.Forms
Core.Forms.DurationsBridgeGaps.BridgeGaps(sub, _bridgeGaps.MinMsBetweenLines, !_bridgeGaps.PreviousSubtitleTakesAllTime, Configuration.Settings.Tools.BridgeGapMilliseconds, null, null);
}
Paragraph prev = sub.GetParagraphOrDefault(0);
bool first = true;
foreach (Paragraph p in sub.Paragraphs)
var prev = sub.GetParagraphOrDefault(0);
var first = true;
foreach (var p in sub.Paragraphs)
{
if (checkBoxRemoveTextForHI.Checked)
{
@ -835,7 +858,7 @@ namespace Nikse.SubtitleEdit.Forms
}
if (!numericUpDownPercent.Value.Equals(100))
{
double toSpeedPercentage = Convert.ToDouble(numericUpDownPercent.Value) / 100.0;
var toSpeedPercentage = Convert.ToDouble(numericUpDownPercent.Value) / 100.0;
p.StartTime.TotalMilliseconds = p.StartTime.TotalMilliseconds * toSpeedPercentage;
p.EndTime.TotalMilliseconds = p.EndTime.TotalMilliseconds * toSpeedPercentage;
@ -884,7 +907,8 @@ namespace Nikse.SubtitleEdit.Forms
Application.DoEvents();
System.Threading.Thread.Sleep(100);
}
var parameter = new ThreadDoWorkParameter(checkBoxFixCommonErrors.Checked, checkBoxMultipleReplace.Checked, checkBoxFixRtl.Checked, checkBoxSplitLongLines.Checked, checkBoxAutoBalance.Checked, checkBoxSetMinimumDisplayTimeBetweenSubs.Checked, item, sub, GetCurrentSubtitleFormat(), GetCurrentEncoding(), Configuration.Settings.Tools.BatchConvertLanguage, fileName, toFormat, format);
var parameter = new ThreadDoWorkParameter(checkBoxFixCommonErrors.Checked, checkBoxMultipleReplace.Checked, checkBoxFixRtl.Checked, checkBoxSplitLongLines.Checked, checkBoxAutoBalance.Checked, checkBoxSetMinimumDisplayTimeBetweenSubs.Checked, item, sub, GetCurrentSubtitleFormat(), GetCurrentEncoding(), Configuration.Settings.Tools.BatchConvertLanguage, fileName, toFormat, format, binaryParagraphs);
if (!worker1.IsBusy)
{
worker1.RunWorkerAsync(parameter);
@ -1240,6 +1264,12 @@ namespace Nikse.SubtitleEdit.Forms
{
if (p.SourceFormat == null)
{
var ext = Path.GetExtension(p.FileName);
if ((ext.Equals(".ts", StringComparison.OrdinalIgnoreCase) || ext.Equals(".m2ts", StringComparison.OrdinalIgnoreCase)) &&
(FileUtil.IsTransportStream(p.FileName) || FileUtil.IsM2TransportStream(p.FileName)))
{
p.Item.SubItems[3].Text = Configuration.Settings.Language.General.PleaseWait;
}
p.SourceFormat = new SubRip();
}

View File

@ -99,7 +99,7 @@ namespace Nikse.SubtitleEdit.Forms
int pid = _tsParser.SubtitlePacketIds[listBoxTracks.SelectedIndex];
var list = _tsParser.GetDvbSubtitles(pid);
var dvbBmp = list[idx].GetActiveImage();
var dvbBmp = list[idx].GetBitmap();
var nDvbBmp = new NikseBitmap(dvbBmp);
nDvbBmp.CropTopTransparent(2);
nDvbBmp.CropTransparentSidesAndBottom(2, true);

View File

@ -14,6 +14,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using Nikse.SubtitleEdit.Core.TransportStream;
namespace Nikse.SubtitleEdit.Logic
{
@ -93,6 +94,7 @@ namespace Nikse.SubtitleEdit.Logic
_stdOutWriter.WriteLine("- For DOST/image .dost/image output use: '" + BatchConvert.DostImageSubtitle.RemoveChar(' ') + "'");
_stdOutWriter.WriteLine("- For BDN/XML .xml/image output use: '" + BatchConvert.BdnXmlSubtitle.RemoveChar(' ') + "'");
_stdOutWriter.WriteLine("- For FCP/image .xml/image output use: '" + BatchConvert.FcpImageSubtitle.RemoveChar(' ') + "'");
_stdOutWriter.WriteLine("- For plain text only output use: '" + Configuration.Settings.Language.BatchConvert.PlainText.RemoveChar(' ') + "'");
}
else
{
@ -386,7 +388,7 @@ namespace Nikse.SubtitleEdit.Logic
throw new Exception(string.Empty);
}
var formats = SubtitleFormat.AllSubtitleFormats;
var formats = SubtitleFormat.AllSubtitleFormats.ToList();
foreach (var fileName in files)
{
count++;
@ -562,6 +564,13 @@ namespace Nikse.SubtitleEdit.Logic
}
}
if (!done && (Path.GetExtension(fileName).Equals(".ts", StringComparison.OrdinalIgnoreCase) || Path.GetExtension(fileName).Equals(".m2ts", StringComparison.OrdinalIgnoreCase)) && (FileUtil.IsTransportStream(fileName) || FileUtil.IsM2TransportStream(fileName)))
{
BatchConvertSave(targetFormat, offset, targetEncoding, outputFolder, count, ref converted, ref errors, formats, fileName, sub, format, null, overwrite, pacCodePage, targetFrameRate, multipleReplaceImportFiles, actions, resolution, true);
done = true;
}
if (!done && fileInfo.Length < 10 * 1024 * 1024) // max 10 mb
{
format = sub.LoadSubtitle(fileName, out _, null, true, frameRate);
@ -1260,64 +1269,73 @@ namespace Nikse.SubtitleEdit.Logic
if (BatchConvert.BluRaySubtitle.RemoveChar(' ').Equals(targetFormat.RemoveChar(' '), StringComparison.OrdinalIgnoreCase))
{
targetFormatFound = true;
outputFileName = FormatOutputFileNameForBatchConvert(fileName, ".sup", outputFolder, overwrite);
_stdOutWriter?.Write($"{count}: {Path.GetFileName(fileName)} -> {outputFileName}...");
using (var form = new ExportPngXml())
var ext = Path.GetExtension(fileName);
if ((ext.Equals(".ts", StringComparison.OrdinalIgnoreCase) || ext.Equals(".m2ts", StringComparison.OrdinalIgnoreCase)) &&
(FileUtil.IsTransportStream(fileName) || FileUtil.IsM2TransportStream(fileName)))
{
form.Initialize(sub, format, ExportPngXml.ExportFormats.BluraySup, fileName, null, null);
int width = 1920;
int height = 1080;
if (!string.IsNullOrEmpty(Configuration.Settings.Tools.ExportBluRayVideoResolution))
ConvertFromTsToBluRaySup(fileName, outputFolder, overwrite, format, _stdOutWriter);
}
else
{
outputFileName = FormatOutputFileNameForBatchConvert(fileName, ".sup", outputFolder, overwrite);
_stdOutWriter?.Write($"{count}: {Path.GetFileName(fileName)} -> {outputFileName}...");
using (var form = new ExportPngXml())
{
var parts = Configuration.Settings.Tools.ExportBluRayVideoResolution.Split('x');
if (parts.Length == 2 && Utilities.IsInteger(parts[0]) && Utilities.IsInteger(parts[1]))
form.Initialize(sub, format, ExportPngXml.ExportFormats.BluraySup, fileName, null, null);
int width = 1920;
int height = 1080;
if (!string.IsNullOrEmpty(Configuration.Settings.Tools.ExportBluRayVideoResolution))
{
width = int.Parse(parts[0]);
height = int.Parse(parts[1]);
var parts = Configuration.Settings.Tools.ExportBluRayVideoResolution.Split('x');
if (parts.Length == 2 && Utilities.IsInteger(parts[0]) && Utilities.IsInteger(parts[1]))
{
width = int.Parse(parts[0]);
height = int.Parse(parts[1]);
}
if (resolution != null)
{
width = resolution.Value.X;
height = resolution.Value.Y;
}
}
if (resolution != null)
{
width = resolution.Value.X;
height = resolution.Value.Y;
}
}
using (var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create))
{
var isImageBased = IsImageBased(format);
for (int index = 0; index < sub.Paragraphs.Count; index++)
using (var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create))
{
var mp = form.MakeMakeBitmapParameter(index, width, height);
mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin;
if (binaryParagraphs != null && binaryParagraphs.Count > 0)
var isImageBased = IsImageBased(format);
for (int index = 0; index < sub.Paragraphs.Count; index++)
{
if (binaryParagraphs.Count > index)
var mp = form.MakeMakeBitmapParameter(index, width, height);
mp.LineJoin = Configuration.Settings.Tools.ExportPenLineJoin;
if (binaryParagraphs != null && binaryParagraphs.Count > 0)
{
mp.Bitmap = binaryParagraphs[index].GetBitmap();
mp.Forced = binaryParagraphs[index].IsForced;
if (binaryParagraphs.Count > index)
{
mp.Bitmap = binaryParagraphs[index].GetBitmap();
mp.Forced = binaryParagraphs[index].IsForced;
}
}
}
else if (isImageBased)
{
using (var ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(fileName), sub.Paragraphs[index].Text))))
else if (isImageBased)
{
mp.Bitmap = (Bitmap)Image.FromStream(ms);
using (var ms = new MemoryStream(File.ReadAllBytes(Path.Combine(Path.GetDirectoryName(fileName), sub.Paragraphs[index].Text))))
{
mp.Bitmap = (Bitmap)Image.FromStream(ms);
}
}
else
{
mp.Bitmap = ExportPngXml.GenerateImageFromTextWithStyle(mp);
}
ExportPngXml.MakeBluRaySupImage(mp);
binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
if (mp.Bitmap != null)
{
mp.Bitmap.Dispose();
mp.Bitmap = null;
}
if (index % 50 == 0)
{
System.Windows.Forms.Application.DoEvents();
}
}
else
{
mp.Bitmap = ExportPngXml.GenerateImageFromTextWithStyle(mp);
}
ExportPngXml.MakeBluRaySupImage(mp);
binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
if (mp.Bitmap != null)
{
mp.Bitmap.Dispose();
mp.Bitmap = null;
}
if (index % 50 == 0)
{
System.Windows.Forms.Application.DoEvents();
}
}
}
@ -1629,6 +1647,61 @@ namespace Nikse.SubtitleEdit.Logic
}
}
private static void ConvertFromTsToBluRaySup(string fileName, string outputFolder, bool overwrite, SubtitleFormat format, StreamWriter stdOutWriter)
{
var tsParser = new TransportStreamParser();
tsParser.Parse(fileName, (position, total) =>
{
var percent = (int)Math.Round(position * 100.0 / total);
stdOutWriter?.Write("\rParsing transport stream: {0}%", percent);
});
stdOutWriter?.Write("\r".PadRight(32, ' '));
stdOutWriter?.Write("\r");
var videoInfo = UiUtil.GetVideoInfo(fileName);
int width = 720;
int height = 576;
if (videoInfo.Success && videoInfo.Width > 0 && videoInfo.Height > 0)
{
width = videoInfo.Width;
height = videoInfo.Height;
}
foreach (int pid in tsParser.SubtitlePacketIds)
{
var outputFileName = FormatOutputFileNameForBatchConvert(Utilities.GetPathAndFileNameWithoutExtension(fileName) + "-" + pid + Path.GetExtension(fileName), ".sup", outputFolder, overwrite);
stdOutWriter?.WriteLine($"Saving PID {pid} to {outputFileName}...");
var sub = tsParser.GetDvbSubtitles(pid);
using (var binarySubtitleFile = new FileStream(outputFileName, FileMode.Create))
{
for (int index = 0; index < sub.Count; index++)
{
var p = sub[index];
var pos = p.GetPosition();
var bmp = sub[index].GetBitmap();
var nbmp = new NikseBitmap(bmp);
pos.Top += nbmp.CropTopTransparent(0);
pos.Left += nbmp.CropSidesAndBottom(0, Color.FromArgb(0, 0, 0, 0), true);
bmp.Dispose();
bmp = nbmp.GetBitmap();
var mp = new ExportPngXml.MakeBitmapParameter
{
Bitmap = bmp,
P = new Paragraph(string.Empty, p.StartMilliseconds, p.EndMilliseconds),
ScreenWidth = width,
ScreenHeight = height,
OverridePosition = new Point(pos.Left, pos.Top)
};
ExportPngXml.MakeBluRaySupImage(mp);
binarySubtitleFile.Write(mp.Buffer, 0, mp.Buffer.Length);
if (mp.Bitmap != null)
{
mp.Bitmap.Dispose();
mp.Bitmap = null;
}
}
}
}
}
private static bool IsImageBased(SubtitleFormat format)
{
return format is TimedTextImage || format is FinalCutProImage || format is SpuImage || format is Dost || format is SeImageHtmlIndex || format is BdnXml;

View File

@ -113,6 +113,12 @@ namespace Nikse.SubtitleEdit.Logic.Ocr.Tesseract
{
var sb = new StringBuilder();
var lineStart = html.IndexOf("<span class='ocr_line'", StringComparison.InvariantCulture);
var alternateLineStart = html.IndexOf("<span class='ocr_header'", StringComparison.InvariantCulture);
if (alternateLineStart > 0)
{
lineStart = Math.Min(lineStart, alternateLineStart);
}
while (lineStart > 0)
{
var wordStart = html.IndexOf("<span class='ocrx_word'", lineStart, StringComparison.InvariantCulture);