mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-26 05:02:36 +01:00
Use language info from ts files
This commit is contained in:
parent
56b3f59f87
commit
06bf912e29
@ -221,9 +221,7 @@ namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
var tsp = new TransportStreamParser();
|
||||
tsp.DetectFormat(fs);
|
||||
return tsp.IsM2TransportStream;
|
||||
return TransportStreamParser.IsM3TransportStream(fs);
|
||||
}
|
||||
}
|
||||
|
||||
|
257
libse/IsoCountryCodes.cs
Normal file
257
libse/IsoCountryCodes.cs
Normal file
@ -0,0 +1,257 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core
|
||||
{
|
||||
public class IsoCountryCodes
|
||||
{
|
||||
public static Dictionary<string, string> ThreeToTweLetterLookup = new Dictionary<string, string>
|
||||
{
|
||||
{ "AFG", "AF" },
|
||||
{ "ALA", "AX" },
|
||||
{ "ALB", "AL" },
|
||||
{ "DZA", "DZ" },
|
||||
{ "ASM", "AS" },
|
||||
{ "AND", "AD" },
|
||||
{ "AGO", "AO" },
|
||||
{ "AIA", "AI" },
|
||||
{ "ATG", "AG" },
|
||||
{ "ARG", "AR" },
|
||||
{ "ARM", "AM" },
|
||||
{ "ABW", "AW" },
|
||||
{ "AUS", "AU" },
|
||||
{ "AUT", "AT" },
|
||||
{ "AZE", "AZ" },
|
||||
{ "BHS", "BS" },
|
||||
{ "BHR", "BH" },
|
||||
{ "BGD", "BD" },
|
||||
{ "BRB", "BB" },
|
||||
{ "BLR", "BY" },
|
||||
{ "BEL", "BE" },
|
||||
{ "BLZ", "BZ" },
|
||||
{ "BEN", "BJ" },
|
||||
{ "BMU", "BM" },
|
||||
{ "BTN", "BT" },
|
||||
{ "BOL", "BO" },
|
||||
{ "BIH", "BA" },
|
||||
{ "BWA", "BW" },
|
||||
{ "BVT", "BV" },
|
||||
{ "BRA", "BR" },
|
||||
{ "VGB", "VG" },
|
||||
{ "IOT", "IO" },
|
||||
{ "BRN", "BN" },
|
||||
{ "BGR", "BG" },
|
||||
{ "BFA", "BF" },
|
||||
{ "BDI", "BI" },
|
||||
{ "KHM", "KH" },
|
||||
{ "CMR", "CM" },
|
||||
{ "CAN", "CA" },
|
||||
{ "CPV", "CV" },
|
||||
{ "CYM", "KY" },
|
||||
{ "CAF", "CF" },
|
||||
{ "TCD", "TD" },
|
||||
{ "CHL", "CL" },
|
||||
{ "CHN", "CN" },
|
||||
{ "HKG", "HK" },
|
||||
{ "MAC", "MO" },
|
||||
{ "CXR", "CX" },
|
||||
{ "CCK", "CC" },
|
||||
{ "COL", "CO" },
|
||||
{ "COM", "KM" },
|
||||
{ "COG", "CG" },
|
||||
{ "COD", "CD" },
|
||||
{ "COK", "CK" },
|
||||
{ "CRI", "CR" },
|
||||
{ "CIV", "CI" },
|
||||
{ "HRV", "HR" },
|
||||
{ "CUB", "CU" },
|
||||
{ "CYP", "CY" },
|
||||
{ "CZE", "CZ" },
|
||||
{ "DAN", "DK" },
|
||||
{ "DJI", "DJ" },
|
||||
{ "DMA", "DM" },
|
||||
{ "DOM", "DO" },
|
||||
{ "ECU", "EC" },
|
||||
{ "EGY", "EG" },
|
||||
{ "SLV", "SV" },
|
||||
{ "GNQ", "GQ" },
|
||||
{ "ERI", "ER" },
|
||||
{ "EST", "EE" },
|
||||
{ "ETH", "ET" },
|
||||
{ "FLK", "FK" },
|
||||
{ "FRO", "FO" },
|
||||
{ "FJI", "FJ" },
|
||||
{ "FIN", "FI" },
|
||||
{ "FRA", "FR" },
|
||||
{ "GUF", "GF" },
|
||||
{ "PYF", "PF" },
|
||||
{ "ATF", "TF" },
|
||||
{ "GAB", "GA" },
|
||||
{ "GMB", "GM" },
|
||||
{ "GEO", "GE" },
|
||||
{ "DEU", "DE" },
|
||||
{ "GHA", "GH" },
|
||||
{ "GIB", "GI" },
|
||||
{ "GRC", "GR" },
|
||||
{ "GRL", "GL" },
|
||||
{ "GRD", "GD" },
|
||||
{ "GLP", "GP" },
|
||||
{ "GUM", "GU" },
|
||||
{ "GTM", "GT" },
|
||||
{ "GGY", "GG" },
|
||||
{ "GIN", "GN" },
|
||||
{ "GNB", "GW" },
|
||||
{ "GUY", "GY" },
|
||||
{ "HTI", "HT" },
|
||||
{ "HMD", "HM" },
|
||||
{ "VAT", "VA" },
|
||||
{ "HND", "HN" },
|
||||
{ "HUN", "HU" },
|
||||
{ "ISL", "IS" },
|
||||
{ "IND", "IN" },
|
||||
{ "IDN", "ID" },
|
||||
{ "IRN", "IR" },
|
||||
{ "IRQ", "IQ" },
|
||||
{ "IRL", "IE" },
|
||||
{ "IMN", "IM" },
|
||||
{ "ISR", "IL" },
|
||||
{ "ITA", "IT" },
|
||||
{ "JAM", "JM" },
|
||||
{ "JPN", "JP" },
|
||||
{ "JEY", "JE" },
|
||||
{ "JOR", "JO" },
|
||||
{ "KAZ", "KZ" },
|
||||
{ "KEN", "KE" },
|
||||
{ "KIR", "KI" },
|
||||
{ "PRK", "KP" },
|
||||
{ "KOR", "KR" },
|
||||
{ "KWT", "KW" },
|
||||
{ "KGZ", "KG" },
|
||||
{ "LAO", "LA" },
|
||||
{ "LVA", "LV" },
|
||||
{ "LBN", "LB" },
|
||||
{ "LSO", "LS" },
|
||||
{ "LBR", "LR" },
|
||||
{ "LBY", "LY" },
|
||||
{ "LIE", "LI" },
|
||||
{ "LTU", "LT" },
|
||||
{ "LUX", "LU" },
|
||||
{ "MKD", "MK" },
|
||||
{ "MDG", "MG" },
|
||||
{ "MWI", "MW" },
|
||||
{ "MYS", "MY" },
|
||||
{ "MDV", "MV" },
|
||||
{ "MLI", "ML" },
|
||||
{ "MLT", "MT" },
|
||||
{ "MHL", "MH" },
|
||||
{ "MTQ", "MQ" },
|
||||
{ "MRT", "MR" },
|
||||
{ "MUS", "MU" },
|
||||
{ "MYT", "YT" },
|
||||
{ "MEX", "MX" },
|
||||
{ "FSM", "FM" },
|
||||
{ "MDA", "MD" },
|
||||
{ "MCO", "MC" },
|
||||
{ "MNG", "MN" },
|
||||
{ "MNE", "ME" },
|
||||
{ "MSR", "MS" },
|
||||
{ "MAR", "MA" },
|
||||
{ "MOZ", "MZ" },
|
||||
{ "MMR", "MM" },
|
||||
{ "NAM", "NA" },
|
||||
{ "NRU", "NR" },
|
||||
{ "NPL", "NP" },
|
||||
{ "NLD", "NL" },
|
||||
{ "ANT", "AN" },
|
||||
{ "NCL", "NC" },
|
||||
{ "NZL", "NZ" },
|
||||
{ "NIC", "NI" },
|
||||
{ "NER", "NE" },
|
||||
{ "NGA", "NG" },
|
||||
{ "NIU", "NU" },
|
||||
{ "NFK", "NF" },
|
||||
{ "MNP", "MP" },
|
||||
{ "NOR", "NO" },
|
||||
{ "OMN", "OM" },
|
||||
{ "PAK", "PK" },
|
||||
{ "PLW", "PW" },
|
||||
{ "PSE", "PS" },
|
||||
{ "PAN", "PA" },
|
||||
{ "PNG", "PG" },
|
||||
{ "PRY", "PY" },
|
||||
{ "PER", "PE" },
|
||||
{ "PHL", "PH" },
|
||||
{ "PCN", "PN" },
|
||||
{ "POL", "PL" },
|
||||
{ "PRT", "PT" },
|
||||
{ "PRI", "PR" },
|
||||
{ "QAT", "QA" },
|
||||
{ "REU", "RE" },
|
||||
{ "ROU", "RO" },
|
||||
{ "RUS", "RU" },
|
||||
{ "RWA", "RW" },
|
||||
{ "BLM", "BL" },
|
||||
{ "SHN", "SH" },
|
||||
{ "KNA", "KN" },
|
||||
{ "LCA", "LC" },
|
||||
{ "MAF", "MF" },
|
||||
{ "SPM", "PM" },
|
||||
{ "VCT", "VC" },
|
||||
{ "WSM", "WS" },
|
||||
{ "SMR", "SM" },
|
||||
{ "STP", "ST" },
|
||||
{ "SAU", "SA" },
|
||||
{ "SEN", "SN" },
|
||||
{ "SRB", "RS" },
|
||||
{ "SYC", "SC" },
|
||||
{ "SLE", "SL" },
|
||||
{ "SGP", "SG" },
|
||||
{ "SVK", "SK" },
|
||||
{ "SVN", "SI" },
|
||||
{ "SLB", "SB" },
|
||||
{ "SOM", "SO" },
|
||||
{ "ZAF", "ZA" },
|
||||
{ "SGS", "GS" },
|
||||
{ "SSD", "SS" },
|
||||
{ "ESP", "ES" },
|
||||
{ "LKA", "LK" },
|
||||
{ "SDN", "SD" },
|
||||
{ "SUR", "SR" },
|
||||
{ "SJM", "SJ" },
|
||||
{ "SWZ", "SZ" },
|
||||
{ "SWE", "SE" },
|
||||
{ "CHE", "CH" },
|
||||
{ "SYR", "SY" },
|
||||
{ "TWN", "TW" },
|
||||
{ "TJK", "TJ" },
|
||||
{ "TZA", "TZ" },
|
||||
{ "THA", "TH" },
|
||||
{ "TLS", "TL" },
|
||||
{ "TGO", "TG" },
|
||||
{ "TKL", "TK" },
|
||||
{ "TON", "TO" },
|
||||
{ "TTO", "TT" },
|
||||
{ "TUN", "TN" },
|
||||
{ "TUR", "TR" },
|
||||
{ "TKM", "TM" },
|
||||
{ "TCA", "TC" },
|
||||
{ "TUV", "TV" },
|
||||
{ "UGA", "UG" },
|
||||
{ "UKR", "UA" },
|
||||
{ "ARE", "AE" },
|
||||
{ "GBR", "GB" },
|
||||
{ "USA", "US" },
|
||||
{ "UMI", "UM" },
|
||||
{ "URY", "UY" },
|
||||
{ "UZB", "UZ" },
|
||||
{ "VUT", "VU" },
|
||||
{ "VEN", "VE" },
|
||||
{ "VNM", "VN" },
|
||||
{ "VIR", "VI" },
|
||||
{ "WLF", "WF" },
|
||||
{ "ESH", "EH" },
|
||||
{ "YEM", "YE" },
|
||||
{ "ZMB", "ZM" },
|
||||
{ "ZWE", "ZW" },
|
||||
};
|
||||
}
|
||||
}
|
@ -197,6 +197,7 @@
|
||||
<Compile Include="IfoParser.cs" />
|
||||
<Compile Include="ImageSplitterItem.cs" />
|
||||
<Compile Include="Interfaces\IRtfTextConverter.cs" />
|
||||
<Compile Include="IsoCountryCodes.cs" />
|
||||
<Compile Include="PlainTextImporter.cs" />
|
||||
<Compile Include="Position.cs" />
|
||||
<Compile Include="SeJsonValidator.cs" />
|
||||
@ -593,6 +594,10 @@
|
||||
<Compile Include="TransportStream\PageCompositionSegemnt.cs" />
|
||||
<Compile Include="TransportStream\PageCompositionSegmentRegion.cs" />
|
||||
<Compile Include="TransportStream\ProgramAssociationTable.cs" />
|
||||
<Compile Include="TransportStream\ProgramMapTable.cs" />
|
||||
<Compile Include="TransportStream\ProgramMapTableDescriptor.cs" />
|
||||
<Compile Include="TransportStream\ProgramMapTableParser.cs" />
|
||||
<Compile Include="TransportStream\ProgramMapTableStream.cs" />
|
||||
<Compile Include="TransportStream\RegionClutSegmentEntry.cs" />
|
||||
<Compile Include="TransportStream\RegionCompositionSegment.cs" />
|
||||
<Compile Include="TransportStream\RegionCompositionSegmentObject.cs" />
|
||||
|
@ -143,7 +143,7 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
|
||||
if (PacketId == ProgramAssociationTablePacketId) // PAT = Program Association Table: lists all programs available in the transport stream.
|
||||
{
|
||||
ProgramAssociationTable = new ProgramAssociationTable(packetBuffer, payloadStart + 1); // TODO: What index?
|
||||
ProgramAssociationTable = new ProgramAssociationTable(packetBuffer, payloadStart);
|
||||
}
|
||||
|
||||
// Save payload
|
||||
|
@ -16,6 +16,15 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
|
||||
public ProgramAssociationTable(byte[] packetBuffer, int index)
|
||||
{
|
||||
var pointer = packetBuffer[index];
|
||||
if (pointer > 0)
|
||||
{
|
||||
index += pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
index++;
|
||||
}
|
||||
TableId = packetBuffer[index];
|
||||
SectionLength = (packetBuffer[index + 1] & Helper.B00000011) * 256 + packetBuffer[index + 2];
|
||||
TransportStreamId = packetBuffer[index + 3] * 256 + packetBuffer[index + 4];
|
||||
@ -23,7 +32,6 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
CurrentNextIndicator = packetBuffer[index + 5] & 1;
|
||||
SectionNumber = packetBuffer[index + 6];
|
||||
LastSectionNumber = packetBuffer[index + 7];
|
||||
|
||||
ProgramNumbers = new List<int>();
|
||||
ProgramIds = new List<int>();
|
||||
index = index + 8;
|
||||
|
51
libse/TransportStream/ProgramMapTable.cs
Normal file
51
libse/TransportStream/ProgramMapTable.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
{
|
||||
public class ProgramMapTable
|
||||
{
|
||||
public int TableId { get; set; }
|
||||
public int SectionLength { get; set; }
|
||||
public int ProgramNumber { get; set; }
|
||||
public int VersionNumber { get; set; }
|
||||
public int CurrentNextIndicator { get; set; }
|
||||
public int SectionNumber { get; set; }
|
||||
public int LastSectionNumber { get; set; }
|
||||
public int PcrId { get; set; }
|
||||
public List<ProgramMapTableDescriptor> Descriptors { get; set; }
|
||||
public List<ProgramMapTableStream> Streams { get; set; }
|
||||
|
||||
public ProgramMapTable(byte[] packetBuffer, int index)
|
||||
{
|
||||
var pointer = packetBuffer[index];
|
||||
if (pointer > 0)
|
||||
{
|
||||
index += pointer;
|
||||
}
|
||||
else
|
||||
{
|
||||
index++;
|
||||
}
|
||||
TableId = packetBuffer[index];
|
||||
SectionLength = (packetBuffer[index + 1] & Helper.B00000011) * 256 + packetBuffer[index + 2];
|
||||
ProgramNumber = packetBuffer[index + 3] * 256 + packetBuffer[index + 4];
|
||||
VersionNumber = (packetBuffer[index + 5] & Helper.B00111110) >> 1;
|
||||
CurrentNextIndicator = packetBuffer[index + 5] & 1;
|
||||
SectionNumber = packetBuffer[index + 6];
|
||||
LastSectionNumber = packetBuffer[index + 7];
|
||||
PcrId = (packetBuffer[index + 8] & Helper.B00011111) * 256 + packetBuffer[index + 9];
|
||||
var programInfoLength = (packetBuffer[index + 10] & Helper.B00001111) * 256 + packetBuffer[index + 11];
|
||||
|
||||
Descriptors = ProgramMapTableDescriptor.ReadDescriptors(packetBuffer, programInfoLength, index + 12);
|
||||
var newIndex = index + 12 + Descriptors.Sum(p => p.Size);
|
||||
Streams = new List<ProgramMapTableStream>();
|
||||
while (newIndex - index < SectionLength - 4)
|
||||
{
|
||||
var stream = new ProgramMapTableStream(packetBuffer, newIndex);
|
||||
Streams.Add(stream);
|
||||
newIndex += stream.Size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
libse/TransportStream/ProgramMapTableDescriptor.cs
Normal file
76
libse/TransportStream/ProgramMapTableDescriptor.cs
Normal file
@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
{
|
||||
public class ProgramMapTableDescriptor
|
||||
{
|
||||
public const int TagCaDescriptor = 9;
|
||||
|
||||
public int Tag { get; set; }
|
||||
public byte[] CaSystemId { get; set; } = new byte[2];
|
||||
public uint CaPid { get; set; }
|
||||
public byte[] PrivateDataBytes { get; set; }
|
||||
public byte[] Content { get; set; }
|
||||
public string ContentAsString { get; set; }
|
||||
|
||||
public ProgramMapTableDescriptor(byte[] data, int index)
|
||||
{
|
||||
Tag = data[index];
|
||||
var length = data[index + 1];
|
||||
if (Tag == TagCaDescriptor)
|
||||
{
|
||||
Buffer.BlockCopy(data, index + 2, CaSystemId, 0, 2);
|
||||
|
||||
// 13 bytes (skip first 3)
|
||||
CaPid = (uint)((data[index + 4] & Helper.B00011111) * 256 + // first 5 bytes
|
||||
data[index + 5]); // last 8 bytes
|
||||
|
||||
PrivateDataBytes = new byte[length - 4];
|
||||
Buffer.BlockCopy(data, index + 6, PrivateDataBytes, 0, length - 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
Content = new byte[length];
|
||||
if (index + 2 + length < data.Length && length > 0)
|
||||
{
|
||||
Buffer.BlockCopy(data, index + 2, Content, 0, length);
|
||||
ContentAsString = Encoding.UTF8.GetString(Content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Tag == TagCaDescriptor)
|
||||
{
|
||||
return PrivateDataBytes.Length + 4;
|
||||
}
|
||||
|
||||
return Content.Length;
|
||||
}
|
||||
}
|
||||
|
||||
public int Size => Length + 2;
|
||||
|
||||
public static List<ProgramMapTableDescriptor> ReadDescriptors(byte[] data, int size, int index)
|
||||
{
|
||||
var total = 0;
|
||||
var descriptors = new List<ProgramMapTableDescriptor>();
|
||||
while (total < size)
|
||||
{
|
||||
var descriptor = new ProgramMapTableDescriptor(data, total + index);
|
||||
descriptors.Add(descriptor);
|
||||
total += descriptor.Size;
|
||||
if (total != size)
|
||||
{
|
||||
break; // Excepted {size} bytes of descriptors, but got {total} bytes of descriptors.
|
||||
}
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
}
|
||||
}
|
146
libse/TransportStream/ProgramMapTableParser.cs
Normal file
146
libse/TransportStream/ProgramMapTableParser.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
{
|
||||
public class ProgramMapTableParser
|
||||
{
|
||||
private List<ProgramMapTable> _programMapTables;
|
||||
public Exception Exception { get; set; }
|
||||
public ProgramMapTableParser()
|
||||
{
|
||||
_programMapTables = new List<ProgramMapTable>();
|
||||
}
|
||||
|
||||
public void Parse(string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var fs = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
Parse(fs);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
private const int MaxScanSize = 5000000;
|
||||
|
||||
/// <summary>
|
||||
/// Get Program Map Tables for a Transport Stream
|
||||
/// </summary>
|
||||
/// <param name="ms">Input stream</param>
|
||||
public void Parse(Stream ms)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
ms.Position = 0;
|
||||
const int packetLength = 188;
|
||||
var isM2TransportStream = TransportStreamParser.IsM3TransportStream(ms);
|
||||
var packetBuffer = new byte[packetLength];
|
||||
var m2TsTimeCodeBuffer = new byte[4];
|
||||
long position = 0;
|
||||
|
||||
// check for Topfield .rec file
|
||||
ms.Seek(position, SeekOrigin.Begin);
|
||||
ms.Read(m2TsTimeCodeBuffer, 0, 3);
|
||||
if (m2TsTimeCodeBuffer[0] == 0x54 && m2TsTimeCodeBuffer[1] == 0x46 && m2TsTimeCodeBuffer[2] == 0x72)
|
||||
{
|
||||
position = 3760;
|
||||
}
|
||||
|
||||
var pmtPids = new List<int>();
|
||||
_programMapTables = new List<ProgramMapTable>();
|
||||
long transportStreamLength = ms.Length;
|
||||
var max = Math.Min(transportStreamLength, MaxScanSize + position);
|
||||
while (position < max)
|
||||
{
|
||||
ms.Seek(position, SeekOrigin.Begin);
|
||||
|
||||
if (isM2TransportStream)
|
||||
{
|
||||
ms.Read(m2TsTimeCodeBuffer, 0, m2TsTimeCodeBuffer.Length);
|
||||
position += m2TsTimeCodeBuffer.Length;
|
||||
}
|
||||
|
||||
ms.Read(packetBuffer, 0, packetLength);
|
||||
byte syncByte = packetBuffer[0];
|
||||
|
||||
if (syncByte == Packet.SynchronizationByte)
|
||||
{
|
||||
var packet = new Packet(packetBuffer);
|
||||
|
||||
if (pmtPids.Contains(packet.PacketId))
|
||||
{
|
||||
var pmt = new ProgramMapTable(packet.Payload, 0);
|
||||
_programMapTables.Add(pmt);
|
||||
}
|
||||
else if (packet.IsProgramAssociationTable)
|
||||
{
|
||||
var pat = new ProgramAssociationTable(packet.Payload, 0);
|
||||
pmtPids.AddRange(pat.ProgramIds.Where(p => !pmtPids.Contains(p)));
|
||||
}
|
||||
|
||||
position += packetLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
public List<int> GetSubtitlePacketIds()
|
||||
{
|
||||
var list = new List<int>();
|
||||
foreach (var programMapTable in _programMapTables)
|
||||
{
|
||||
foreach (var stream in programMapTable.Streams)
|
||||
{
|
||||
if (stream.StreamType == ProgramMapTableStream.StreamTypePrivateData && !list.Contains(stream.ElementaryPid))
|
||||
{
|
||||
list.Add(stream.ElementaryPid);
|
||||
}
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public string GetSubtitleLanguage(int packetId)
|
||||
{
|
||||
foreach (var programMapTable in _programMapTables)
|
||||
{
|
||||
foreach (var stream in programMapTable.Streams)
|
||||
{
|
||||
if (stream.ElementaryPid == packetId)
|
||||
{
|
||||
return stream.GetLanguage();
|
||||
}
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string GetSubtitleLanguageTwoLetter(int packetId)
|
||||
{
|
||||
var language = GetSubtitleLanguage(packetId);
|
||||
var uppercaseLanguage = language.ToUpperInvariant();
|
||||
if (IsoCountryCodes.ThreeToTweLetterLookup.ContainsKey(uppercaseLanguage))
|
||||
{
|
||||
return IsoCountryCodes.ThreeToTweLetterLookup[uppercaseLanguage].ToLowerInvariant();
|
||||
}
|
||||
return language;
|
||||
}
|
||||
}
|
||||
}
|
109
libse/TransportStream/ProgramMapTableStream.cs
Normal file
109
libse/TransportStream/ProgramMapTableStream.cs
Normal file
@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
{
|
||||
public class ProgramMapTableStream
|
||||
{
|
||||
public const int StreamTypePrivateData = 6;
|
||||
public List<ProgramMapTableDescriptor> Descriptors;
|
||||
public int StreamType { get; set; }
|
||||
public int ElementaryPid { get; set; }
|
||||
public int Size { get; set; }
|
||||
|
||||
public ProgramMapTableStream(byte[] data, int index)
|
||||
{
|
||||
StreamType = data[index];
|
||||
|
||||
// 13 bytes (skip first 3)
|
||||
ElementaryPid = (data[index + 1] & Helper.B00011111) * 256 + // first 5 bytes
|
||||
data[index + 2]; // last 8 bytes
|
||||
|
||||
var esInfoLength = (data[index + 3] & Helper.B00001111) * 256 + // first 5 bytes
|
||||
data[index + 4]; // last 8 bytes
|
||||
|
||||
Descriptors = ProgramMapTableDescriptor.ReadDescriptors(data, esInfoLength, index + 5);
|
||||
Size = 5 + Descriptors.Sum(p => p.Size);
|
||||
}
|
||||
|
||||
public string GetStreamTypeString()
|
||||
{
|
||||
switch (StreamType)
|
||||
{
|
||||
case 0x00:
|
||||
return "ITU-T | ISO/IEC Reserved";
|
||||
case 0x01:
|
||||
return "ISO/IEC 11172 Video";
|
||||
case 0x02:
|
||||
return
|
||||
"ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream";
|
||||
case 0x03:
|
||||
return "ISO/IEC 11172 Audio";
|
||||
case 0x04:
|
||||
return "ISO/IEC 13818-3 Audio";
|
||||
case 0x05:
|
||||
return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections";
|
||||
case 0x06:
|
||||
return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data";
|
||||
case 0x07:
|
||||
return "ISO/IEC 13522 MHEG";
|
||||
case 0x08:
|
||||
return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC";
|
||||
case 0x09:
|
||||
return "ITU-T Rec. H.222.1";
|
||||
case 0x0A:
|
||||
return "ISO/IEC 13818-6 type A";
|
||||
case 0x0B:
|
||||
return "ISO/IEC 13818-6 type B";
|
||||
case 0x0C:
|
||||
return "ISO/IEC 13818-6 type C";
|
||||
case 0x0D:
|
||||
return "ISO/IEC 13818-6 type D";
|
||||
case 0x0E:
|
||||
return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary";
|
||||
case 0x0F:
|
||||
return "ISO/IEC 13818-7 Audio with ADTS transport syntax";
|
||||
case 0x10:
|
||||
return "ISO/IEC 14496-2 Visual";
|
||||
case 0x11:
|
||||
return "ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1";
|
||||
case 0x12:
|
||||
return "ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets";
|
||||
case 0x13:
|
||||
return "ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections";
|
||||
case 0x14:
|
||||
return "ISO/IEC 13818-6 Synchronized Download Protocol";
|
||||
case int n when (n < 0x15 && n >= 0x7F):
|
||||
return "ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved";
|
||||
default:
|
||||
return "User Private";
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetLanguage()
|
||||
{
|
||||
foreach (var descriptor in Descriptors)
|
||||
{
|
||||
if (descriptor.Tag != ProgramMapTableDescriptor.TagCaDescriptor)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in descriptor.Content)
|
||||
{
|
||||
if (b >= 32)
|
||||
{
|
||||
sb.Append(Convert.ToChar(b));
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -20,10 +20,7 @@ namespace Nikse.SubtitleEdit.Core.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; }
|
||||
private Dictionary<int, List<DvbSubPes>> SubtitlesLookup { get; set; }
|
||||
|
||||
private Dictionary<int, List<TransportStreamSubtitle>> DvbSubtitlesLookup { get; set; }
|
||||
public bool IsM2TransportStream { get; private set; }
|
||||
public ulong FirstVideoPts { get; private set; }
|
||||
@ -51,10 +48,9 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
TotalNumberOfPrivateStream1Continuation0 = 0;
|
||||
SubtitlePacketIds = new List<int>();
|
||||
SubtitlePackets = new List<Packet>();
|
||||
// ProgramAssociationTables = new List<Packet>();
|
||||
ms.Position = 0;
|
||||
const int packetLength = 188;
|
||||
DetectFormat(ms);
|
||||
IsM2TransportStream = IsM3TransportStream(ms);
|
||||
var packetBuffer = new byte[packetLength];
|
||||
var m2TsTimeCodeBuffer = new byte[4];
|
||||
long position = 0;
|
||||
@ -76,7 +72,6 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
if (IsM2TransportStream)
|
||||
{
|
||||
ms.Read(m2TsTimeCodeBuffer, 0, m2TsTimeCodeBuffer.Length);
|
||||
//var tc = (m2tsTimeCodeBuffer[0]<< 24) | (m2tsTimeCodeBuffer[1] << 16) | (m2tsTimeCodeBuffer[2] << 8) | (m2tsTimeCodeBuffer[3]);
|
||||
position += m2TsTimeCodeBuffer.Length;
|
||||
}
|
||||
|
||||
@ -109,38 +104,7 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
}
|
||||
else if (packet.IsProgramAssociationTable)
|
||||
{
|
||||
//var sb = new StringBuilder();
|
||||
//sb.AppendLine("PacketNo: " + TotalNumberOfPackets + 1);
|
||||
//sb.AppendLine("PacketId: " + packet.PacketId);
|
||||
//sb.AppendLine();
|
||||
//sb.AppendLine("TransportErrorIndicator: " + packet.TransportErrorIndicator);
|
||||
//sb.AppendLine("PayloadUnitStartIndicator: " + packet.PayloadUnitStartIndicator);
|
||||
//sb.AppendLine("TransportPriority: " + packet.TransportPriority);
|
||||
//sb.AppendLine("ScramblingControl: " + packet.ScramblingControl);
|
||||
//sb.AppendLine("AdaptationFieldExist: " + packet.AdaptationFieldControl);
|
||||
//sb.AppendLine("ContinuityCounter: " + packet.ContinuityCounter);
|
||||
//sb.AppendLine();
|
||||
//if (packet.AdaptationField != null)
|
||||
//{
|
||||
//sb.AppendLine("AdaptationFieldLength: " + packet.AdaptationField.Length);
|
||||
//sb.AppendLine("DiscontinuityIndicator: " + packet.AdaptationField.DiscontinuityIndicator);
|
||||
//sb.AppendLine("RandomAccessIndicator: " + packet.AdaptationField.RandomAccessIndicator);
|
||||
//sb.AppendLine("ElementaryStreamPriorityIndicator: " + packet.AdaptationField.ElementaryStreamPriorityIndicator);
|
||||
//sb.AppendLine("PcrFlag: " + packet.AdaptationField.PcrFlag);
|
||||
//sb.AppendLine("OpcrFlag: " + packet.AdaptationField.OpcrFlag);
|
||||
//sb.AppendLine("SplicingPointFlag: " + packet.AdaptationField.SplicingPointFlag);
|
||||
//sb.AppendLine("TransportPrivateDataFlag: " + packet.AdaptationField.TransportPrivateDataFlag);
|
||||
//sb.AppendLine("AdaptationFieldExtensionFlag: " + packet.AdaptationField.AdaptationFieldExtensionFlag);
|
||||
//sb.AppendLine();
|
||||
//}
|
||||
//sb.AppendLine("TableId: " + packet.ProgramAssociationTable.TableId);
|
||||
//sb.AppendLine("SectionLength: " + packet.ProgramAssociationTable.SectionLength);
|
||||
//sb.AppendLine("TransportStreamId: " + packet.ProgramAssociationTable.TransportStreamId);
|
||||
//sb.AppendLine("VersionNumber: " + packet.ProgramAssociationTable.VersionNumber);
|
||||
//sb.AppendLine("CurrentNextIndicator: " + packet.ProgramAssociationTable.CurrentNextIndicator);
|
||||
//sb.AppendLine("SectionNumber: " + packet.ProgramAssociationTable.SectionNumber);
|
||||
//sb.AppendLine("LastSectionNumber: " + packet.ProgramAssociationTable.LastSectionNumber);
|
||||
//ProgramAssociationTables.Add(packet);
|
||||
|
||||
}
|
||||
else if (packet.IsPrivateStream1 || SubtitlePacketIds.Contains(packet.PacketId))
|
||||
{
|
||||
@ -434,7 +398,7 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
list.Add(pes);
|
||||
}
|
||||
|
||||
internal void DetectFormat(Stream ms)
|
||||
public static bool IsM3TransportStream(Stream ms)
|
||||
{
|
||||
if (ms.Length > 192 + 192 + 5)
|
||||
{
|
||||
@ -443,14 +407,15 @@ namespace Nikse.SubtitleEdit.Core.TransportStream
|
||||
ms.Read(buffer, 0, buffer.Length);
|
||||
if (buffer[0] == Packet.SynchronizationByte && buffer[188] == Packet.SynchronizationByte)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer[4] == Packet.SynchronizationByte && buffer[192 + 4] == Packet.SynchronizationByte && buffer[192 + 192 + 4] == Packet.SynchronizationByte)
|
||||
{
|
||||
IsM2TransportStream = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsDvbSup(string fileName)
|
||||
|
@ -12044,8 +12044,16 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
{
|
||||
using (var formSubOcr = new VobSubOcr())
|
||||
{
|
||||
string language = null;
|
||||
var programMapTableParser = new ProgramMapTableParser();
|
||||
programMapTableParser.Parse(fileName); // get languages
|
||||
if (programMapTableParser.GetSubtitlePacketIds().Count > 0)
|
||||
{
|
||||
language = programMapTableParser.GetSubtitleLanguageTwoLetter(programMapTableParser.GetSubtitlePacketIds().First());
|
||||
}
|
||||
|
||||
var subtitles = TransportStreamParser.GetDvbSup(fileName);
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName);
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName, language);
|
||||
if (formSubOcr.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle);
|
||||
@ -12107,7 +12115,15 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
using (var formSubOcr = new VobSubOcr())
|
||||
{
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName);
|
||||
string language = null;
|
||||
var programMapTableParser = new ProgramMapTableParser();
|
||||
programMapTableParser.Parse(fileName); // get languages
|
||||
if (programMapTableParser.GetSubtitlePacketIds().Count > 0)
|
||||
{
|
||||
language = programMapTableParser.GetSubtitleLanguage(packedId);
|
||||
}
|
||||
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, fileName, language);
|
||||
if (formSubOcr.ShowDialog(this) == DialogResult.OK)
|
||||
{
|
||||
MakeHistoryForUndo(_language.BeforeImportingDvdSubtitle);
|
||||
|
@ -8740,8 +8740,7 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Get language from ts file
|
||||
internal void Initialize(List<TransportStreamSubtitle> subtitles, VobSubOcrSettings vobSubOcrSettings, string fileName)
|
||||
internal void Initialize(List<TransportStreamSubtitle> subtitles, VobSubOcrSettings vobSubOcrSettings, string fileName, string language)
|
||||
{
|
||||
buttonOK.Enabled = false;
|
||||
buttonCancel.Enabled = false;
|
||||
@ -8757,7 +8756,8 @@ namespace Nikse.SubtitleEdit.Forms.Ocr
|
||||
numericUpDownNumberOfPixelsIsSpaceNOCR.Value = vobSubOcrSettings.XOrMorePixelsMakesSpace;
|
||||
_vobSubOcrSettings = vobSubOcrSettings;
|
||||
|
||||
InitializeTesseract();
|
||||
InitializeTesseract(language);
|
||||
SetTesseractLanguageFromLanguageString(language);
|
||||
LoadImageCompareCharacterDatabaseList();
|
||||
|
||||
SetOcrMethod();
|
||||
|
@ -13,6 +13,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
{
|
||||
private TransportStreamParser _tsParser;
|
||||
private string _fileName;
|
||||
private ProgramMapTableParser _programMapTableParser;
|
||||
|
||||
public TransportStreamSubtitleChooser()
|
||||
{
|
||||
@ -50,14 +51,24 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
internal void Initialize(TransportStreamParser tsParser, string fileName)
|
||||
{
|
||||
_programMapTableParser = new ProgramMapTableParser();
|
||||
_programMapTableParser.Parse(fileName); // get languages
|
||||
_tsParser = tsParser;
|
||||
_fileName = fileName;
|
||||
Text = string.Format(Configuration.Settings.Language.TransportStreamSubtitleChooser.Title, fileName);
|
||||
|
||||
foreach (int id in tsParser.SubtitlePacketIds)
|
||||
{
|
||||
var language = _programMapTableParser.GetSubtitleLanguage(id);
|
||||
if (!string.IsNullOrEmpty(language))
|
||||
{
|
||||
listBoxTracks.Items.Add(string.Format(Configuration.Settings.Language.TransportStreamSubtitleChooser.PidLine, id + "=" + language, tsParser.GetDvbSubtitles(id).Count));
|
||||
}
|
||||
else
|
||||
{
|
||||
listBoxTracks.Items.Add(string.Format(Configuration.Settings.Language.TransportStreamSubtitleChooser.PidLine, id, tsParser.GetDvbSubtitles(id).Count));
|
||||
}
|
||||
}
|
||||
listBoxTracks.SelectedIndex = 0;
|
||||
}
|
||||
|
||||
@ -121,6 +132,18 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
return _tsParser.GetDvbSubtitles(pid);
|
||||
}
|
||||
|
||||
private string GetSelectedLanguage()
|
||||
{
|
||||
int idx = listBoxSubtitles.SelectedIndex;
|
||||
if (idx < 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
int pid = _tsParser.SubtitlePacketIds[listBoxTracks.SelectedIndex];
|
||||
return _programMapTableParser.GetSubtitleLanguage(pid);
|
||||
}
|
||||
|
||||
private void BluraySupToolStripMenuItem_Click(object sender, EventArgs e)
|
||||
{
|
||||
ExportTo(ExportPngXml.ExportFormats.BluraySup);
|
||||
@ -151,10 +174,10 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
using (var formSubOcr = new VobSubOcr())
|
||||
{
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, _fileName);
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, _fileName, GetSelectedLanguage());
|
||||
using (var exportBdnXmlPng = new ExportPngXml())
|
||||
{
|
||||
exportBdnXmlPng.InitializeFromVobSubOcr(formSubOcr.SubtitleFromOcr, new SubRip(), exportType, _fileName, formSubOcr, null);
|
||||
exportBdnXmlPng.InitializeFromVobSubOcr(formSubOcr.SubtitleFromOcr, new SubRip(), exportType, _fileName, formSubOcr, GetSelectedLanguage());
|
||||
exportBdnXmlPng.ShowDialog(this);
|
||||
}
|
||||
}
|
||||
@ -171,7 +194,7 @@ namespace Nikse.SubtitleEdit.Forms
|
||||
|
||||
using (var formSubOcr = new VobSubOcr())
|
||||
{
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, _fileName);
|
||||
formSubOcr.Initialize(subtitles, Configuration.Settings.VobSubOcr, _fileName, GetSelectedLanguage());
|
||||
formSubOcr.SaveAllImagesWithHtmlIndexViewToolStripMenuItem_Click(sender, e);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using Nikse.SubtitleEdit.Core;
|
||||
using Nikse.SubtitleEdit.Core.SubtitleFormats;
|
||||
@ -12,6 +13,8 @@ namespace Nikse.SubtitleEdit.Logic.CommandLineConvert
|
||||
{
|
||||
public static bool ConvertFromTsToBluRaySup(string fileName, string outputFolder, bool overwrite, StreamWriter stdOutWriter, CommandLineConverter.BatchConvertProgress progressCallback)
|
||||
{
|
||||
var programMapTableParser = new ProgramMapTableParser();
|
||||
programMapTableParser.Parse(fileName); // get languages
|
||||
var tsParser = new TransportStreamParser();
|
||||
tsParser.Parse(fileName, (position, total) =>
|
||||
{
|
||||
@ -50,7 +53,12 @@ namespace Nikse.SubtitleEdit.Logic.CommandLineConvert
|
||||
form.Initialize(new Subtitle(), new SubRip(), BatchConvert.BluRaySubtitle, fileName, videoInfo, fileName);
|
||||
foreach (int pid in tsParser.SubtitlePacketIds)
|
||||
{
|
||||
var outputFileName = CommandLineConverter.FormatOutputFileNameForBatchConvert(Utilities.GetPathAndFileNameWithoutExtension(fileName) + "-" + pid + Path.GetExtension(fileName), ".sup", outputFolder, overwrite);
|
||||
var language = programMapTableParser.GetSubtitleLanguageTwoLetter(pid);
|
||||
if (string.IsNullOrEmpty(language))
|
||||
{
|
||||
language = pid.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
var outputFileName = CommandLineConverter.FormatOutputFileNameForBatchConvert(Utilities.GetPathAndFileNameWithoutExtension(fileName) + "." + language + Path.GetExtension(fileName), ".sup", outputFolder, overwrite);
|
||||
stdOutWriter?.WriteLine($"Saving PID {pid} to {outputFileName}...");
|
||||
var sub = tsParser.GetDvbSubtitles(pid);
|
||||
progressCallback?.Invoke($"Save PID {pid}");
|
||||
|
Loading…
Reference in New Issue
Block a user