Added a failed attempt at OpenTV Parsing.

This commit is contained in:
feyris-tan 2025-07-17 17:08:19 +02:00
parent 6302a25f26
commit 7d218ade9c
26 changed files with 2934 additions and 19 deletions

View File

@ -0,0 +1,275 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Globalization;
using System.IO;
using System.Text;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes a dictionary entry for a single tree Huffman scenario.
/// </summary>
public class SingleTreeDictionaryEntry
{
/// <summary>
/// Get or set the flag for not starting at the first bit in the compressed string.
/// </summary>
public static bool OffsetStart
{
get { return (offsetStart); }
set { offsetStart = value; }
}
/// <summary>
/// Get the decode string.
/// </summary>
public string Decode { get { return (decode); } }
private string decode;
private string pattern;
private static HuffmanEntry[] roots = new HuffmanEntry[2];
private static bool offsetStart = true;
/// <summary>
/// Initialize a new instance of the SingleTreeDictionaryEntry class.
/// </summary>
/// <param name="pattern">The Huffman bit pattern.</param>
/// <param name="decode">The decode for the bit pattern.</param>
public SingleTreeDictionaryEntry(string pattern, string decode)
{
this.pattern = pattern;
this.decode = decode;
}
/// <summary>
/// Load the dictionary entries ino the first root.
/// </summary>
/// <returns>True if the file has been loaded; false otherwise.</returns>
public static bool Load(string fileName)
{
return (Load(fileName, 1));
}
/// <summary>
/// Load the dictionary entries.
/// </summary>
/// <returns>True if the file has been loaded; false otherwise.</returns>
public static bool Load(string fileName, int rootNumber)
{
FileStream fileStream = null;
Logger.Instance.Write("Loading Huffman Dictionary from " + fileName);
try { fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read); }
catch (IOException e)
{
Logger.Instance.Write("Huffman Dictionary file " + fileName + " not available");
Logger.Instance.Write(e.Message);
return (false);
}
StreamReader streamReader = new StreamReader(fileStream);
roots[rootNumber - 1] = null;
while (!streamReader.EndOfStream)
{
string line = streamReader.ReadLine();
if (line != string.Empty && !line.StartsWith("####"))
{
string[] parts = line.Split(new char[] { '=' });
if (parts.Length == 2)
addEntry(rootNumber, parts[1], getDecode(parts[0]));
else
{
if (parts.Length == 3 && parts[0] == string.Empty && parts[1] == string.Empty)
addEntry(rootNumber, parts[2], "=");
else
Logger.Instance.Write("Dictionary line '" + line + "' format wrong - line ignored ");
}
}
}
streamReader.Close();
fileStream.Close();
Logger.Instance.Write("Dictionary loaded");
return (true);
}
private static void addEntry(int rootNumber, string pattern, string decode)
{
if (roots[rootNumber - 1] == null)
roots[rootNumber - 1] = new HuffmanEntry();
HuffmanEntry currentEntry = roots[rootNumber - 1];
for (int index = 0; index < pattern.Length; index++)
{
char patternChar = pattern[index];
switch (patternChar)
{
case '0':
if (currentEntry.P0 == null)
{
currentEntry.P0 = new HuffmanEntry();
currentEntry = currentEntry.P0;
if (index == pattern.Length - 1)
currentEntry.Value = decode;
}
else
{
currentEntry = currentEntry.P0;
if (currentEntry.Value != null && index == pattern.Length - 1)
Logger.Instance.Write("Dictionary entry already set");
}
break;
case '1':
if (currentEntry.P1 == null)
{
currentEntry.P1 = new HuffmanEntry();
currentEntry = currentEntry.P1;
if (index == pattern.Length - 1)
currentEntry.Value = decode;
}
else
{
currentEntry = currentEntry.P1;
if (currentEntry.Value != null && index == pattern.Length - 1)
Logger.Instance.Write("Dictionary entry already set");
}
break;
default:
break;
}
}
}
private static string getDecode(string originalParameter)
{
if (originalParameter.Length != 4)
return (originalParameter);
if (originalParameter[0] != '<' || originalParameter[3] != '>')
return (originalParameter);
return (((char)(Int32.Parse(originalParameter.Substring(1, 2), NumberStyles.HexNumber))).ToString());
}
/// <summary>
/// Decompress a compressed Huffman string using the first root table.
/// </summary>
/// <param name="byteData">The compressed byte data.</param>
/// <returns>The decompressed string.</returns>
public static string DecodeData(byte[] byteData)
{
return (DecodeData(1, byteData));
}
/// <summary>
/// Decompress a compressed Huffman string.
/// </summary>
/// <param name="rootNumber">The root table to use.</param>
/// <param name="byteData">The compressed byte data.</param>
/// <returns>The decompressed string.</returns>
public static string DecodeData(int rootNumber, byte[] byteData)
{
StringBuilder outputString = new StringBuilder();
HuffmanEntry currentEntry = roots[rootNumber - 1];
byte mask;
if (offsetStart)
mask = 0x20;
else
mask = 0x80;
StringBuilder bitString = new StringBuilder();
for (int index = 0; index < byteData.Length; index++)
{
byte dataByte = byteData[index];
while (mask > 0)
{
if (currentEntry.Value != null)
{
if (currentEntry.Value != "??")
outputString.Append(currentEntry.Value);
currentEntry = roots[rootNumber - 1];
bitString = new StringBuilder();
}
if ((dataByte & mask) == 0)
{
bitString.Append("0");
if (currentEntry.P0 != null)
currentEntry = currentEntry.P0;
else
{
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
Logger.Instance.Write("Decoded data: " + outputString.ToString());
Logger.Instance.Write("Bit string: " + bitString.ToString());
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
}
}
else
{
bitString.Append("1");
if (currentEntry.P1 != null)
currentEntry = currentEntry.P1;
else
{
Logger.Instance.Write(" ** DECOMPRESSION FAILED **");
Logger.Instance.Write("Original data: " + Utils.ConvertToHex(byteData));
Logger.Instance.Write("Decoded data: " + outputString.ToString());
Logger.Instance.Write("Bit string: " + bitString.ToString());
return (outputString.ToString() + " ** DECOMPRESSION FAILED **");
}
}
mask = (byte)(mask >> 1);
}
mask = 0x80;
}
/*if (currentEntry.Value != null && currentEntry.Value != "??")
outputString.Append(currentEntry.Value);*/
if (currentEntry.Value != null)
outputString.Append(currentEntry.Value);
return(outputString.ToString());
}
}
}

View File

