Work on mcc

This commit is contained in:
Nikolaj Olsson 2021-03-22 20:21:56 +01:00
parent 1db5589a4b
commit 927ba1a781
12 changed files with 196 additions and 44 deletions

View File

@ -1,6 +1,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Nikse.SubtitleEdit.Core.Cea708;
using Nikse.SubtitleEdit.Core.Cea708.Commands;
using System;
namespace Test.Logic.SubtitleFormats
{
@ -201,7 +202,7 @@ namespace Test.Logic.SubtitleFormats
var input = new byte[] { 0x73, 0xF2, 0xE0, 0x20, 0x20, 0x20, 0x7E, 0x7F, 0xFF, 0xE1, 0x65, 0x6E, 0x67, 0xC1, 0x7F, 0xFF };
var serviceInfoSection = new CcServiceInfoSection(input, 0);
var bytes = serviceInfoSection.GetBytes();
Assert.AreEqual(2, serviceInfoSection.CcServiceInfoSectionElement.Length);
Assert.AreEqual(2, serviceInfoSection.CcServiceInfoSectionElements.Length);
Assert.AreEqual(bytes.Length, input.Length);
for (var index = 0; index < input.Length; index++)
{
@ -221,5 +222,26 @@ namespace Test.Logic.SubtitleFormats
Assert.AreEqual(input[index], bytes[index]);
}
}
[TestMethod]
public void VancTest()
{
var s = VancDataWriter.GenerateLinesFromText("Hi!", 0)[0];
var smpte291M = new Smpte291M(HexStringToByteArray(s));
var result = smpte291M.GetText(0, true, new CommandState());
Assert.AreEqual("Hi!", result);
}
private static byte[] HexStringToByteArray(string hex)
{
var numberChars = hex.Length;
var bytes = new byte[numberChars / 2];
for (var i = 0; i < numberChars - 1; i += 2)
{
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
}
return bytes;
}
}
}

View File

@ -10,7 +10,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
/// <summary>
/// Should be 0x72 (114).
/// </summary>
public int DataSection { get; set; }
public int DataSection { get; set; }
public bool ProcessEmData { get; set; }
public bool ProcessCcData { get; set; }
public bool AdditionalData { get; set; }
@ -48,7 +48,13 @@ namespace Nikse.SubtitleEdit.Core.Cea708
ProcessEmData = true;
ProcessEmData = true;
if (bytes.Length / 2 > 16)
{
throw new Exception("Too many bytes for CCData!");
}
CcData = new CcData[ccDataCount];
int bytesIndex = 0;
for (int i = 0; i < ccDataCount; i++)
{
if (i == 0)
@ -81,9 +87,23 @@ namespace Nikse.SubtitleEdit.Core.Cea708
Data2 = 0x33,
};
}
else
else
{
CcData[i] = new CcData { Type = 2 };
if (bytesIndex < bytes.Length)
{
CcData[i].Valid = true;
CcData[i].Data1 = bytes[bytesIndex];
bytesIndex++;
if (bytesIndex < bytes.Length)
{
CcData[i].Data2 = bytes[bytesIndex];
}
bytesIndex++;
}
}
}

View File

