/// <summary> /// Adds the specified packet and automatically places it on the right track. /// If the track requires sorting it does so by reordering packets based on their timestamp. /// </summary> /// <param name="item">The item.</param> public void Add(ClosedCaptionPacket item) { CurrentNtscField = item.NtscField != 0 ? item.NtscField : 1; CurrentChannel = item.Channel != 0 ? item.Channel : CurrentChannel; var targetCC = CC1; if (CurrentNtscField == 1) { if (CurrentChannel == 1) { targetCC = CC1; } else { targetCC = CC2; } } else { if (CurrentChannel == 1) { targetCC = CC3; } else { targetCC = CC4; } } var performSort = targetCC.Count != 0; if (targetCC.Count > 0 && targetCC.Last().Timestamp.Ticks <= item.Timestamp.Ticks) { performSort = false; } targetCC.Add(item); if (performSort) { targetCC.Sort(); } }
/// <summary> /// Initializes a new instance of the <see cref="ClosedCaptionPacket"/> class. /// </summary> /// <param name="timestamp">The timestamp.</param> /// <param name="header">The header.</param> /// <param name="d0">The d0.</param> /// <param name="d1">The d1.</param> public ClosedCaptionPacket(TimeSpan timestamp, byte header, byte d0, byte d1) { D0 = DropParityBit(d0); D1 = DropParityBit(d1); NtscField = ClosedCaptionPacket.GetHeaderFieldType(header); Channel = 0; Timestamp = timestamp; #region Header Checking if (HeaderHasMarkers(header) == false || IsHeaderValidFalgSet(header) == false || (NtscField == 0) || (D0 == 0x00 && D1 == 0x00)) { PacketType = CCPacketType.NullPad; return; } PacketType = CCPacketType.Unrecognized; #endregion #region Xds Packet Detection // XDS Parsing if ((D0 & 0x0F) == D0 && D0 != 0) { PacketType = CCPacketType.XdsClass; XdsClass = (CCXdsClassType)D0; return; } #endregion #region Color Command Detection (Table 3) if ((D0 == 0x10 || D0 == 0x18) && (D1 >= 0x20 && D1 <= 0x2F)) { Channel = (D0 == 0x10) ? 1 : 2; PacketType = CCPacketType.Color; Color = (CCColorType)D1; return; } if ((D0 == 0x17 || D0 == 0x1F) && (D1 >= 0x2D && D1 <= 0x2F)) { Channel = (D0 == 0x17) ? 1 : 2; PacketType = CCPacketType.Color; var colorValue = D1 << 16; Color = (CCColorType)colorValue; return; } #endregion #region Charset Select Packet Detection (Table 4) if ((D0 == 0x17 || D0 == 0x1F) && (D1 >= 0x24 && D1 <= 0x2A)) { Channel = (D0 == 0x17) ? 1 : 2; PacketType = CCPacketType.Charset; return; } #endregion #region MidRow Code Detection (Table 69) // Midrow Code Parsing if ((D0 == 0x11 || D0 == 0x19) && (D1 >= 0x20 && D1 <= 0x2F)) { PacketType = CCPacketType.MidRow; Channel = D0 == 0x11 ? 1 : 2; MidRowStyle = (CCStyleType)D1; return; } #endregion #region Misc Command Detection (Table 70) // Screen command parsing if ((D0 == 0x14 || D0 == 0x1C) && (D1 >= 0x20 && D1 <= 0x2F)) { PacketType = CCPacketType.MiscCommand; MiscCommand = (CCMiscCommandType)D1; Channel = (D0 == 0x14 || D0 == 0x1C) ? 1 : 2; return; } // Tab command Parsing if ((D0 == 0x17 || D0 == 0x1F) && (D1 >= 0x21 && D1 <= 0x23)) { PacketType = CCPacketType.Tabs; Tabs = D1 & 0x03; Channel = D0 == 0x17 ? 1 : 2; return; } #endregion #region Preamble Command Detection (Table 71) // Preamble Parsing if ((D1 >= 0x40 && D1 <= 0x5F) || (D1 >= 0x60 && D1 <= 0x7F)) { // Row 11 is different -- check for it if (D0 == 0x10 || D0 == 0x18) { PacketType = CCPacketType.Preamble; Channel = D0 == 0x10 ? 1 : 2; PreambleRow = 11; PreambleStyle = (CCStyleType)(D1 - 0x20); return; } var wasSet = false; if (D0 >= 0x11 && D0 <= 0x17) { PacketType = CCPacketType.Preamble; Channel = 1; wasSet = true; } if (D0 >= 0x19 && D0 <= 0x1F) { PacketType = CCPacketType.Preamble; Channel = 2; wasSet = true; } if (wasSet) { if (D1 >= 0x40 && D1 <= 0x5F) { PreambleRow = OddPreambleRows[D0]; PreambleStyle = (CCStyleType)(D1 - 0x20); } else { PreambleRow = EvenPreambleRows[D0]; PreambleStyle = (CCStyleType)(D1 - 0x40); } return; } } #endregion #region Text Parsing (Table 5, 6, 7, 8, 9, 10, and 68 for ASCII Chars) PacketType = CCPacketType.Text; // Special North American character set if ((D0 == 0x11 || D0 == 0x19) && D1 >= 0x30 && D1 <= 0x3F) { if (SpecialNorthAmerican.ContainsKey(D1)) { Channel = (D0 == 0x11) ? 1 : 2; Text = SpecialNorthAmerican[D1]; return; } } if (D0 == 0x12 || D0 == 0x1A) { if (Spanish.ContainsKey(D1)) { Channel = 1; Text = Spanish[D1]; return; } if (French.ContainsKey(D1)) { Channel = 2; Text = French[D1]; return; } } if (D0 == 0x13 || D0 == 0x1B) { if (Portuguese.ContainsKey(D1)) { Channel = 1; Text = Portuguese[D1]; return; } if (German.ContainsKey(D1)) { Channel = 2; Text = German[D1]; return; } } // Basic North American character set (2 chars) if (D0 >= 0x20 && D0 <= 0x7F && (D1 == 0x00 || (D1 >= 0x20 && D1 <= 0x7F))) { Channel = 0; Text = D1 == 0x00 ? $"{ToEia608Char(D0)}" : $"{ToEia608Char(D0)}{ToEia608Char(D1)}"; return; } #endregion PacketType = CCPacketType.Unrecognized; Channel = 0; }