@ -0,0 +1,149 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
namespace DVBServices
{
/// <summary>
/// The class that describes an MPEG2 extended header.
/// </summary>
public class Mpeg2ExtendedHeader : Mpeg2BasicHeader
{
/// <summary>
/// Get the table identification extension.
/// </summary>
public int TableIDExtension { get { return (tableIDExtension); } }
/// <summary>
/// Return true if the MPEG2 section is current; false otherwise.
/// </summary>
public bool CurrentNextIndicator { get { return (currentNextIndicator); } }
/// <summary>
/// Get the version number.
/// </summary>
public int VersionNumber { get { return (versionNumber); } }
/// <summary>
/// Get the section number.
/// </summary>
public int SectionNumber { get { return (sectionNumber); } }
/// <summary>
/// Get the last section number.
/// </summary>
public int LastSectionNumber { get { return (lastSectionNumber); } }
/// <summary>
/// Return true if the MPEG2 section is current; false otherwise.
/// </summary>
public bool Current { get { return (currentNextIndicator); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the header.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The header has not been processed.
/// </exception>
public override int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("Mpeg2ExtendedHeader: Index requested before block processed"));
return (lastIndex);
}
}
private int tableIDExtension;
private bool currentNextIndicator;
private int versionNumber;
private int sectionNumber;
private int lastSectionNumber;
private int lastIndex = -1;
// MPEG extended header layout is as follows
//
// table ID extension word uimsbf
//
// reserved 2 bits bslbf
// version no 5 bits uimsbf
// current/next ind 1 bit bslbf
//
// section no byte uimsbf
// last section no byte uimsbf
/// <summary>
/// Initialize a new instance of the Mpeg2ExtendedHeader class.
/// </summary>
public Mpeg2ExtendedHeader() { }
/// <summary>
/// Parse the header.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the header.</param>
public override void Process(byte[] byteData)
{
base.Process(byteData);
lastIndex = base.Index;
try
{
tableIDExtension = (byteData[lastIndex] * 256) + (int)byteData[lastIndex + 1];
lastIndex += 2;
versionNumber = ((int)((byteData[lastIndex] >> 1) & 0x1f));
currentNextIndicator = (byteData[lastIndex] & 0x01) != 0;
lastIndex++;
sectionNumber = (int)byteData[lastIndex];
lastIndex++;
lastSectionNumber = (int)byteData[lastIndex];
lastIndex++;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("MPEG2 extended header short"));
}
}
/// <summary>
/// Validate the header fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A header field is not valid.
/// </exception>
public override void Validate()
{
base.Validate();
}
/// <summary>
/// Log the header fields.
/// </summary>
public override void LogMessage()
{
base.LogMessage();
}
}
}

View File

@ -0,0 +1,111 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an OpenTV extended description record.
/// </summary>
internal class OpenTVExtendedDescriptionRecord : OpenTVRecordBase
{
/// <summary>
/// Get the tag value for this record.
/// </summary>
public const int TagValue = 0xbb;
/// <summary>
/// Get the extended description.
/// </summary>
public string Description { get { return (SingleTreeDictionaryEntry.DecodeData(description)); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the record.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The record has not been processed.
/// </exception>
public override int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVExtendedDescriptionRecord: Index requested before block processed"));
return (lastIndex);
}
}
private byte[] description;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVExtendedDescriptionRecord class.
/// </summary>
internal OpenTVExtendedDescriptionRecord() { }
/// <summary>
/// Parse the record.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
internal override void Process(byte[] byteData, int index)
{
lastIndex = index;
try
{
description = Utils.GetBytes(byteData, lastIndex, Length);
lastIndex += Length;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
/// <summary>
/// Validate the record data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A record data field is not valid.
/// </exception>
internal override void Validate() { }
/// <summary>
/// Log the record data fields.
/// </summary>
internal override void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV EXTENDED DESCRIPTION RECORD: Description: " + Utils.ConvertToHex(description));
}
}
}

View File

@ -0,0 +1,195 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The base OpenTV record class.
/// </summary>
internal class OpenTVRecordBase
{
/// <summary>
/// Get the tag of the record.
/// </summary>
internal int Tag { get { return (tag); } }
/// <summary>
/// Get the length of the record data.
/// </summary>
internal int Length { get { return (length); } }
/// <summary>
/// Get the record data.
/// </summary>
internal byte[] Data { get { return (data); } }
/// <summary>
/// Get the total length of the record.
/// </summary>
internal int TotalLength { get { return (Length + 2); } }
/// <summary>
/// Return true if the record is undefined; false otherwise.
/// </summary>
internal bool IsUndefined { get { return (isUndefined); } }
/// <summary>
/// Return the collection of unknown records.
/// </summary>
internal static Collection<OpenTVRecordBase> UnknownRecords { get { return (unknownRecords); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following this record.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The descriptor has not been processed.
/// </exception>
public virtual int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVRecordBase: Index requested before block processed"));
return (lastIndex);
}
}
private int lastIndex = -1;
private int tag;
private int length;
private byte[] data;
private bool isUndefined;
private static Collection<OpenTVRecordBase> unknownRecords;
/// <summary>
/// Create an instance of the record class.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">The index of the tag byte of the record.</param>
/// <returns>A descriptor instance.</returns>
internal static OpenTVRecordBase Instance(byte[] byteData, int index)
{
OpenTVRecordBase record;
switch ((int)byteData[index])
{
case OpenTVTitleDataRecord.TagValue:
record = new OpenTVTitleDataRecord();
break;
case OpenTVShortDescriptionRecord.TagValue:
record = new OpenTVShortDescriptionRecord();
break;
case OpenTVExtendedDescriptionRecord.TagValue:
record = new OpenTVExtendedDescriptionRecord();
break;
case OpenTVSeriesLinkRecord.TagValue:
record = new OpenTVSeriesLinkRecord();
break;
default:
record = new OpenTVRecordBase();
if (DebugEntry.IsDefined(DebugName.LogUnknownRecords))
{
if (unknownRecords == null)
unknownRecords = new Collection<OpenTVRecordBase>();
unknownRecords.Add(record);
}
break;
}
record.tag = (int)byteData[index];
index++;
record.length = (int)byteData[index];
index++;
record.Process(byteData, index);
return (record);
}
/// <summary>
/// Initialize a new instance of the OpenTVRecordBase class.
/// </summary>
internal OpenTVRecordBase() { }
/// <summary>
/// Parse the descriptor.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">Index of the byte in the MPEG2 section following the descriptor length.</param>
internal virtual void Process(byte[] byteData, int index)
{
lastIndex = index;
if (Length != 0)
{
data = Utils.GetBytes(byteData, 0, Length);
lastIndex += Length;
}
isUndefined = true;
}
/// <summary>
/// Validate the record fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A record field is not valid.
/// </exception>
internal virtual void Validate() { }
/// <summary>
/// Log the descriptor fields.
/// </summary>
internal virtual void LogMessage()
{
if (DebugEntry.IsDefined(DebugName.LogUnknownRecords))
logMessage(Logger.Instance);
else
{
if (Logger.ProtocolLogger == null)
return;
if (!TraceEntry.IsDefined(TraceName.GenericOpenTvRecord))
return;
logMessage(Logger.ProtocolLogger);
}
}
private void logMessage(Logger logger)
{
logger.Write(Logger.ProtocolIndent + "OPENTV GENERIC RECORD: Tag: " + Utils.ConvertToHex(tag) +
" Length: " + length);
if (length != 0)
logger.Dump("OpenTV Generic Record Data", data, data.Length);
}
}
}

View File