@ -10,13 +10,35 @@ namespace Nikse.SubtitleEdit.Core.Cea708
public bool Change { get; set; }
public bool Complete { get; set; }
public int ServiceCount { get; set; }
public CcServiceInfoSectionElement[] CcServiceInfoSectionElement { get; set; }
public CcServiceInfoSectionElement[] CcServiceInfoSectionElements { get; set; }
public int GetLength()
{
return 2 + ServiceCount * 7;
}
public CcServiceInfoSection()
{
Id = 0x73;
Start = true;
Change = true;
Complete = true;
ServiceCount = 2;
CcServiceInfoSectionElements = new[]
{
new CcServiceInfoSectionElement
{
CaptionServiceNumber = 0,
ServiceDataByte = new byte[] { 32, 32, 32, 126, 127, 255},
},
new CcServiceInfoSectionElement
{
CaptionServiceNumber = 1,
ServiceDataByte = new byte[] { 101, 110, 103, 193, 127, 255},
},
};
}
public CcServiceInfoSection(byte[] bytes, int index)
{
Id = bytes[index];
@ -26,10 +48,10 @@ namespace Nikse.SubtitleEdit.Core.Cea708
Complete = (bytes[index + 1] & 0b00010000) > 0;
ServiceCount = bytes[index + 1] & 0b00001111;
CcServiceInfoSectionElement = new CcServiceInfoSectionElement[ServiceCount];
CcServiceInfoSectionElements = new CcServiceInfoSectionElement[ServiceCount];
for (int i = 0; i < ServiceCount; i++)
{
CcServiceInfoSectionElement[i] = new CcServiceInfoSectionElement
CcServiceInfoSectionElements[i] = new CcServiceInfoSectionElement
{
CaptionServiceNumber = bytes[index + i * 7 + 2] & 0b00011111,
ServiceDataByte =
@ -48,7 +70,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
public byte[] GetBytes()
{
var elementBytes = new List<byte>();
foreach (var element in CcServiceInfoSectionElement)
foreach (var element in CcServiceInfoSectionElements)
{
elementBytes.Add((byte)(0b11100000 | (element.CaptionServiceNumber & 0b00011111)));
foreach (var b in element.ServiceDataByte)

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Text;
using Nikse.SubtitleEdit.Core.Common;
namespace Nikse.SubtitleEdit.Core.Cea708
{
@ -10,7 +11,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
/// </summary>
public static class Cea708
{
public static bool DebugMode { get; set; } = false;
public static bool DebugMode { get; set; } = Configuration.Settings.SubtitleSettings.MccDebug;
private static readonly Dictionary<byte, string> SingleCharLookupTable = new Dictionary<byte, string>
{
@ -316,7 +317,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(clearWindows);
if (DebugMode)
{
debugBuilder.Append("{ClearWindows}");
debugBuilder.Append("{ClearWindows:" + clearWindows.Flags[0] + "," + clearWindows.Flags[1] + "," + clearWindows.Flags[2] + "," + clearWindows.Flags[3] + "," + clearWindows.Flags[4] + "," + clearWindows.Flags[5] + "," + clearWindows.Flags[6] + "," + clearWindows.Flags[7] + "}");
}
i++;
@ -328,7 +329,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(displayWindows);
if (DebugMode)
{
debugBuilder.Append("{DisplayWindows}");
debugBuilder.Append("{DisplayWindows:" + displayWindows.Flags[0] + "," + displayWindows.Flags[1] + "," + displayWindows.Flags[2] + "," + displayWindows.Flags[3] + "," + displayWindows.Flags[4] + "," + displayWindows.Flags[5] + "," + displayWindows.Flags[6] + "," + displayWindows.Flags[7] + "}");
}
i++;
@ -342,7 +343,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(hideWindows);
if (DebugMode)
{
debugBuilder.Append("{HideWindows}");
debugBuilder.Append("{HideWindows:" + hideWindows.Flags[0] + "," + hideWindows.Flags[1] + "," + hideWindows.Flags[2] + "," + hideWindows.Flags[3] + "," + hideWindows.Flags[4] + "," + hideWindows.Flags[5] + "," + hideWindows.Flags[6] + "," + hideWindows.Flags[7] + "}");
}
i++;
@ -354,7 +355,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(toggleWindows);
if (DebugMode)
{
debugBuilder.Append("{ToggleWindows}");
debugBuilder.Append("{ToggleWindows:" + toggleWindows.Flags[0] + "," + toggleWindows.Flags[1] + "," + toggleWindows.Flags[2] + "," + toggleWindows.Flags[3] + "," + toggleWindows.Flags[4] + "," + toggleWindows.Flags[5] + "," + toggleWindows.Flags[6] + "," + toggleWindows.Flags[7] + "}");
}
i++;
@ -366,7 +367,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(deleteWindows);
if (DebugMode)
{
debugBuilder.Append("{DeleteWindows}");
debugBuilder.Append("{DeleteWindows:" + deleteWindows.Flags[0] + "," + deleteWindows.Flags[1] + "," + deleteWindows.Flags[2] + "," + deleteWindows.Flags[3] + "," + deleteWindows.Flags[4] + "," + deleteWindows.Flags[5] + "," + deleteWindows.Flags[6] + "," + deleteWindows.Flags[7] + "}");
}
i++;
@ -415,7 +416,15 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(penAttributes);
if (DebugMode)
{
debugBuilder.Append("{SetPenAttributes:italic=" + penAttributes.Italics + "}");
//public int { get; set; }
//public int Offset { get; set; }
//public int TextTag { get; set; }
//public int FontTag { get; set; }
//public int EdgeType { get; set; }
//public bool Underline { get; set; }
//public bool Italics { get; set; }
debugBuilder.Append($"{{SetPenAttributes:PenSize={penAttributes.PenSize},Offset={penAttributes.Offset},TextTag={penAttributes.TextTag},FontTag={penAttributes.FontTag},EdgeType={penAttributes.EdgeType},Underline={penAttributes.Underline},Italic={penAttributes.Italics}}}");
}
i += 2;
@ -432,7 +441,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(penColor);
if (DebugMode)
{
debugBuilder.Append("{SetPenColor:color=r" + penColor.ForegroundColorRed + " g" + penColor.ForegroundColorGreen + " b" + penColor.ForegroundColorBlue + "}");
debugBuilder.Append($"{{SetPenColor:Foreground=r{penColor.ForegroundColorRed} g{penColor.ForegroundColorGreen} b{penColor.ForegroundColorBlue} op-{penColor.ForegroundOpacity}, Background=r{penColor.BackgroundColorRed} g{penColor.BackgroundColorGreen} b{penColor.BackgroundColorBlue} op-{penColor.BackgroundOpacity}, Edge=r{penColor.EdgeColorRed} g{penColor.EdgeColorGreen} b{penColor.EdgeColorBlue}}}");
}
i += 3;
@ -461,7 +470,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(windowAttributes);
if (DebugMode)
{
debugBuilder.Append("{SetWindowAttributes}");
debugBuilder.Append($"{{SetWindowAttributes:Justify={windowAttributes.Justify}, PrintDirection={windowAttributes.PrintDirection}, ScrollDirection={windowAttributes.ScrollDirection}, Wordwrap={windowAttributes.Wordwrap}, DisplayEffect={windowAttributes.DisplayEffect}, EffectDirection={windowAttributes.EffectDirection}, EffectSpeed={windowAttributes.EffectSpeed}, FillColorRed={windowAttributes.FillColorRed}, FillColorGreen={windowAttributes.FillColorGreen}, FillColorBlue={windowAttributes.FillColorBlue}, FillOpacity={windowAttributes.FillOpacity}, BorderType={windowAttributes.BorderType}, BorderColorRed={windowAttributes.BorderColorRed}, BorderColorGreen={windowAttributes.BorderColorGreen}, BorderColorBlue={windowAttributes.BorderColorBlue}}}");
}
i += 4;
@ -478,7 +487,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
state.Commands.Add(defineWindow);
if (DebugMode)
{
debugBuilder.Append("{DefineWindow:AnchorId=" + defineWindow.AnchorId + "}");
debugBuilder.Append($"{{DefineWindow:AnchorId={defineWindow.AnchorId}, AnchorV={defineWindow.AnchorVertical}, AnchorH={defineWindow.AnchorHorizontal}, Id={defineWindow.Id:X2}, Columns={defineWindow.ColumnCount}, Rows={defineWindow.RowCount}, RowLock={defineWindow.RowLock}, ColumnLock={defineWindow.ColumnLock}, PenStyleId={defineWindow.PenStyleId}, Priority={defineWindow.Priority}, RelativePositioning={defineWindow.RelativePositioning}, Visible={defineWindow.Visible}, WindowStyleId={defineWindow.WindowStyleId}}}");
}
i += 6;

View File

@ -18,9 +18,6 @@
public const int AnchorLowerRight = 8;
public int Id { get; set; }
public bool Active { get; set; }
public int Priority { get; set; }
public bool ColumnLock { get; set; }
public bool RowLock { get; set; }
@ -28,15 +25,36 @@
public int AnchorVertical { get; set; }
public bool RelativePositioning { get; set; }
public int AnchorHorizontal { get; set; }
public int RowCount { get; set; }
public int AnchorId { get; set; }
/// <summary>
/// The range is 0-15.
/// </summary>
public int ColumnCount { get; set; }
/// <summary>
/// The range is 0-31 for 4:3 streams, and 0-41 for 16:9 streams.
/// </summary>
public int RowCount { get; set; }
public int AnchorId { get; set; }
public int PenStyleId { get; set; }
public int WindowStyleId { get; set; }
public DefineWindow()
public DefineWindow(int numberOfLines)
{
//TODO: set default values...
Id = 0x99;
AnchorId = 0;
AnchorVertical = 65;
AnchorHorizontal = 70;
ColumnCount = 41;
RowCount = numberOfLines - 1;
RowLock = false;
ColumnLock = false;
PenStyleId = 1;
Priority = 0;
RelativePositioning = false;
Visible = false;
WindowStyleId = 2;
}
public DefineWindow(int lineIndex, byte[] bytes, int index)

View File

@ -14,8 +14,15 @@
public bool Underline { get; set; }
public bool Italics { get; set; }
public SetPenAttributes()
public SetPenAttributes(bool italic)
{
PenSize = 1;
Offset = 1;
TextTag = 0;
FontTag = 0;
EdgeType = 0;
Underline = false;
Italics = italic;
}
public SetPenAttributes(int lineIndex, byte[] bytes, int index)

View File

@ -23,6 +23,19 @@
public SetPenColor()
{
ForegroundColorRed = 2;
ForegroundColorGreen = 2;
ForegroundColorBlue = 2;
ForegroundOpacity = 0;
BackgroundColorRed = 0;
BackgroundColorGreen = 0;
BackgroundColorBlue = 0;
BackgroundOpacity = 0;
EdgeColorRed = 1;
EdgeColorGreen = 1;
EdgeColorBlue = 1;
}
public SetPenColor(int lineIndex, byte[] bytes, int index)

View File

@ -32,8 +32,23 @@
public int EffectDirection { get; set; }
public int EffectSpeed { get; set; }
public SetWindowAttributes()
public SetWindowAttributes(int justify)
{
Justify = justify;
PrintDirection = PrintDirectionTop;
ScrollDirection = 3;
Wordwrap = 0;
DisplayEffect = 0;
EffectDirection = 0;
EffectSpeed = 2;
FillColorRed = 1;
FillColorGreen = 1;
FillColorBlue = 1;
FillOpacity = 3;
BorderType = 0;
BorderColorRed = 1;
BorderColorGreen = 1;
BorderColorBlue = 1;
}
public SetWindowAttributes(int lineIndex, byte[] bytes, int index)

View File

@ -1,7 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Nikse.SubtitleEdit.Core.Cea708.Commands;
using System.Linq;
namespace Nikse.SubtitleEdit.Core.Cea708
{
@ -65,6 +62,7 @@ namespace Nikse.SubtitleEdit.Core.Cea708
CaptionDistributionPacketHeaderSequenceCounter = sequenceCount;
CcDataSectionCcData = new CcDataSection(ccDataCount, bytes);
CcServiceInfoSection = new CcServiceInfoSection();
}
public Smpte291M(byte[] bytes)

View File

@ -31,31 +31,52 @@ namespace Nikse.SubtitleEdit.Core.Cea708
public static string[] GenerateLinesFromText(string text, int counter)
{
//TODO: chunk in max 32 bytes chunks (do not split commands)
var results = new List<string>();
var bytes = new List<byte>();
var lines = text.SplitToLines();
var commands = new List<ICommand>
{
new DefineWindow(),
new SetWindowAttributes(),
new SetPenAttributes(),
new DefineWindow(lines.Count),
new SetWindowAttributes(SetWindowAttributes.JustifyCenter),
new SetPenAttributes(false),
new SetPenColor(),
};
foreach (var line in text.SplitToLines())
{
commands.Add(new SetPenLocation());
commands.Add(new SetText(line));
}
var bytes = new List<byte>();
foreach (var command in commands)
{
bytes.AddRange(command.GetBytes());
}
commands.Clear();
foreach (var line in lines)
{
var c1 = new SetPenLocation();
if (c1.GetBytes().Length + bytes.Count > 32)
{
counter = FlushCommands(counter, bytes, results);
}
bytes.AddRange(c1.GetBytes());
var c2 = new SetText(line);
if (c2.GetBytes().Length + bytes.Count > 32)
{
counter = FlushCommands(counter, bytes, results);
}
bytes.AddRange(c2.GetBytes());
}
FlushCommands(counter, bytes, results);
return results.ToArray();
}
private static int FlushCommands(int counter, List<byte> bytes, List<string> results)
{
var smpte291M = new Smpte291M(counter, 20, bytes.ToArray());
counter++;
var resultBytes = smpte291M.GetBytes();
var hex = ByteArrayToHexString(resultBytes);
return new[] { hex };
results.Add(hex);
bytes.Clear();
return counter;
}
public static string ByteArrayToHexString(byte[] bytes)

View File

@ -568,6 +568,7 @@ namespace Nikse.SubtitleEdit.Core.Common
public long WebVttTimescale { get; set; }
public bool TeletextItalicFix { get; set; }
public bool MccDebug { get; set; }
public SubtitleSettings()
{
@ -5281,6 +5282,12 @@ $HorzAlign = Center
settings.SubtitleSettings.TeletextItalicFix = Convert.ToBoolean(subNode.InnerText, CultureInfo.InvariantCulture);
}
subNode = node.SelectSingleNode("MccDebug");
if (subNode != null)
{
settings.SubtitleSettings.MccDebug = Convert.ToBoolean(subNode.InnerText, CultureInfo.InvariantCulture);
}
subNode = node.SelectSingleNode("WebVttUseXTimestampMap");
if (subNode != null)
{
@ -8528,6 +8535,7 @@ $HorzAlign = Center
textWriter.WriteElementString("NuendoCharacterListFile", settings.SubtitleSettings.NuendoCharacterListFile);
textWriter.WriteElementString("WebVttTimescale", settings.SubtitleSettings.WebVttTimescale.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("TeletextItalicFix", settings.SubtitleSettings.TeletextItalicFix.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("MccDebug", settings.SubtitleSettings.MccDebug.ToString(CultureInfo.InvariantCulture));
textWriter.WriteElementString("WebVttUseXTimestampMap", settings.SubtitleSettings.WebVttUseXTimestampMap.ToString(CultureInfo.InvariantCulture));
textWriter.WriteEndElement();

View File

@ -179,7 +179,6 @@ namespace Nikse.SubtitleEdit.Core.SubtitleFormats
return sb.ToString();
}
private static byte[] HexStringToByteArray(string hex)
{
var numberChars = hex.Length;