@ -0,0 +1,111 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an OpenTV series link record.
/// </summary>
internal class OpenTVSeriesLinkRecord : OpenTVRecordBase
{
/// <summary>
/// Get the tag value for this record.
/// </summary>
public const int TagValue = 0xc1;
/// <summary>
/// Get the series link.
/// </summary>
public int SeriesLink { get { return (seriesLink); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the record.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The record has not been processed.
/// </exception>
public override int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVSeriesLinkRecord: Index requested before block processed"));
return (lastIndex);
}
}
private int seriesLink;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVSeriesLinkRecord class.
/// </summary>
internal OpenTVSeriesLinkRecord() { }
/// <summary>
/// Parse the record.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
internal override void Process(byte[] byteData, int index)
{
lastIndex = index;
try
{
seriesLink = Utils.Convert2BytesToInt(byteData, lastIndex);
lastIndex += 2;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
/// <summary>
/// Validate the record data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A record data field is not valid.
/// </exception>
internal override void Validate() { }
/// <summary>
/// Log the record data fields.
/// </summary>
internal override void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SERIES LINK RECORD: Series link: " + seriesLink);
}
}
}

View File

@ -0,0 +1,116 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an OpenTV short description record.
/// </summary>
internal class OpenTVShortDescriptionRecord : OpenTVRecordBase
{
/// <summary>
/// Get the tag value for this record.
/// </summary>
public const int TagValue = 0xb9;
/// <summary>
/// Get the short description.
/// </summary>
public string Description { get { return (SingleTreeDictionaryEntry.DecodeData(description)); } }
/// <summary>
/// Get the short description bytes.
/// </summary>
public byte[] DescriptionBytes { get { return (description); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the record.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The record has not been processed.
/// </exception>
public override int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVShortDescriptionRecord: Index requested before block processed"));
return (lastIndex);
}
}
private byte[] description;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVShortDescriptionRecord class.
/// </summary>
internal OpenTVShortDescriptionRecord() { }
/// <summary>
/// Parse the record.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
internal override void Process(byte[] byteData, int index)
{
lastIndex = index;
try
{
description = Utils.GetBytes(byteData, lastIndex, Length);
lastIndex += Length;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
/// <summary>
/// Validate the record data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A record data field is not valid.
/// </exception>
internal override void Validate() { }
/// <summary>
/// Log the record data fields.
/// </summary>
internal override void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SHORT DESCRIPTION RECORD: Description: " + Utils.ConvertToHex(description));
}
}
}

View File

@ -0,0 +1,244 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes Open TV summary data.
/// </summary>
public class OpenTVSummaryData
{
/// <summary>
/// Get the event identification.
/// </summary>
public int EventID { get { return (eventID); } }
/// <summary>
/// Get the short description of the event.
/// </summary>
public string ShortDescription
{
get
{
OpenTVShortDescriptionRecord record = (OpenTVShortDescriptionRecord)getRecord(OpenTVShortDescriptionRecord.TagValue);
if (record != null)
return (record.Description);
else
return null;
}
}
/// <summary>
/// Get the raw bytes of short description of the event.
/// </summary>
public byte[] ShortDescriptionBytes
{
get
{
OpenTVShortDescriptionRecord record = (OpenTVShortDescriptionRecord)getRecord(OpenTVShortDescriptionRecord.TagValue);
if (record != null)
return (record.DescriptionBytes);
else
return (new byte[] { 0x00 });
}
}
/// <summary>
/// Get the extended description of the event.
/// </summary>
public string ExtendedDescription
{
get
{
OpenTVExtendedDescriptionRecord record = (OpenTVExtendedDescriptionRecord)getRecord(OpenTVExtendedDescriptionRecord.TagValue);
if (record != null)
return (record.Description);
else
return (null);
}
}
/// <summary>
/// Get the series link of the event.
/// </summary>
public int SeriesLink
{
get
{
OpenTVSeriesLinkRecord record = (OpenTVSeriesLinkRecord)getRecord(OpenTVSeriesLinkRecord.TagValue);
if (record != null)
return (record.SeriesLink);
else
return (-1);
}
}
/// <summary>
/// Get the collection of records for this summary section.
/// </summary>
internal Collection<OpenTVRecordBase> Records
{
get
{
if (records == null)
records = new Collection<OpenTVRecordBase>();
return (records);
}
}
/// <summary>
/// Get the collection of undefined records for this summary section.
/// </summary>
internal Collection<OpenTVRecordBase> UndefinedRecords
{
get
{
if (records == null)
return (null);
Collection<OpenTVRecordBase> undefinedRecords = new Collection<OpenTVRecordBase>();
foreach (OpenTVRecordBase record in records)
{
if (record.IsUndefined)
undefinedRecords.Add(record);
}
return (undefinedRecords);
}
}
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the summary data.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The summary data has not been processed.
/// </exception>
public int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVSummaryData: Index requested before block processed"));
return (lastIndex);
}
}
private int eventID;
private int length;
private Collection<OpenTVRecordBase> records;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVSummaryData class.
/// </summary>
public OpenTVSummaryData() { }
/// <summary>
/// Parse the summary data.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the summary data.</param>
/// <param name="index">Index of the first byte of the summary data in the MPEG2 section.</param>
/// <param name="baseDate">The base date for the program events.</param>
internal void Process(byte[] byteData, int index, DateTime baseDate)
{
lastIndex = index;
try
{
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
lastIndex += 2;
length = ((byteData[lastIndex] & 0x0f) * 256) + byteData[lastIndex + 1];
lastIndex += 2;
int recordLength = length;
while (recordLength != 0)
{
OpenTVRecordBase record = OpenTVRecordBase.Instance(byteData, lastIndex);
Records.Add(record);
lastIndex += record.TotalLength;
recordLength -= record.TotalLength;
}
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("The Open TV Summary Data message is short"));
}
}
/// <summary>
/// Validate the summary data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A summary data field is not valid.
/// </exception>
public void Validate() { }
/// <summary>
/// Log the summary data fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SUMMARY DATA: Event ID: " + eventID +
" Length: " + length);
if (records != null)
{
Logger.IncrementProtocolIndent();
foreach (OpenTVRecordBase record in records)
record.LogMessage();
Logger.DecrementProtocolIndent();
}
}
private OpenTVRecordBase getRecord(int tag)
{
if (records == null)
return (null);
foreach (OpenTVRecordBase record in records)
{
if (record.Tag == tag)
return (record);
}
return (null);
}
}
}

View File

@ -0,0 +1,161 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an Open TV summary header.
/// </summary>
public class OpenTVSummaryHeader
{
/// <summary>
/// Get the channel identification.
/// </summary>
public int ChannelID { get { return (channelID); } }
/// <summary>
/// Get the title date base.
/// </summary>
public DateTime BaseDate { get { return (baseDate); } }
/// <summary>
/// Get the data collection related to this summary.
/// </summary>
public Collection<OpenTVSummaryData> SummaryData { get { return (summaryData); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the summary header.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The summary header has not been processed.
/// </exception>
public int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVSummaryHeader: Index requested before block processed"));
return (lastIndex);
}
}
private int channelID;
private DateTime baseDate;
private Collection<OpenTVSummaryData> summaryData;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVSummaryHeader class.
/// </summary>
public OpenTVSummaryHeader() { }
/// <summary>
/// Parse the summary header.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the summary header.</param>
/// <param name="index">Index of the first byte of the summary header in the MPEG2 section.</param>
/// <param name="mpeg2Header">The MPEG2 header of the section.</param>
internal void Process(byte[] byteData, int index, Mpeg2ExtendedHeader mpeg2Header)
{
lastIndex = index;
channelID = mpeg2Header.TableIDExtension;
try
{
baseDate = getDate(Utils.Convert2BytesToInt(byteData, lastIndex));
lastIndex += 2;
while (lastIndex < byteData.Length - 4)
{
OpenTVSummaryData data = new OpenTVSummaryData();
data.Process(byteData, lastIndex, baseDate);
if (summaryData == null)
summaryData = new Collection<OpenTVSummaryData>();
summaryData.Add(data);
lastIndex = data.Index;
}
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("The Open TV Summary Header message is short"));
}
}
private DateTime getDate(int mjd)
{
int j = mjd + 2400001 + 68569;
int c = 4 * j / 146097;
j = j - (146097 * c + 3) / 4;
int y = 4000 * (j + 1) / 1461001;
j = j - 1461 * y / 4 + 31;
int m = 80 * j / 2447;
int day = j - 2447 * m / 80;
j = m / 11;
int month = m + 2 - (12 * j);
int year = 100 * (c - 49) + y + j;
return (new DateTime(year, month, day) + new TimeSpan(1, 0, 0, 0));
}
/// <summary>
/// Validate the summary header fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A summary header field is not valid.
/// </exception>
public void Validate() { }
/// <summary>
/// Log the summary header fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV SUMMARY HEADER: Channel ID: " + channelID +
" Base date : " + baseDate);
if (summaryData != null)
{
Logger.IncrementProtocolIndent();
foreach (OpenTVSummaryData data in summaryData)
data.LogMessage();
Logger.DecrementProtocolIndent();
}
}
}
}

View File

@ -0,0 +1,151 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an Open TV Summary section.
/// </summary>
public class OpenTVSummarySection
{
/// <summary>
/// Get the collection of Open TV Title sections.
/// </summary>
public static Collection<OpenTVSummarySection> OpenTVSummarySections
{
get
{
if (openTVSummarySections == null)
openTVSummarySections = new Collection<OpenTVSummarySection>();
return (openTVSummarySections);
}
}
/// <summary>
/// Get the section number.
/// </summary>
public int SectionNumber { get { return (sectionNumber); } }
/// <summary>
/// Get the section number.
/// </summary>
public int LastSectionNumber { get { return (lastSectionNumber); } }
/// <summary>
/// Get the title header.
/// </summary>
public OpenTVSummaryHeader SummaryHeader { get { return (summaryHeader); } }
private int sectionNumber;
private int lastSectionNumber;
private OpenTVSummaryHeader summaryHeader;
private static Collection<OpenTVSummarySection> openTVSummarySections;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVSummarySection class.
/// </summary>
internal OpenTVSummarySection() { }
/// <summary>
/// Parse the section.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the section.</param>
/// <param name="mpeg2Header">The MPEG2 header that preceedes the section.</param>
internal void Process(byte[] byteData, Mpeg2ExtendedHeader mpeg2Header)
{
lastIndex = mpeg2Header.Index;
sectionNumber = mpeg2Header.SectionNumber;
lastSectionNumber = mpeg2Header.LastSectionNumber;
summaryHeader = new OpenTVSummaryHeader();
summaryHeader.Process(byteData, lastIndex, mpeg2Header);
}
/// <summary>
/// Log the section fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
summaryHeader.LogMessage();
}
/// <summary>
/// Process an MPEG2 section from the Open TV Summary table.
/// </summary>
/// <param name="byteData">The MPEG2 section.</param>
/// <returns>An Open TV Summary Section instance.</returns>
public static OpenTVSummarySection ProcessOpenTVSummaryTable(byte[] byteData)
{
Mpeg2ExtendedHeader mpeg2Header = new Mpeg2ExtendedHeader();
try
{
mpeg2Header.Process(byteData);
if (mpeg2Header.Current)
{
OpenTVSummarySection openTVSummarySection = new OpenTVSummarySection();
openTVSummarySection.Process(byteData, mpeg2Header);
openTVSummarySection.LogMessage();
return (openTVSummarySection);
}
else
return (null);
}
catch (ArgumentOutOfRangeException e)
{
Logger.Instance.Write("<e> Error processing Summary Section: " + e.Message);
return (null);
}
}
/// <summary>
/// Add a section to the collection.
/// </summary>
/// <param name="newSection">The section to be added.</param>
public static void AddSection(OpenTVSummarySection newSection)
{
/*foreach (OpenTVSummarySection oldSection in OpenTVSummarySections)
{
if (oldSection.sectionNumber == newSection.sectionNumber)
return;
if (oldSection.SectionNumber > newSection.SectionNumber)
{
OpenTVSummarySections.Insert(OpenTVSummarySections.IndexOf(oldSection), newSection);
return;
}
}*/
OpenTVSummarySections.Add(newSection);
}
}
}

View File

@ -0,0 +1,289 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes Open TV title data.
/// </summary>
public class OpenTVTitleData
{
/// <summary>
/// Get the event identification.
/// </summary>
public int EventID { get { return (eventID); } }
/// <summary>
/// Get the start time of the event.
/// </summary>
public DateTime StartTime
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (baseDate + record.StartTimeOffset);
}
}
/// <summary>
/// Get the duration of the event.
/// </summary>
public TimeSpan Duration
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (record.Duration);
}
}
/// <summary>
/// Get the theme identification of the event.
/// </summary>
public int CategoryID
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (record.CategoryID);
}
}
/// <summary>
/// Get the name of the event.
/// </summary>
public string EventName
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (record.DecodedEventName);
}
}
/// <summary>
/// Get the raw bytes of the event name.
/// </summary>
public byte[] EventNameBytes
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (record.EventName);
}
}
/// <summary>
/// Get the flags field of the event.
/// </summary>
public byte[] Flags
{
get
{
OpenTVTitleDataRecord record = (OpenTVTitleDataRecord)getRecord(OpenTVTitleDataRecord.TagValue);
return (record.Flags);
}
}
/// <summary>
/// Get the collection of records for this title section.
/// </summary>
internal Collection<OpenTVRecordBase> Records
{
get
{
if (records == null)
records = new Collection<OpenTVRecordBase>();
return (records);
}
}
/// <summary>
/// Get the collection of undefined records for this title section.
/// </summary>
internal Collection<OpenTVRecordBase> UndefinedRecords
{
get
{
if (records == null)
return (null);
Collection<OpenTVRecordBase> undefinedRecords = new Collection<OpenTVRecordBase>();
foreach (OpenTVRecordBase record in records)
{
if (record.IsUndefined)
undefinedRecords.Add(record);
}
return (undefinedRecords);
}
}
/// <summary>
/// Return true if the entry is empty; false otherwise.
/// </summary>
public bool IsEmpty { get { return (records == null || records.Count == 0); } }
/// <summary>
/// Get the PID of the section containing the data.
/// </summary>
public int PID { get { return (pid); } }
/// <summary>
/// Get the table ID of the section containing the data.
/// </summary>
public int Table { get { return (table); } }
/// <summary>
/// Get the timestamp when the data arrived.
/// </summary>
public DateTime TimeStamp { get { return (timeStamp); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the title data.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The title data has not been processed.
/// </exception>
public int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVTitleData: Index requested before block processed"));
return (lastIndex);
}
}
private int eventID;
private int length;
private DateTime baseDate;
private int pid;
private int table;
private DateTime timeStamp;
private Collection<OpenTVRecordBase> records;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVTitleData class.
/// </summary>
public OpenTVTitleData() { }
/// <summary>
/// Parse the title data.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the title data.</param>
/// <param name="index">Index of the first byte of the title data in the MPEG2 section.</param>
/// <param name="baseDate">The base date for the programs.</param>
/// <param name="channel">The channel for the data.</param>
/// <param name="pid">The PID of the section.</param>
/// <param name="table">The table ID of the section.</param>
internal void Process(byte[] byteData, int index, DateTime baseDate, int channel, int pid, int table)
{
lastIndex = index;
this.pid = pid;
this.table = table;
this.baseDate = baseDate;
try
{
eventID = Utils.Convert2BytesToInt(byteData, lastIndex);
lastIndex += 2;
length = ((byteData[lastIndex] & 0x0f) * 256) + byteData[lastIndex + 1];
lastIndex += 2;
int recordLength = length;
while (recordLength != 0)
{
OpenTVRecordBase record = OpenTVRecordBase.Instance(byteData, lastIndex);
Records.Add(record);
lastIndex += record.TotalLength;
recordLength -= record.TotalLength;
}
timeStamp = DateTime.Now;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
/// <summary>
/// Validate the title data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A title data field is not valid.
/// </exception>
public void Validate() { }
/// <summary>
/// Log the title data fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE DATA: Event ID: " + eventID +
" Length: " + length);
if (records != null)
{
Logger.IncrementProtocolIndent();
foreach (OpenTVRecordBase record in records)
record.LogMessage();
Logger.DecrementProtocolIndent();
}
}
private OpenTVRecordBase getRecord(int tag)
{
if (records == null)
return(null);
foreach (OpenTVRecordBase record in records)
{
if (record.Tag == tag)
return(record);
}
return(null);
}
}
}

View File

@ -0,0 +1,164 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an OpenTV title data record.
/// </summary>
internal class OpenTVTitleDataRecord : OpenTVRecordBase
{
/// <summary>
/// Get the tag value for this record.
/// </summary>
public const int TagValue = 0xb5;
/// <summary>
/// Get the start time of the event.
/// </summary>
public TimeSpan StartTimeOffset { get { return (startTimeOffset); } }
/// <summary>
/// Get the duration of the event.
/// </summary>
public TimeSpan Duration { get { return (duration); } }
/// <summary>
/// Get the theme identification of the event.
/// </summary>
public int CategoryID { get { return (categoryID); } }
/// <summary>
/// Get the flags field of the event.
/// </summary>
public byte[] Flags { get { return (flags); } }
/// <summary>
/// Get the name of the event.
/// </summary>
public byte[] EventName { get { return (eventName); } }
/// <summary>
/// Get the decompressed event name.
/// </summary>
public string DecodedEventName { get { return (SingleTreeDictionaryEntry.DecodeData(eventName)); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the record.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The record has not been processed.
/// </exception>
public override int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVTitleDataRecord: Index requested before block processed"));
return (lastIndex);
}
}
private TimeSpan startTimeOffset;
private TimeSpan duration;
private int categoryID;
private byte[] flags;
private byte[] eventName;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVTitleDataRecord class.
/// </summary>
internal OpenTVTitleDataRecord() { }
/// <summary>
/// Parse the record.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the record.</param>
/// <param name="index">Index of the first byte of the record data in the MPEG2 section.</param>
internal override void Process(byte[] byteData, int index)
{
lastIndex = index;
try
{
// Source value to 2 second resolution
startTimeOffset = getTime((byteData[lastIndex] * 512) + (byteData[lastIndex + 1] * 2));
lastIndex += 2;
duration = getTime(Utils.Convert2BytesToInt(byteData, lastIndex) * 2);
lastIndex += 2;
categoryID = (int)byteData[lastIndex];
lastIndex++;
flags = Utils.GetBytes(byteData, lastIndex, 2);
lastIndex += 2;
eventName = Utils.GetBytes(byteData, lastIndex, Length - 7);
lastIndex += Length - 7;
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
private TimeSpan getTime(int totalSeconds)
{
int days = totalSeconds / 86400;
int hours = (totalSeconds - (days * 86400)) / 3600;
int minutes = (totalSeconds - ((days * 86400) + (hours * 3600))) / 60;
int seconds = totalSeconds % 60;
return (new TimeSpan(days, hours, minutes, seconds));
}
/// <summary>
/// Validate the record data fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A record data field is not valid.
/// </exception>
internal override void Validate() { }
/// <summary>
/// Log the record data fields.
/// </summary>
internal override void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "");
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE DATA RECORD: " +
"Start time: " + startTimeOffset +
" Duration: " + duration +
" Category: " + categoryID +
" Unknown: " + Utils.ConvertToHex(flags) +
" Name: " + Utils.ConvertToHex(eventName));
}
}
}

View File

@ -0,0 +1,165 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an Open TV title header.
/// </summary>
public class OpenTVTitleHeader
{
/// <summary>
/// Get the channel identification.
/// </summary>
public int ChannelID { get { return (channelID); } }
/// <summary>
/// Get the title date base.
/// </summary>
public DateTime BaseDate { get { return (baseDate); } }
/// <summary>
/// Get the data collection related to this title.
/// </summary>
public Collection<OpenTVTitleData> TitleData { get { return (titleData); } }
/// <summary>
/// Get the index of the next byte in the MPEG2 section following the title header.
/// </summary>
/// <exception cref="InvalidOperationException">
/// The title header has not been processed.
/// </exception>
public int Index
{
get
{
if (lastIndex == -1)
throw (new InvalidOperationException("OpenTVTitleHeader: Index requested before block processed"));
return (lastIndex);
}
}
private int channelID;
private DateTime baseDate;
private Collection<OpenTVTitleData> titleData;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVTitleHeader class.
/// </summary>
public OpenTVTitleHeader() { }
/// <summary>
/// Parse the title header.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the title header.</param>
/// <param name="index">Index of the first byte of the title header in the MPEG2 section.</param>
/// <param name="mpeg2Header">The MPEG2 header of the section.</param>
/// <param name="pid">The PID of the section.</param>
/// <param name="tid">The table ID of the section.</param>
internal void Process(byte[] byteData, int index, Mpeg2ExtendedHeader mpeg2Header, int pid, int tid)
{
lastIndex = index;
channelID = mpeg2Header.TableIDExtension;
try
{
baseDate = getDate(Utils.Convert2BytesToInt(byteData, lastIndex));
lastIndex += 2;
while (lastIndex < byteData.Length - 4)
{
OpenTVTitleData data = new OpenTVTitleData();
data.Process(byteData, lastIndex, baseDate, channelID, pid, tid);
if (!data.IsEmpty)
{
if (titleData == null)
titleData = new Collection<OpenTVTitleData>();
titleData.Add(data);
}
lastIndex = data.Index;
}
Validate();
}
catch (IndexOutOfRangeException)
{
throw (new ArgumentOutOfRangeException("lastIndex = " + lastIndex));
}
}
private DateTime getDate(int mjd)
{
int j = mjd + 2400001 + 68569;
int c = 4 * j / 146097;
j = j - (146097 * c + 3) / 4;
int y = 4000 * (j + 1) / 1461001;
j = j - 1461 * y / 4 + 31;
int m = 80 * j / 2447;
int day = j - 2447 * m / 80;
j = m / 11;
int month = m + 2 - (12 * j);
int year = 100 * (c - 49) + y + j;
return (new DateTime(year, month, day));
}
/// <summary>
/// Validate the title header fields.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">
/// A title header field is not valid.
/// </exception>
public void Validate() { }
/// <summary>
/// Log the title header fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
Logger.ProtocolLogger.Write(Logger.ProtocolIndent + "OPENTV TITLE HEADER: Channel ID: " + channelID +
" Base date : " + baseDate);
if (titleData != null)
{
Logger.IncrementProtocolIndent();
foreach (OpenTVTitleData data in titleData)
data.LogMessage();
Logger.DecrementProtocolIndent();
}
}
}
}

View File

@ -0,0 +1,126 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using DomainObjects;
namespace DVBServices
{
/// <summary>
/// The class that describes an Open TV Title section.
/// </summary>
public class OpenTVTitleSection
{
/// <summary>
/// Get the section number.
/// </summary>
public int SectionNumber { get { return (sectionNumber); } }
/// <summary>
/// Get the section number.
/// </summary>
public int LastSectionNumber { get { return (lastSectionNumber); } }
/// <summary>
/// Get the title header.
/// </summary>
public OpenTVTitleHeader TitleHeader { get { return (titleHeader); } }
private int sectionNumber;
private int lastSectionNumber;
private OpenTVTitleHeader titleHeader;
private int lastIndex = -1;
/// <summary>
/// Initialize a new instance of the OpenTVTitleSection class.
/// </summary>
internal OpenTVTitleSection() { }
/// <summary>
/// Parse the section.
/// </summary>
/// <param name="byteData">The MPEG2 section containing the section.</param>
/// <param name="mpeg2Header">The MPEG2 header that preceedes the section.</param>
/// <param name="pid">The PID containing the section.</param>
/// <param name="tid">The table ID containing the section.</param>
internal void Process(byte[] byteData, Mpeg2ExtendedHeader mpeg2Header, int pid, int tid)
{
lastIndex = mpeg2Header.Index;
sectionNumber = mpeg2Header.SectionNumber;
lastSectionNumber = mpeg2Header.LastSectionNumber;
titleHeader = new OpenTVTitleHeader();
titleHeader.Process(byteData, lastIndex, mpeg2Header, pid, tid);
}
/// <summary>
/// Log the section fields.
/// </summary>
public void LogMessage()
{
if (Logger.ProtocolLogger == null)
return;
titleHeader.LogMessage();
}
/// <summary>
/// Process an MPEG2 section from the Open TV Title table.
/// </summary>
/// <param name="byteData">The MPEG2 section.</param>
/// <param name="pid">The PID containing the section.</param>
/// <param name="table">The table ID containing the section.</param>
/// <returns>An Open TV Title Section instance or null if a section is not created.</returns>
public static OpenTVTitleSection ProcessOpenTVTitleTable(byte[] byteData, int pid, int table)
{
Mpeg2ExtendedHeader mpeg2Header = new Mpeg2ExtendedHeader();
try
{
mpeg2Header.Process(byteData);
if (mpeg2Header.Current)
{
OpenTVTitleSection openTVTitleSection = new OpenTVTitleSection();
openTVTitleSection.Process(byteData, mpeg2Header, pid, table);
openTVTitleSection.LogMessage();
return (openTVTitleSection);
}
else
return (null);
}
catch (ArgumentOutOfRangeException e)
{
Logger.Instance.Write("<e> Error processing Title Section: " + e.Message);
if (DebugEntry.IsDefined(DebugName.TitleSection))
{
Logger.Instance.Write(e.Message);
Logger.Instance.Write(e.StackTrace);
Logger.Instance.Dump("Title Section", byteData, byteData.Length);
}
return (null);
}
}
}
}

View File

@ -138,5 +138,42 @@ namespace DVBServices
temp = "";
return temp;
}
/// <summary>
/// Convert an integer value to a hex string.
/// </summary>
/// <param name="value">The value to be converted.</param>
/// <returns>The converted string.</returns>
public static string ConvertToHex(int value)
{
if (value == 0)
return ("0x00");
uint tempValue = (uint)value;
char[] outputChars = new char[8];
int outputIndex = 7;
for (int index = 3; index > -1; index--)
{
uint hexByte = (tempValue << 24) >> 24;
int hexByteLeft = (int)(hexByte >> 4);
int hexByteRight = (int)(hexByte & 0x0f);
outputChars[outputIndex] = getHex(hexByteRight);
outputChars[outputIndex - 1] = getHex(hexByteLeft);
outputIndex -= 2;
tempValue = tempValue >> 8;
}
string replyString = new string(outputChars).TrimStart(new char[] { '0' });
if (replyString.Length % 2 == 0)
return ("0x" + replyString);
else
return ("0x0" + replyString);
}
}
}

View File

@ -0,0 +1,266 @@
//////////////////////////////////////////////////////////////////////////////////
// //
// Copyright © 2005-2020 nzsjb //
// //
// This Program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2, or (at your option) //
// any later version. //
// //
// This Program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details. //
// //
// You should have received a copy of the GNU General Public License //
// along with GNU Make; see the file COPYING. If not, write to //
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. //
// http://www.gnu.org/copyleft/gpl.html //
// //
//////////////////////////////////////////////////////////////////////////////////
using System;
using System.Collections.ObjectModel;
namespace DomainObjects
{
/// <summary>
/// The class that describes a trace parameter entry.
/// </summary>
public class TraceEntry
{
/// <summary>
/// Get the last error message.
/// </summary>
public static string LastError { get { return (lastError); } }
/// <summary>
/// Get the entry name.
/// </summary>
public TraceName Name { get; private set; }
/// <summary>
/// Get or set the number entry parameter.
/// </summary>
public int NumberParameter
{
get
{
if (!numberParameterSet)
throw (new InvalidOperationException("TraceEntry number parameter not set"));
return (numberParameter);
}
set
{
numberParameter = value;
numberParameterSet = true;
}
}
/// <summary>
/// Get or set the string entry parameter.
/// </summary>
public string StringParameter
{
get
{
if (!stringParameterSet)
throw (new InvalidOperationException("TraceEntry string parameter not set"));
return (stringParameter);
}
set
{
stringParameter = value;
stringParameterSet = true;
}
}
/// <summary>
/// Return true if the entry number parameter has been set; false otherwise.
/// </summary>
public bool NumberParameterSet { get { return (numberParameterSet); } }
/// <summary>
/// Return true if the entry string parameter has been set; false otherwise.
/// </summary>
public bool StringParameterSet { get { return (stringParameterSet); } }
private int numberParameter;
private bool numberParameterSet;
private string stringParameter;
private bool stringParameterSet;
private static string lastError;
private TraceEntry() { }
/// <summary>
/// Initialize a new instance of the TraceEntry class with a name.
/// </summary>
/// <param name="name">The name of the entry.</param>
public TraceEntry(TraceName name)
{
Name = name;
}
/// <summary>
/// Initialize a new entry of the TraceEntry class with a name and number parameter.
/// </summary>
/// <param name="name"></param>
/// <param name="parameter"></param>
public TraceEntry(TraceName name, int parameter) : this(name)
{
NumberParameter = parameter;
}
/// <summary>
/// Initialize a new entry of the TraceEntry class with a name and string parameter.
/// </summary>
/// <param name="name"></param>
/// <param name="parameter"></param>
public TraceEntry(TraceName name, string parameter) : this(name)
{
StringParameter = parameter;
}
/// <summary>
/// Get a string representation of the instance.
/// </summary>
/// <returns>A string representing the instance.</returns>
public override string ToString()
{
if (numberParameterSet)
return (Name.ToString() + "-" + NumberParameter);
else
{
if (stringParameterSet)
return (Name.ToString() + "-" + '"' + StringParameter + '"');
else
return (Name.ToString());
}
}
/// <summary>
/// Copy the instance.
/// </summary>
/// <returns>A new instance of the TraceEntry class with the same values as this instance.</returns>
public TraceEntry Clone()
{
TraceEntry newEntry = new TraceEntry(Name);
if (numberParameterSet)
newEntry.NumberParameter = NumberParameter;
if (stringParameterSet)
newEntry.StringParameter = StringParameter;
return (newEntry);
}
/// <summary>
/// Get an instance of the TraceEntry from a parameter file entry.
/// </summary>
/// <param name="parameter">The parameter file entry.</param>
/// <returns>A new instance of the class.</returns>
public static TraceEntry GetInstance(string parameter)
{
string[] parameterParts = parameter.Split(new char[] { '-' });
if (parameterParts.Length == 2 && string.IsNullOrWhiteSpace(parameterParts[1]))
return(null);
try
{
TraceEntry traceEntry = new TraceEntry((TraceName)Enum.Parse(typeof(TraceName), parameterParts[0].Trim(), true));
if (parameterParts.Length == 2)
{
if (parameterParts[1].Trim()[0] != '"')
{
try
{
traceEntry.NumberParameter = Int32.Parse(parameterParts[1]);
}
catch (FormatException)
{
lastError = "The Trace name '" + parameterParts[0].Trim() + "' has a parameter in the wrong format.";
return (null);
}
catch (OverflowException)
{
lastError = "The Trace name '" + parameterParts[0].Trim() + "' has a parameter out of range.";
return (null);
}
}
else
{
if (parameterParts[1].Trim().Length < 3 || parameterParts[1].Trim()[parameterParts[1].Length - 1] != '"')
return (null);
traceEntry.StringParameter = parameterParts[1].Trim().Substring(1, parameterParts[1].Length - 2);
}
}
return (traceEntry);
}
catch (ArgumentException)
{
lastError = "The Trace ID '" + parameter.Trim() + "' is undefined and will be ignored.";
return (null);
}
}
/// <summary>
/// Check if a trace name is present.
/// </summary>
/// <param name="traceName">The name of the trace entry.</param>
/// <returns>True if the trace name is present; false otherwise.</returns>
public static bool IsDefined(TraceName traceName)
{
return false;
}
/// <summary>
/// Find a trace entry.
/// </summary>
/// <param name="traceName">The name of the trace entry.</param>
/// <returns>The trace entry if it is found; otherwise null</returns>
public static TraceEntry FindEntry(TraceName traceName)
{
return (FindEntry(traceName, false));
}
/// <summary>
/// Find a trace entry.
/// </summary>
/// <param name="traceName">The name of the trace entry.</param>
/// <param name="withParameter">True if a parameter must be present; false otherwise.</param>
/// <returns>The trace entry if it is found; otherwise null</returns>
public static TraceEntry FindEntry(TraceName traceName, bool withParameter)
{
//feyris-tan: We don't use these in skyscraper, so we'll just always return null
return null;
}
/// <summary>
/// Find a trace entry.
/// </summary>
/// <param name="traceEntries">The list of trace entries to search.</param>
/// <param name="identifier">The string representation of the debug entry.</param>
/// <returns>The trace entry if it is found; otherwise null</returns>
public static TraceEntry FindEntry(Collection<TraceEntry> traceEntries, string identifier)
{
if (traceEntries == null)
return (null);
foreach (TraceEntry traceEntry in traceEntries)
{
if (traceEntry.ToString().ToUpperInvariant() == identifier.ToUpperInvariant())
return (traceEntry);
}
return (null);
}
}
}

View File

@ -0,0 +1,68 @@
using skyscraper5.Data.PostgreSql;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal interface IOpenTvDataStorage
{
bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId, int titleDataEventId, DateTime titleDataStartTime);
}
internal class OpenTvDataStorageImpl : IOpenTvDataStorage
{
private IOpenTvDataStorage _storageEngine;
public OpenTvDataStorageImpl(object[] getPluginConnector)
{
object o = getPluginConnector[0];
switch (o)
{
case InMemoryPluginToken t1:
_storageEngine = new OpenTvDataStorageMemory();
break;
case PostgresqlToken t2:
_storageEngine = new OpenTvDataStoragePostgresql(t2);
break;
default:
throw new NotImplementedException(o.GetType().FullName);
}
}
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
int titleDataEventId, DateTime titleDataStartTime)
{
return _storageEngine.TestForTitles(skyscraperContextCurrentNetworkId, skyscraperContextCurrentTransportStreamId, titleDataEventId, titleDataStartTime);
}
}
internal class OpenTvDataStorageMemory : IOpenTvDataStorage
{
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
int titleDataEventId, DateTime titleDataStartTime)
{
throw new NotImplementedException();
}
}
internal class OpenTvDataStoragePostgresql : IOpenTvDataStorage
{
private readonly PostgresqlToken _postgresql;
public OpenTvDataStoragePostgresql(PostgresqlToken postgresql)
{
_postgresql = postgresql;
}
public bool TestForTitles(int skyscraperContextCurrentNetworkId, int skyscraperContextCurrentTransportStreamId,
int titleDataEventId, DateTime titleDataStartTime)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal enum OpenTvExpectedDataType
{
Titles,
Summaries
}
}

View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DVBServices;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal interface OpenTvHandler
{
void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId);
void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection);
void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection);
}
}

View File

@ -0,0 +1,59 @@
using DVBServices;
using skyscraper5.Skyscraper.Scraper;
using skyscraper8.Skyscraper.Plugins;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal class OpenTvScraper : OpenTvHandler
{
private readonly SkyscraperContext _skyscraperContext;
private readonly IOpenTvDataStorage storage;
private static PluginLogger _logger;
public OpenTvScraper(SkyscraperContext skyscraperContext)
{
_skyscraperContext = skyscraperContext;
storage = new OpenTvDataStorageImpl(skyscraperContext.DataStorage.GetPluginConnector());
if (_logger == null)
{
_logger = PluginLogManager.GetLogger(GetType());
}
}
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
{
throw new NotImplementedException();
}
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
{
if (!_skyscraperContext.CurrentNetworkId.HasValue)
return;
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
return;
foreach (OpenTVTitleData titleData in titleSection.TitleHeader.TitleData)
{
if (!storage.TestForTitles(_skyscraperContext.CurrentNetworkId.Value, _skyscraperContext.CurrentTransportStreamId.Value, titleData.EventID, titleData.StartTime))
{
}
}
}
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
{
if (!_skyscraperContext.CurrentNetworkId.HasValue)
return;
if (!_skyscraperContext.CurrentTransportStreamId.HasValue)
return;
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,68 @@
using DVBServices;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
////Disabled due to the Huffmann Table being dynamically determined.
//[SkyscraperPlugin]
internal class OpenTvSummaryContestant : Contestant, OpenTvHandler
{
public OpenTvSummaryContestant(int pid)
: base("OpenTV Summaries", pid)
{
PacketProcessor = new PsiDecoder(pid, new OpenTvSummaryParser(this));
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
OpenTvScraper openTvScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is OpenTvScraper) as OpenTvScraper;
if (openTvScraper == null)
{
openTvScraper = new OpenTvScraper(skyscraperContext);
skyscraperContext.PluginContext.Add(openTvScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new OpenTvSummaryParser(openTvScraper)));
}
public override void Introduce(ProgramContext programContext)
{
}
private byte[] nonTrafficMarkers;
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
{
if (nonTrafficMarkers == null)
nonTrafficMarkers = new byte[byte.MaxValue];
nonTrafficMarkers[sectionTableId]++;
if (nonTrafficMarkers[sectionTableId] == 1)
Score++;
}
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
{
throw new NotImplementedException();
}
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
{
Score++;
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DVBServices;
using skyscraper5.Mpeg2;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal class OpenTvSummaryParser : IPsiProcessor
{
private readonly OpenTvHandler _openTvScraper;
public OpenTvSummaryParser(OpenTvHandler openTvScraper)
{
_openTvScraper = openTvScraper;
}
public void GatherPsi(PsiSection section, int sourcePid)
{
if (section.TableId >= 0xa8 && section.TableId <= 0xab)
{
OpenTVSummarySection summarySection = OpenTVSummarySection.ProcessOpenTVSummaryTable(section.GetData());
if (summarySection != null)
{
_openTvScraper.OnSummaries(sourcePid, section.TableId, summarySection);
}
}
else
{
if (section.TableId >= 0xa0 && section.TableId <= 0xa7)
{
//Titles
return;
}
_openTvScraper.OnNonOpenTvTraffic(sourcePid, OpenTvExpectedDataType.Summaries, section.TableId);
}
}
}
}

View File

@ -0,0 +1,62 @@
using DVBServices;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.StreamAutodetection;
using skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
//Disabled due to the Huffmann Table being dynamically determined.
//[SkyscraperPlugin]
internal class OpenTvTitleContestant : Contestant, OpenTvHandler
{
public OpenTvTitleContestant(int pid)
: base("OpenTV Titles", pid)
{
PacketProcessor = new PsiDecoder(pid, new OpenTvTitleParser(this));
}
public override void Dispose()
{
}
public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext)
{
OpenTvScraper openTvScraper = skyscraperContext.PluginContext.FirstOrDefault(x => x is OpenTvScraper) as OpenTvScraper;
if (openTvScraper == null)
{
openTvScraper = new OpenTvScraper(skyscraperContext);
skyscraperContext.PluginContext.Add(openTvScraper);
}
skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new OpenTvTitleParser(openTvScraper)));
}
public override void Introduce(ProgramContext programContext)
{
}
public void OnNonOpenTvTraffic(int sourcePid, OpenTvExpectedDataType titles, int sectionTableId)
{
throw new NotImplementedException();
}
public void OnTitles(int sourcePid, int sectionTableId, OpenTVTitleSection titleSection)
{
Score++;
}
public void OnSummaries(int sourcePid, int sectionTableId, OpenTVSummarySection summarySection)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DVBServices;
using skyscraper5.Mpeg2;
namespace skyscraper8.EPGCollectorPort.SkyscraperSide.OpenTV
{
internal class OpenTvTitleParser : IPsiProcessor
{
private readonly OpenTvHandler _handler;
public OpenTvTitleParser(OpenTvHandler handler)
{
_handler = handler;
}
public void GatherPsi(PsiSection section, int sourcePid)
{
if (section.TableId >= 0xa0 && section.TableId <= 0xa7)
{
OpenTVTitleSection titleSection = OpenTVTitleSection.ProcessOpenTVTitleTable(section.GetData(),sourcePid,section.TableId);
if (titleSection != null)
{
_handler.OnTitles(sourcePid, section.TableId, titleSection);
}
}
else
{
if (section.TableId >= 0xa8 && section.TableId <= 0xab)
{
//Summaries.
return;
}
_handler.OnNonOpenTvTraffic(sourcePid,OpenTvExpectedDataType.Titles, section.TableId);
}
}
}
}

View File

@ -40,6 +40,7 @@ namespace skyscraper5
private static void IntegrationTest()
{
}
static void Main(string[] args)

View File

@ -2,7 +2,7 @@
"profiles": {
"skyscraper8": {
"commandName": "Project",
"commandLineArgs": "cscan-live tcp://tetsuro:6969",
"commandLineArgs": "file-live \"C:\\Temp\\sky-uk-000000.ts\"",
"remoteDebugEnabled": false
},
"Container (Dockerfile)": {

View File

@ -633,12 +633,7 @@ namespace skyscraper5.Skyscraper.Scraper
interactionChannelDecoder.Handler = this;
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, interactionChannelDecoder));
break;
case StreamType.OpenTvPrivate:
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new OpenTvPrivate());
break;
case StreamType.BSkyBPrivate:
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new BSkyBPrivate());
break;
case StreamType.Id3:
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(new Id3PesProcessor(this)));
break;
@ -934,18 +929,6 @@ namespace skyscraper5.Skyscraper.Scraper
}
}
if (stream.PrivateDataSpecifier == 0x00000002)
{
if (stream.UnknownUserDefines != null)
{
UserDefinedDescriptor userDefinedDescriptor = stream.UnknownUserDefines.Find(x => x.DescriptorTag == 0xb0);
if (userDefinedDescriptor != null)
{
//BSkyB EPG Related descriptor
return StreamType.BSkyBPrivate;
}
}
}
if (stream.MetadataApplicationFormat == 0xffff && stream.MetadataApplicationFormatIdentifier == 0x49443320 && stream.MetadataFormat == 0xff && stream.MetadataFormatIdentifier == 0x49443320)
{